1

哪个选择语句更好?

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;
4

3 回答 3

3

它们产生非常相似的执行计划(在我的测试表上,它们很小;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的这篇优秀文章中对这些技术进行了更多比较。


作为参考,这是我创建aTablebTable(因为您没有提供定义)和测试您的查询的方式:

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 秒)
于 2012-10-24T14:50:20.587 回答
1

我认为第二个转换为相关的子查询语义,因此与第一个相比成本很高。最好的办法是只加入这两个表,如下所示:

SELECT 
    a.* 
FROM 
    aTable a
    JOIN bTable b
    ON aTable.aField = bTable.xField
WHERE 
    b.xField > 5

这将使您避免 IN 子句中出现大量结果,如果是第一次查询,这会使查询执行速度变慢,并且有时会导致溢出错误(SQL Server 曾经在 IN 中有 32767 个值的限制)子句,之后它会抛出此溢出错误)。

于 2012-10-24T13:36:47.750 回答
0

Alot 取决于表的索引以及是否在连接条件中使用索引列。这些的组合将在某种程度上决定 SQL 引擎如何“决定”在内部构造查询,并最终影响查询性能。在 MySQL 上不太确定,但 SQL Server 肯定会允许创建一个执行计划,这将显示潜在的瓶颈。

于 2012-10-24T13:47:35.670 回答