使用LEFT JOIN查询时,MySQL Empty表返回TRUE

时间:2017-08-21 14:18:40

标签: mysql

我刚刚在MySQL 5.7中遇到了一个奇怪的行为(bug?),它没有出现在MySQL 5.5中。

太尴尬了,我需要一个例子来解释它。

  1. 使用2个表格上的左连接创建表格
  2. 确保第二个表为空(没有记录),但是通过在其中一个字段中写入静态值来构造。
  3. 无条件的左连接产生N行(如预期的那样)

    左连接一个永不匹配的条件 ALSO产生N行。

    ### EXAMPLE ###
    
    ## CREATE TABLES
    
    create table PCPL (K1 int);  ## Table 1
    create table AUX (K2 int);   ## Table 2
    
    ## FILL IN TABLES
    
    insert into PCPL values (1),(2),(3);    ## fill main table with 3 values
    truncate table AUX;                     ## No need to do this, just to make things clearer
    
    ## TEST 1 : "Dry Left join" => RESULT OK : Resulting Table has 3 rows
    
    select PCPL.K1 as K1 , DERIVED.K2  as K2 
    from PCPL
    LEFT JOIN (select K2, 1 as staticValue from AUX) DERIVED
    ON PCPL.K1 = DERIVED.K2; 
    
    +------+------+
    | K1   | K2   |
    +------+------+
    |    1 | NULL |
    |    2 | NULL |
    |    3 | NULL |
    +------+------+
    3 rows in set (0,00 sec)
    
    
    ## TEST 2 : "Never matching condition" => STRANGE : Resulting Table NOT empty 
    
    select PCPL.K1 as K1 , DERIVED.K2  as K2  
    from PCPL
    LEFT JOIN (select K2, 1 as staticValue from AUX) DERIVED
    ON PCPL.K1 = DERIVED.K2
    where staticValue=1;   ##### THIS CONDITION IS NEVER MET SINCE TABLE AUX IS EMPTY
    
    +------+------+
    | K1   | K2   |
    +------+------+
    |    1 | NULL |
    |    2 | NULL |
    |    3 | NULL |
    +------+------+
    3 rows in set (0,00 sec)
    
    THIS SHOULDN'T HAPPEN !
    

    MySQL 5.5不会发生此行为

    这是我在5.5中忘记设置的5.5中的错误或某些参数吗?

    谢谢你的时间!

2 个答案:

答案 0 :(得分:2)

这看起来像是子查询合并中的错误。这是一种允许MySQL避免实现子查询的开销的策略。

考虑以下两个查询(第一个是原始查询):

select PCPL.K1 as K1, DERIVED.K2 as K2,
       (CASE WHEN DERIVED.K2 IS NULL THEN 'is null' ELSE 'not null' END) as K2_null,
       staticValue
       (CASE WHEN staticValue IS NULL THEN 'is null' ELSE 'not null' END) as staticValue_null
from PCPL LEFT JOIN
     (select K2, 1 as staticValue from AUX) DERIVED
     ON PCPL.K1 = DERIVED.K2
where staticValue IS NOT NULL;

这个修改过的表单只有DERIVED的唯一区别:

select PCPL.K1 as K1, DERIVED.K2 as K2,
       (CASE WHEN DERIVED.K2 IS NULL THEN 'is null' ELSE 'not null' END) as K2_null,
       staticValue
       (CASE WHEN staticValue IS NULL THEN 'is null' ELSE 'not null' END) as staticValue_null
from PCPL LEFT JOIN
     (select K2, 1 as staticValue from AUX order by k2 limit 3) DERIVED
-------------------------------------------^XXXXXXXXXXXXXXXXXX
     ON PCPL.K1 = DERIVED.K2
where staticValue IS NOT NULL;

order by k2 limit 3的目的是强制子查询的实现。第一个版本返回三行(不正确)。第二个版本返回零行(正确)。在这两种情况下,子查询都返回相同的行集。

不同之处在于强制实现可以解决问题。因此,这看起来像子查询合并中的错误。

您可以在documentation中阅读有关子查询合并的内容。

一篇小编辑。复杂的数据库将查询解析为描述处理的DAG(有向非循环图)。然后,他们有通过图表推送操作的复杂规则 - 特别是过滤操作和列计算。

MySQL从一个更简单的查询模型开始。开发人员正朝着更复杂的模式迈进。像这样的小错误并不出乎意料,但需要一两个版本来解决它们。

答案 1 :(得分:0)

非常感谢。在等待修复错误的同时,可以通过在变量 optimizer_switch

中取消设置 derived_merge 来防止错误发生
SET @@optimizer_switch='block_nested_loop=off';