我使用的是 MySQL 5.6,我的存储引擎是 InnoDB。
我有一个包含 100 万行的表,其中包含以下列:
- ID(主键)
- 名字
- 姓氏
- foreign_key_id(外键,非空)
- foreign_key_id2(另一个外键,默认为NULL)
行在下面分隔:
- 25% foreign_key_id 值为 1 且 foreign_key_id2 NULL
- 25% foreign_key_id 值为 1 且 foreign_key_id2 NOT NULL
- 25% foreign_key_id 值为 2 且 foreign_key_id2 NULL
- 25% foreign_key_id 值为 2 且 foreign_key_id2 NOT NULL
具有以下指标:
- 在 foreign_key_id 上索引 foreign_key_idx
- 索引 foreign_key_2_idx 和 foreign_key_id2
- (foreign_key_idx, foreign_key_2_idx) 上的复合索引 foreign_key_comp_idx
我执行以下查询:
Query 1 - without indexes:
SELECT *
FROM table tbl
IGNORE INDEX(foreign_key_idx, foreign_key_2_idx, foreign_key_comp_idx)
WHERE tbl.foreign_key_id = 1 AND tbl.foreign_key_id2 IS NOT NULL
Query 2 - with indexes (no composite index):
SELECT *
FROM table tbl
IGNORE INDEX(foreign_key_comp_idx)
WHERE tbl.foreign_key_id = 1 AND tbl.foreign_key_id2 IS NOT NULL
Query 3 - with composite index (no other indexes):
SELECT *
FROM table tbl
IGNORE INDEX(foreign_key_idx, foreign_key_2_idx)
WHERE tbl.foreign_key_id = 1 AND tbl.foreign_key_id2 IS NOT NULL
结果:
Query 1 (no indexes) performs a full table scan and uses 1 million records with a total duration of 0.37 seconds.
Query 2 (indexes, no composite index) performs a non-unique key lookup on foreign_key_idx index and uses 500K records with a total duration of 0.6 seconds.
Query 3 (composite index only) performs an index range scan on composite index and uses 480K records with a total duration of 0.13 seconds.
我真正不明白的是:为什么query 2(有索引)总是比query 1(没有索引)执行得慢?我真的真的卡住了,需要一些帮助......
我已经用不同数量的行测试了上面的查询,例如 1k、10k、20k、50k、100k、200k、250k、500k、1M 等,始终具有相同的比率 (25%),结果是相同(查询 2 总是执行缓慢)
提前致谢,非常感谢任何类型的输入!
编辑(2016 年 5 月 2 日)
显示创建表命令:
CREATE TABLE `table` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`FirstName` varchar(255) NOT NULL,
`LastName` varchar(255) NOT NULL,
`foreign_key_id` int(11) NOT NULL,
`foreign_key_id2` int(11) DEFAULT NULL,
PRIMARY KEY (`ID`),
KEY `foreign_key_idx` (`foreign_key_id`),
KEY `foreign_key_2_idx` (`foreign_key_id2`),
KEY `foreign_key_comp_idx ` (`foreign_key_id`,`foreign_key_id2`),
CONSTRAINT `foreign_key_idx` FOREIGN KEY (`foreign_key_id`) REFERENCES `table2` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `foreign_key_2_idx` FOREIGN KEY (`foreign_key_id2`) REFERENCES `table3` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
) ENGINE=InnoDB AUTO_INCREMENT=1515998 DEFAULT CHARSET=latin1
不确定是否重要,但表 2 有 20 条记录,表 3 也有 100 万条。
最佳答案
让我吃惊的是查询 3 比查询 1 更快 :-)
您需要表中 25% 的记录。因此,简单地按顺序阅读表格应该是最快的方法。 (至少这是我会做的,也是大多数 DBMS 在那种情况下所做的。)
使用复合索引就可以了,因为知道选择哪些记录就足够了。但是,遍历一棵树只得到所有记录中的 25%,必须一条一条访问,这似乎是一项艰巨的任务。如前所述,令人惊讶的是,它比全表扫描运行得更快。也许物理记录恰好是按需要排序的,所以你不必从一个部分到另一个部分来回移动,这是从索引中获取时通常会发生的情况。 (解释:假设您在磁盘上的表部分 A 的索引中找到匹配的记录引用,下一个匹配恰好在扇区 B,第三个再次在扇区 A,......这可能需要很长时间。如果你是然而,幸运的是,您首先在一个扇区中找到所有记录,然后在另一个扇区中找到。通过全表扫描,您可以逐个读取扇区,而不必从一个扇区切换到另一个扇区并返回。因此,全表扫描可以保证相当快,而通过索引访问可能快也可能慢。)
现在查询2:索引只指向可能匹配的记录(表中50%的记录,其中只有一半是匹配的)。这意味着您必须按照描述遍历树,只是为了仍然读取表的一半记录。这工作量太大了。
关于mysql - 有索引的查询比没有索引慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36970194/