mysql - 更快地执行 'WHERE IN (SELECT)' 或 'WHERE x = (SELECT)'

标签 mysql

哪种选择语句更好?

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);
+----+--------------------+--------+-------+---------------+---------------+---------+------+------+-------------+
| id | select_type        | table  | type  | possible_keys | key           | key_len | ref  | rows | Extra       |
+----+--------------------+--------+-------+---------------+---------------+---------+------+------+-------------+
|  1 | PRIMARY            | aTable | ALL   | NULL          | NULL          | NULL    | NULL |    4 | Using where |
|  2 | DEPENDENT SUBQUERY | bTable | range | bTable_yField | bTable_yField | 5       | NULL |    2 | Using where |
+----+--------------------+--------+-------+---------------+---------------+---------+------+------+-------------+

The second:

EXPLAIN SELECT * FROM aTable WHERE (SELECT yField FROM bTable WHERE aTable.aField = bTable.xField) > 5;
+----+--------------------+--------+------+---------------+------+---------+------+------+-------------+
| id | select_type        | table  | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+--------------------+--------+------+---------------+------+---------+------+------+-------------+
|  1 | PRIMARY            | aTable | ALL  | NULL          | NULL | NULL    | NULL |    4 | Using where |
|  2 | DEPENDENT SUBQUERY | bTable | ALL  | NULL          | NULL | NULL    | NULL |    4 | Using where |
+----+--------------------+--------+------+---------------+------+---------+------+------+-------------+

Both result in a dependent subquery; on my example tables, the first one gets the benefit of the index (I assume bTable.yField is indexed) while the second doesn't.

You can avoid the dependent subquery and get better up-front filtering using a JOIN:

The third alternative:

EXPLAIN SELECT * FROM aTable INNER JOIN bTable On aTable.aField = bTable.xField WHERE bTable.yField > 5;
+----+-------------+--------+-------+---------------+---------------+---------+------+------+--------------------------------+
| id | select_type | table  | type  | possible_keys | key           | key_len | ref  | rows | Extra                          |
+----+-------------+--------+-------+---------------+---------------+---------+------+------+--------------------------------+
|  1 | SIMPLE      | bTable | range | bTable_yField | bTable_yField | 5       | NULL |    2 | Using where                    |
|  1 | SIMPLE      | aTable | ALL   | NULL          | NULL          | NULL    | NULL |    4 | Using where; Using join buffer |
+----+-------------+--------+-------+---------------+---------------+---------+------+------+--------------------------------+

同样,您确实必须使用您的 架构和您的 具有代表性的真实世界数据进行分析,因为优化器可能会做出不同的决定。

this excellent article 中对这些技术进行了更多比较通过 quassnoi .


作为引用,下面是我如何创建 aTablebTable(因为您没有提供定义)并测试您的查询:

mysql> CREATE TABLE aTable (aField INT, aMore VARCHAR(200));
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE TABLE bTable (xField INT, yField INT);
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO aTable (aField, aMore) VALUES (1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> INSERT INTO bTable (xField, yField) VALUES (1, 10), (2, 2), (3, 20), (4, 4);
Query OK, 4 rows affected (0.02 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> CREATE INDEX bTable_yField ON bTable(yField);
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM aTable WHERE aField in (SELECT xField FROM bTable WHERE yField > 5);
+--------+-------+
| aField | aMore |
+--------+-------+
|      1 | One   |
|      3 | Three |
+--------+-------+
2 rows in set (0.00 sec)

mysql> SELECT * FROM aTable WHERE (SELECT yField FROM bTable WHERE aTable.aField = bTable.xField) > 5;
+--------+-------+
| aField | aMore |
+--------+-------+
|      1 | One   |
|      3 | Three |
+--------+-------+
2 rows in set (0.00 sec)

关于mysql - 更快地执行 'WHERE IN (SELECT)' 或 'WHERE x = (SELECT)',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13050351/

相关文章:

php - 使用 PHP 从 MySQL 数据库中提取 ID 号

MySQL 在具有多个 ID 的列中查找空白

php - 如何在将 .CSV 格式的文件导入 SQL 时验证员工 ID?

mysql - 根据列的 SUM 限制结果

mysql - 关于列中的选择查询

mysql - 如何在 mySQL 中按降序对前 10 个条目进行排序?

python - 如何在 Python 脚本中的 MySQL 查询中使用变量路径

mysql - mysql中的用户队列

ASP.NET FormView 更新失败

mysql - 自连接返回比预期更多的行