我有一个包含3个字段的表格截图:
CREATE TABLE `screenshot` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`UserID` int(11) NOT NULL,
`DateTaken` date NOT NULL,
PRIMARY KEY (`ID`),
KEY `DateTaken` (`DateTaken`),
KEY `UserID` (`UserID`) USING BTREE,
CONSTRAINT `userID_foreign_key` FOREIGN KEY (`UserID`) REFERENCES `users` (`UserID`)
) ENGINE=InnoDB AUTO_INCREMENT=22514871 DEFAULT CHARSET=latin1
和
SELECT @@innodb_buffer_pool_size
结果:16777216
查询:
SELECT COUNT(ID) total
FROM screenshot WHERE DateTaken BETWEEN '2000-05-01' AND '2000-06-10'
结果:2828844
解释输出:
ID|select_type| table |type |possible_keys| key |key_len| rows |Extra
1 | SIMPLE |screenshot|range| DateTaken |DateTaken| 3 |5730138|Using where; Using index
这是我的问题: 我已将索引添加到DateTaken列,但扫描行(Explain输出)大于结果。它看起来像是一个完整的扫描表。查询的查询运行时间为15秒。如何提高上述查询的速度?
答案 0 :(得分:1)
没有问题。你的指数没问题。解释......
5730138
中的EXPLAIN
是估算值。它可以大于或小于实际值,有时是大量的。不要被它打扰。
在该日期范围内有2.8M的屏幕截图,对吗?好吧,扫描索引可能需要15秒来计算那么多行。
如果您想进一步分析,请提供:
RAM大小
innodb_buffer_pool_size
SHOW CREATE TABLE screenshot;
(这将显示引擎)
桌子有多大(GB)
你有什么类型的磁盘(旋转与SSD)
有了这些,我们可以进一步讨论缓存,I / O和引擎的影响。它可能有助于解释" 15秒"与" 20"。
(并且,是的,请使用COUNT(*)
,而不是COUNT(x)
,除非您需要测试x
是否为NULL。)
如果你使用InnoDB,那么INDEX(DateTaken, id)
与INDEX(DateTaken)
相同,所以我建议你急于接受这个答案。
缓冲池
innodb_buffer_pool_size
应设置为大约70%的RAM。你拥有的是如此之小(旧的16M默认值),即使建议的索引也不适合缓存。因此,查询将始终击中磁盘,至少在某些时候。增加缓冲池应该可以显着提高速度,可能低至2秒。
答案 1 :(得分:0)
尝试运行此查询:
SELECT COUNT(*) as total
FROM screenshot
WHERE DateTaken BETWEEN '2000-05-01' AND '2000-06-10';
ID
中对SELECT
的引用可能会影响索引的使用。
答案 2 :(得分:0)
您可以尝试添加复合索引
create index test on screenshot (DateTaken, id)