我在一张桌子上做一个简单的选择。
CREATE TABLE `book` (
`Book_Id` int(10) NOT NULL AUTO_INCREMENT,
`Book_Name` varchar(100) COLLATE utf8_turkish_ci DEFAULT NULL ,
`Book_Active` bit(1) NOT NULL DEFAULT b'1' ,
`Author_Id` int(11) NOT NULL,
PRIMARY KEY (`Book_Id`),
KEY `FK_Author` (`Author_Id`),
CONSTRAINT `FK_Author` FOREIGN KEY (`Author_Id`) REFERENCES `author` (`Author_Id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=5947698 DEFAULT CHARSET=utf8 COLLATE=utf8_turkish_ci ROW_FORMAT=COMPACT
表格:预订
列:
Book_Id(INTEGER 10)| Book_Name(VARCHAR 100)| Author_Id(INTEGER 10)| Book_Active(布尔)
我有三列索引:Book_Id(PRIMARY键),Author_Id(FK),Book_Active。
第一次查询:
SELECT * FROM book WHERE Author_Id = 1 AND Book_Active = 1
EXPLAIN :
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE book ref FK_Author,index_Book_Active FK_Author 4 const 4488510 Using where
第二个查询:
SELECT b.* FROM book b
WHERE Book_Active=1
AND Book_Id IN (SELECT Book_Id FROM book WHERE Author_Id=1)
EXPLAIN :
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY book ref index_Book_Active index_Book_Active 1 const 9369399 Using where
2 DEPENDENT SUBQUERY book unique_subquery PRIMARY,FK_Author PRIMARY 4 func 1 Using where
数据统计数据如下:
16.8 million books
10.5 million Book_Active=true
6.3 million Book_Active = false
而Author_Id=1
2.4 million Book_Active=false
5000 Book_Active=true
第一个查询需要 6.7 秒。第二个查询需要 0.0002 秒
造成这种巨大差异的原因是什么?使用嵌套的选择查询是正确的吗?
编辑:添加“sql explain”
答案 0 :(得分:2)
在第一种情况下:MySQL使用FK_Author
索引(这给了我们~4.5M行),然后它必须匹配Book_Active = 1
条件的每一行 - 这里不能使用索引。
第二种情况:InnoDB隐式adds每个索引的主键。因此,当MySQL执行此部分时:SELECT book.* FROM book WHERE Book_Active=1
它从索引中获得Book_Id
。然后,对于子查询,它必须与Book_Id
匹配Author_Id
; Author_Id
是常量,是索引的前缀;隐式包含的主键可以与来自Book_Active
索引的隐式主键进行匹配。在您的情况下,交叉两个索引比使用索引检索4.5M行并按顺序扫描它们更快。