【问题标题】:simple mysql query working slower than nested Select简单的 mysql 查询工作比嵌套 Select 慢
【发布时间】:2026-02-02 12:30:02
【问题描述】:

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

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 (整数 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解释”

【问题讨论】:

  • 在两个查询之前添加 EXPLAIN 并发布输出。
  • 如果你改变这两个查询的执行顺序,你会得到不同的结果,原因是缓存内存的使用。
  • @SashiKant 我强烈反对。我尝试了很多次,并且以任何顺序进行。时间永远不会改变
  • 你有多少不同的作者?

标签: mysql indexing nested


【解决方案1】:

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

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

【讨论】:

  • 为什么第一种情况不能使用book_Active索引?
  • (Book_Active, Author_Id)上添加索引
  • @ypercube 它会表现得更好还是应该像示例一样将我的查询变成嵌套查询?
  • 哪个例子?我的意思是添加索引,然后尝试第一个版本。
  • 对不起,我没有及时看到您的评论,但我添加了您建议的索引,并且正如预期的那样,它就像一个魅力,平均大约 0.0001 秒。这么直白的忠告,但有时缺乏经验真的是一片遮天蔽日的大云。你介意回答这个问题,解释为什么我的索引没有帮助而你的索引有帮助吗?这样我就可以选择它作为正确答案?