哪个选择语句更好?
SELECT *
FROM aTable
WHERE aField in (
SELECT xField
FROM bTable
WHERE yField > 5
);
或者
SELECT *
FROM aTable
WHERE (
SELECT yField
FROM bTable
WHERE aTable.aField = bTable.xField
) > 5;
哪个选择语句更好?
SELECT *
FROM aTable
WHERE aField in (
SELECT xField
FROM bTable
WHERE yField > 5
);
或者
SELECT *
FROM aTable
WHERE (
SELECT yField
FROM bTable
WHERE aTable.aField = bTable.xField
) > 5;
它们产生非常相似的执行计划(在我的测试表上,它们很小;YMMV,总是分析真实数据),您可能需要考虑第三种选择:
首先:
EXPLAIN SELECT * FROM aTable WHERE aField in (SELECT xField FROM bTable WHERE yField > 5);
+----+--------+--------+--------+------ ---------+---------------+---------+------+------+ -------------+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+--------+--------+--------+------ ---------+---------------+---------+------+------+ -------------+ | 1 | 初级 | 表 | 全部 | 空 | 空 | 空 | 空 | 4 | 使用位置 | | 2 | 依赖子查询 | 表 | 范围 | bTable_y 字段 | bTable_y 字段 | 5 | 空 | 2 | 使用位置 | +----+--------+--------+--------+------ ---------+---------------+---------+------+------+ -------------+
第二:
EXPLAIN SELECT * FROM aTable WHERE (SELECT yField FROM bTable WHERE aTable.aField = bTable.xField) > 5;
+----+--------+--------+------+-------- --------+------+---------+------+------+---------- ---+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+--------+--------+------+-------- --------+------+---------+------+------+---------- ---+ | 1 | 初级 | 表 | 全部 | 空 | 空 | 空 | 空 | 4 | 使用位置 | | 2 | 依赖子查询 | 表 | 全部 | 空 | 空 | 空 | 空 | 4 | 使用位置 | +----+--------+--------+------+-------- --------+------+---------+------+------+---------- ---+
两者都导致依赖子查询;在我的示例表中,第一个获得了索引的好处(我假设bTable.yField
是索引),而第二个没有。
您可以避免依赖子查询并使用以下方式获得更好的预先过滤JOIN
:
第三种选择:
EXPLAIN SELECT * FROM aTable INNER JOIN bTable On aTable.aField = bTable.xField WHERE bTable.yField > 5;
+----+-------------+--------+--------+------------- --+----------------+----------+------+------+----- -------------------------------------+ | 编号 | 选择类型 | 表| 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 额外 | +----+-------------+--------+--------+------------- --+----------------+----------+------+------+----- -------------------------------------+ | 1 | 简单 | 表 | 范围 | bTable_y 字段 | bTable_y 字段 | 5 | 空 | 2 | 使用位置 | | 1 | 简单 | 表 | 全部 | 空 | 空 | 空 | 空 | 4 | 使用哪里;使用连接缓冲区 | +----+-------------+--------+--------+------------- --+----------------+----------+------+------+----- -------------------------------------+
但是,您确实必须再次使用您的模式和您的代表性真实数据进行概要分析,因为优化器可能会做出不同的决定。
在quassnoi的这篇优秀文章中对这些技术进行了更多比较。
作为参考,这是我创建aTable
和bTable
(因为您没有提供定义)和测试您的查询的方式:
mysql> 创建表 aTable (aField INT, aMore VARCHAR(200)); 查询正常,0 行受影响(0.01 秒) mysql> 创建表 bTable (xField INT, yField INT); 查询正常,0 行受影响(0.02 秒) mysql> INSERT INTO aTable (aField, aMore) VALUES (1, '一'), (2, '二'), (3, '三'), (4, '四'); 查询正常,4 行受影响(0.00 秒) 记录:4 重复:0 警告:0 mysql> INSERT INTO bTable (xField, yField) 值 (1, 10), (2, 2), (3, 20), (4, 4); 查询正常,4 行受影响(0.02 秒) 记录:4 重复:0 警告:0 mysql> 创建索引 bTable_yField ON bTable(yField); 查询正常,0 行受影响(0.05 秒) 记录:0 重复:0 警告:0 mysql> SELECT * FROM aTable WHERE aField in (SELECT xField FROM bTable WHERE yField > 5); +--------+--------+ | 场 | a更多 | +--------+--------+ | 1 | 一 | | 3 | 三 | +--------+--------+ 2 行(0.00 秒) mysql> SELECT * FROM aTable WHERE (SELECT yField FROM bTable WHERE aTable.aField = bTable.xField) > 5; +--------+--------+ | 场 | a更多 | +--------+--------+ | 1 | 一 | | 3 | 三 | +--------+--------+ 2 行(0.00 秒)
我认为第二个转换为相关的子查询语义,因此与第一个相比成本很高。最好的办法是只加入这两个表,如下所示:
SELECT
a.*
FROM
aTable a
JOIN bTable b
ON aTable.aField = bTable.xField
WHERE
b.xField > 5
这将使您避免 IN 子句中出现大量结果,如果是第一次查询,这会使查询执行速度变慢,并且有时会导致溢出错误(SQL Server 曾经在 IN 中有 32767 个值的限制)子句,之后它会抛出此溢出错误)。
Alot 取决于表的索引以及是否在连接条件中使用索引列。这些的组合将在某种程度上决定 SQL 引擎如何“决定”在内部构造查询,并最终影响查询性能。在 MySQL 上不太确定,但 SQL Server 肯定会允许创建一个执行计划,这将显示潜在的瓶颈。