Mysql在where子句中优化子查询
Posted
技术标签:
【中文标题】Mysql在where子句中优化子查询【英文标题】:Mysql optimize subquery in where clause 【发布时间】:2017-01-28 18:02:56 【问题描述】:如果我执行查询,例如
SELECT *
FROM `table1`
WHERE 1 OR EXISTS (
SELECT show
FROM `table2`
WHERE id IN(1,2,3)
)
我希望优化器意识到 where 子句总是解析为 true,因此没有必要运行子查询。使用 EXPLAIN 运行查询表明情况并非如此,并且无论如何都会执行子查询。 这是一个更复杂问题的缩小示例,我尝试根据外部查询的列值执行不同的子查询,例如:
SELECT value FROM table t
LEFT JOIN...
WHERE
(SELECT
IF(t.value = 1,
(SELECT ...),
(SELECT ...)
)
)
意思是 where 条件中只有一个内部子查询被执行,但这里也发生了同样的情况,两者都被执行,但只使用了一个的值。所以结果是正确的,但运行了无用的查询。我已经尝试过 CASE WHEN 以及同样的问题。不确定是因为我使用 MariaDB 还是我在这里缺少的东西。
【问题讨论】:
请提供您正在使用的 MariaDB 的版本号。并请提供EXPLAIN SELECT ...
。
类似的查询在 5.6.22 中“短路”失败。
5.7.15、8.0.0 和 MariaDB 10.2.2 同上。
【参考方案1】:
对不起,我希望我能正确理解您的问题。在 WHERE 1 的第一个查询中,mysql 从不执行 EXISTS 子查询。 EPLAIN 只向您展示可以做什么。您可以通过 SHOW status LIKE 'Handler_read_first'; 看到它很简单。我有 2 个表。如果我使用 WHERE 1 进行测试,它的唯一增量为 1(读取 1 个表),没有它的增量为 2
样本
表格
MariaDB [test]> select * from index_usage;
+----+------+------+------+-------+
| id | a | b | c | dummy |
+----+------+------+------+-------+
| 11 | 1 | 1 | 1 | a |
+----+------+------+------+-------+
1 row in set (0.00 sec)
MariaDB [test]> select * from index_usage_copy;
+----+------+------+------+-------+
| id | a | b | c | dummy |
+----+------+------+------+-------+
| 99 | 1 | 1 | 1 | a |
+----+------+------+------+-------+
1 row in set (0.00 sec)
柜台
MariaDB [test]> SHOW status LIKE 'Handler_read_first';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| Handler_read_first | 59 |
+--------------------+-------+
1 row in set (0.00 sec)
第一个查询(没有 WHERE 1)递增 2
MariaDB [test]> SELECT * from index_usage WHERE EXISTS ( SELECT 1 FROM index_usage_copy where id in (1,2,99)); SHOW status LIKE 'Handler_read_first';
+----+------+------+------+-------+
| id | a | b | c | dummy |
+----+------+------+------+-------+
| 11 | 1 | 1 | 1 | a |
+----+------+------+------+-------+
1 row in set (0.00 sec)
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| Handler_read_first | 61 |
+--------------------+-------+
1 row in set (0.00 sec)
MariaDB [test]> SELECT * from index_usage WHERE EXISTS ( SELECT 1 FROM index_usage_copy where id in (1,2,99)); SHOW status LIKE 'Handler_read_first';
+----+------+------+------+-------+
| id | a | b | c | dummy |
+----+------+------+------+-------+
| 11 | 1 | 1 | 1 | a |
+----+------+------+------+-------+
1 row in set (0.00 sec)
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| Handler_read_first | 63 |
+--------------------+-------+
1 row in set (0.00 sec)
MariaDB [test]> SELECT * from index_usage WHERE EXISTS ( SELECT 1 FROM index_usage_copy where id in (1,2,99)); SHOW status LIKE 'Handler_read_first';
+----+------+------+------+-------+
| id | a | b | c | dummy |
+----+------+------+------+-------+
| 11 | 1 | 1 | 1 | a |
+----+------+------+------+-------+
1 row in set (0.00 sec)
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| Handler_read_first | 65 |
+--------------------+-------+
1 row in set (0.00 sec)
现在使用 WHERE 1 - 仅递增 1
MariaDB [test]> SELECT * from index_usage WHERE 1 OR EXISTS ( SELECT 1 FROM index_usage_copy where id in (1,2,99)); SHOW status LIKE 'Handler_read_first';
+----+------+------+------+-------+
| id | a | b | c | dummy |
+----+------+------+------+-------+
| 11 | 1 | 1 | 1 | a |
+----+------+------+------+-------+
1 row in set (0.00 sec)
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| Handler_read_first | 66 |
+--------------------+-------+
1 row in set (0.00 sec)
MariaDB [test]> SELECT * from index_usage WHERE 1 OR EXISTS ( SELECT 1 FROM index_usage_copy where id in (1,2,99)); SHOW status LIKE 'Handler_read_first';
+----+------+------+------+-------+
| id | a | b | c | dummy |
+----+------+------+------+-------+
| 11 | 1 | 1 | 1 | a |
+----+------+------+------+-------+
1 row in set (0.00 sec)
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| Handler_read_first | 67 |
+--------------------+-------+
1 row in set (0.00 sec)
MariaDB [test]>
【讨论】:
【参考方案2】:另外,EXPLAIN FORMAT=JSON
表示 5.6 和 5.7 的“optimized_away_subqueries”。 8.0 和 MariaDB 10.2 和 10.3 并没有这么说,但似乎无论如何都摆脱了子查询。
【讨论】:
以上是关于Mysql在where子句中优化子查询的主要内容,如果未能解决你的问题,请参考以下文章
Oracle 查询优化器是不是将*** where 子句应用于子查询或视图?
子选择查询是不是基于它之外的 WHERE 子句进行了优化? [关闭]