MySQL查询速度慢(索引列上的DISTINCT WHERE)

时间:2015-05-22 21:18:24

标签: mysql performance

规格:

  • MySQL版本:5.6.19(Ubuntu)
  • 还尝试了MariaDB,并遇到了同样的问题

表:

CREATE TABLE `x` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `a` INT(10) UNSIGNED NOT NULL,
    `time` DECIMAL(16,6) NOT NULL,

    PRIMARY KEY (`id`),
    INDEX `a` (`a`),
    INDEX `time` (`time`),
    INDEX `time_a` (`time`, `a`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=298846
;

查询:

SELECT COUNT(DISTINCT `a`) c
FROM `x`
WHERE `time` >= (UNIX_TIMESTAMP()- (60 * 24));

如果在给定范围内有很多行time,则此查询非常缓慢。另请注意,虽然可能存在大量匹配行(数千或数万或更多),但DISTINCT a的数量总是相当小(几百)。

在以下情况下,查询很快(基本上是即时的),无论表的大小如何:

  1. 在给定范围内或
  2. 时,只有少数行time
  3. 没有WHERE部分(由于a上的索引)
  4. 这让我觉得在计算时它无论如何都无法使用a上的索引,即使EXPLAIN提到了possibly_keys中的所有三个索引。

    即使出现以下情况,问题仍然存在:

    • time的类型为BIGINTDATETIME(对查询进行了相应的更改)
    • ENGINE=MyISAM

    有什么建议吗?

4 个答案:

答案 0 :(得分:1)

SELECT COUNT(DISTINCT `a`)
    FROM `x`;

将跳过INDEX(a)。请参阅EXPLAIN FORMAT=JSON SELECT ...并查找"using_index_for_group_by": true。当只有少量不同的a值时,这会非常快。

我怀疑使用WHERE子句会说"using_index_for_group_by": "scanning",这意味着效率较低。我怀疑实施者做的是单键案例,而不是多键案例。

这是整个表的定义吗?我看到AUTO_INCREMENT没有任何索引。怎么了?关于与本讨论相关的MyISAM和InnoDB之间的唯一区别是PRIMARY KEY的处理。

time的数据类型可能不重要。

如果我对您的"任何建议不满意?"问题,请重新提问。

答案 1 :(得分:0)

尝试使用索引提示强制查询使用您希望它使用的索引。

SELECT COUNT(DISTINCT `a`) c FROM `x` FORCE INDEX (the_index_you_want_to_use) WHERE `time` >= (UNIX_TIMESTAMP()- (60 * 24));

答案 2 :(得分:0)

最好不要在where where子句中进行任何计算。

var unixtime = UNIX_TIMESTAMP()- (60 * 24)

SELECT COUNT(DISTINCT `a`) c
FROM `x` FORCE INDEX (the_index_you_want_to_use) 
WHERE `time` >= unixtime

答案 3 :(得分:0)

如果我不得不猜测,问题就是类型。 UNIX_TIMESTAMP()返回无符号整数。您的time变量为decimal。这些不是相同的东西。而且,类型不匹配会使优化器混淆。

听起来表格很大,所以更改类型是不可行的(但是,如果你可以通过选择具有正确类型的新表格的数据,你可能想要测试它。)

以下内容可能有所帮助:

WHERE `time` >= cast(UNIX_TIMESTAMP() - (60 * 24) as unsigned);

您还可以声明一个本地无符号变量,并在变量中存储“常量”,以查看是否能解决性能问题。

最后,如果未使用time, a上的索引,请尝试查询的此变体:

SELECT COUNT(*) as c
FROM (SELECT DISTINCT a
      FROM `x` 
      WHERE `time` >= CAST(unixtime - 24 * 60 as unsigned)
     ) ax

我已经看到这种重组可以提高其他数据库的性能,但不是在MySQL上。