下面的查询需要很长时间才能执行大约2分钟请帮助我如何提高此查询的性能。
所以我们的要求是在2到3秒内得到结果。
查询也在使用索引。
但它正在进行更多的扫描。
查询:
select max(`log_date`)
from `top_competitor_summary_entity`
where
own_domain_id = 4
and keyword_top1_count > 0
and (grouptag_id = 0 OR grouptag_id is null);
扩展计划:
+----+-------------+-------------------------------+------+--------------------------------------+------------------------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------------------------+------+--------------------------------------+------------------------+---------+-------+---------+-------------+
| 1 | SIMPLE | top_competitor_summary_entity | ref | own_domain_id,own_domain_id_log_date | own_domain_id_log_date | 4 | const | 2100128 | Using where |
+----+-------------+-------------------------------+------+--------------------------------------+------------------------+---------+-------+---------+-------------+
1 row in set (0.66 sec)
表格结构:
mysql> show create table top_competitor_summary_entity\G
*************************** 1. row ***************************
Table: top_competitor_summary_entity
Create Table: CREATE TABLE `top_competitor_summary_entity` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`domain` varchar(255) NOT NULL COMMENT 'competitor domain name',
`own_domain_id` int(11) NOT NULL,
`keyword_top10_count` int(11) DEFAULT NULL,
`keyword_top3_count` int(11) DEFAULT NULL,
`keyword_top1_count` int(11) DEFAULT NULL,
`keyword_top10_search_volume` bigint(20) DEFAULT NULL,
`keyword_top3_search_volume` bigint(20) DEFAULT NULL,
`keyword_top1_search_volume` bigint(20) DEFAULT NULL,
`url_top10_count` int(11) DEFAULT NULL
COMMENT 'how many competitor url in Top 10',
`log_date` date DEFAULT NULL,
`grouptag_id` int(11) DEFAULT '0',
`keyword_top10_count_bing` int(11) DEFAULT '0',
`keyword_top10_count_yahoo` int(11) DEFAULT '0',
`keyword_top3_count_bing` int(11) DEFAULT '0',
`keyword_top3_count_yahoo` int(11) DEFAULT '0',
`keyword_top1_count_bing` int(11) DEFAULT '0',
`keyword_top1_count_yahoo` int(11) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `own_domain_id` (`own_domain_id`),
KEY `domain_own_domain_id_log_date` (`domain`,`own_domain_id`,`log_date`),
KEY `own_domain_id_log_date` (`own_domain_id`,`log_date`)
) ENGINE=InnoDB AUTO_INCREMENT=680592051 DEFAULT CHARSET=utf8
1 row in set (0.09 sec)
最佳答案
查询本身非常简单,我认为您不可能对它做任何修改以使其更快。不过,我想知道使用“IsNull(grouptag_id,0)=0”是否会有任何不同。我很怀疑,但看看能不能刮掉什么可能会很有趣。
我认为真正的问题是,可能有很多记录拥有自己的域id值4,而where子句中没有其他字段的索引。您可以为它们创建单独的索引,并且/或者如果您想创建一个专门为此查询定制的索引,那么就创建一个索引,该索引对所有引用的4个字段都进行键控。
其他一些观察:
如果有可能更改代码以处理空值(可能只将它们视为0),那么可以去掉大多数这些字段中的默认值,改为空值。如果没有多少字段的值实际为0,那么这就没有多大用处,但是如果将许多字段设置为0,那么这将导致表占用磁盘空间更少,从而减少扫描表的时间。
您还可以水平或垂直地对表进行分区。
横向:你可以把所有的前1个字段放在前1个表中,所有的前3个字段放在前3个表中,等等。或者,你可以把所有的yahoo放在一个表中,把所有的bing放在另一个表中;或者,你可以把所有的计数字段放在一个表中,把所有的搜索字段放在另一个表中。如果你发现自己通常一次只需要一组字段,那么这将减少搜索时间,但是如果你最终在大多数查询中获取所有字段,那么这当然没有什么帮助。
垂直:这个可能比它的价值要多得多,但是您可以将表中的记录拆分到多个表上,并将它们放在多个硬盘上,同时异步查询它们。我一直在想,谷歌是否会按照这些思路做些什么。
我还注意到您使用了一个bigint作为id,它是8字节,而不是一个只有4字节的int。如果你认为在某个时候你将实际处理数十亿条记录,那么bigint显然是一个可行的方法,但是如果你不这样做,你可以将你的数据库缩小大约100兆字节,这也会使你的搜索稍微快一些。如果有必要的话,没有理由现在不能把它设为int,以后再改为bigint。