Mysql在where子句中优化子查询

时间:2017-01-28 18:02:57

标签: mysql subquery query-optimization

如果我执行查询,例如

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条件中只有一个inners子查询被执行,但是这里发生了同样的事情,两者都被执行但只使用了一个值。因此结果是正确的,但运行无用的查询。我试过CASE WHEN和同样的问题。不确定是不是因为我使用的是MariaDB或者我在这里缺少的东西。

2 个答案:

答案 0 :(得分:0)

抱歉,我希望我能正确理解你的问题。在使用 WHERE 1 的第一个查询中,MySQL NEVER执行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 - 仅增加一个

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]>

答案 1 :(得分:0)

此外,EXPLAIN FORMAT=JSON对于5.6和5.7说“ optimized_away_subqueries”。 8.0和MariaDB 10.2和10.3并没有这么说,但似乎还是摆脱了子查询。