1
  1. 下面的查询需要很长时间才能执行大约 2 分钟,请帮助我如何提高此查询的性能。
  2. 所以我们的要求是在 2 到 3 秒内得到结果。
  3. 查询也使用索引。
  4. 但它正在执行更多扫描。

询问:

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)
4

2 回答 2

2

As Brandon Moore said

The query itself is so simple that I don't think there's anything you could possibly do to it to make it faster by modifying it.

Still you can try this and check if it make a bit difference

select `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)
Order by log_date
LIMIT 0,1;
于 2012-12-27T11:12:39.417 回答
1

查询本身非常简单,我认为您无法通过修改它来使其更快。我仍然很好奇使用“IsNull(grouptag_id, 0) = 0”是否会产生任何影响。我对此表示怀疑,但看看它是否能刮掉任何东西可能会很有趣。

我认为真正的问题是可能有大量的 own_domain_id 值为 4 的记录,而 where 子句中的其他字段没有索引。您可以为它们创建单独的索引和/或如果您想创建一个专门为此查询量身定制的索引,然后创建一个在所有 4 个引用字段上的键。

其他一些观察:

如果有可能更改您的代码以处理空值(也许只是将它们视为 0),那么您可以摆脱您在大多数这些字段中放置的默认值并将它们设为空值。如果实际上没有多少字段的值为 0,那么这不会做太多,但是如果很多字段设置为 0,那么这将导致表占用更少的磁盘空间,这将转化为更少的时间来扫描桌子。

您还可以水平或垂直分区表。

横向:您可以将所有 top1 字段放入 top1 表中,将所有 top3 字段放入 top3 表中,等等。或者,您可以将所有 yahoo 放在一个表中,而将所有 bing 放在另一个表中;或者可能是一个表中的所有计数字段和另一个表中的所有搜索字段。如果您发现自己通常一次只需要一组字段,那么这将减少搜索时间,但如果您通常最终在大多数查询中获取所有字段,那么它当然不会有什么帮助。

Vertically:这可能比它的价值多得多,但是您可以将表中的记录拆分到多个表中,然后将它们放在多个硬盘上并同时异步查询它们。我一直想知道谷歌是否会按照这些思路做一些事情。

我还注意到您为您的 id 使用了一个 bigint,它是 8 个字节,而不是一个只有 4 个字节的 int。如果您认为您实际上会在某个时候处理数十亿条记录,那么 bigint 显然是要走的路,但否则您可以将您的数据库缩小大约 100 兆字节,这也会使您的搜索速度稍微快一些。并且没有理由现在不能将其设为 int 并在必要时将其更改回 bigint。

于 2012-12-27T11:06:24.483 回答