我有一个(大)表,我使用 WHERE
中的 3 个字段进行查询。其中一个字段有一个索引(日期),我正在寻找过去 3 个月内的点击次数。虽然它永远不会是一个快速查询,但我至少希望使用该日期的索引。
这是我的查询:
SELECT id
FROM statsTable
WHERE 1
AND ip = 'ipgoeshere'
AND anotherstring = 'Quite a long string goes here, something like this or even longer'
AND `date` > DATE_ADD( NOW( ) , INTERVAL -3 MONTH )
解释一下:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE statsTable ALL date NULL NULL NULL 4833721 Using where; Using filesort
这是一个完整的表扫描,行数是关闭的,因为我猜是 INNODB 行计数,但这就是全部。 这大约需要 30 秒。
如果我像这样强制索引,我会得到预期的结果:
SELECT id
FROM statsTable FORCE INDEX (date)
WHERE 1
AND ip = 'ipgoeshere'
AND anotherstring = 'Quite a long string goes here, something like this or even longer'
AND `date` > DATE_ADD( NOW( ) , INTERVAL -3 MONTH )
再次解释一下:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE statsTable range date date 8 NULL 1120172 Using where
现在我们“仅”有 100 万个结果,但完成速度“非常快”(例如,3 秒而不是 30 秒)。
表格:
CREATE TABLE IF NOT EXISTS `statsTable` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`date` datetime NOT NULL,
`ip` varchar(15) NOT NULL,
`anotherstring` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `date` (`date`)
) ENGINE=InnoDB;
奇怪的是:我也有这个表在另一个数据库上运行(在不同的服务器上运行),并且索引正在该实例中使用。我看不出这里可能有什么问题。是否有我错过的设置?或者可能是其他一些细微的差别?除了差异之外,我不明白为什么上面的查询不使用该 key 。
我已经运行了OPTIMIZE TABLE
,并且正如@DhruvPathak建议的ANALYZE TABLE
,但解释仍然保持不变。我还根据 friend 的建议尝试了 ALTER TABLE 来重建索引。运气不好。
最佳答案
未使用索引,因为执行计划程序决定最好完全扫描表而不是使用索引。当索引对于查询来说选择性不够时,就会发生这种情况。
如果范围检查中的日期超过整个表的 10-20%,则规划器会决定扫描(顺序)整个表比使用索引并检索属于该范围的行更快(此检索不会按顺序进行,因为行将分散在整个表中)。
这就是为什么您会在不同的数据集上看到不同的行为。
为了让您的查询发挥最佳效果,您可以在以下位置创建索引:
(ip, yourDateField)
或
(anotherstring, yourDateField)
或
(ip, anotherstring, yourDateField)
我认为第一个选项的选择性就足够了。无需在索引中添加长 VARCHAR(255)
字段。或者,使用似乎适合您的情况的 FORCE INDEX
。
关于mysql - 在可以而且应该使用的地方没有使用索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7266876/