3

我正在从单个表中进行简单的选择。

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) | 书名 (VARCHAR 100) | Author_Id (整数 10) | Book_Active (布尔值)

我在三列上有索引: Book_Id (PRIMARY key) , 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解释”

4

1 回答 1

2

在第一种情况下:MySQL 使用FK_Author索引(这给了我们大约 450 万行),然后它必须根据Book_Active = 1条件匹配每一行——索引不能在这里使用。

第二种情况:InnoDB 为每个索引隐式添加主键。因此,当 MySQL 执行这部分时:SELECT book.* FROM book WHERE Book_Active=1它已经Book_Id从索引。Book_Id然后对于子查询,它必须匹配Author_Id; Author_Id是一个常数,是索引的前缀;隐式包含的主键可以与Book_Active索引中的隐式主键匹配。在您的情况下,相交两个索引比使用索引检索 4.5M 行并按顺序扫描它们要快。

于 2013-01-11T11:01:49.970 回答