3

假设我在 CASE...WHEN...THEN 中有一个带有子查询的查询(简化,因为我正在处理的真正查询对眼睛来说有点困难):

SELECT
  CASE 
    WHEN (subquery1) = 1
      THEN (subquery2)
    WHEN (subquery1) > 1 AND (subquery3) = 1
      THEN (subquery4)
  END
FROM foo

所有 4 个子查询都是依赖子查询。

是否所有 4 个子查询都被执行?因为当我执行 EXPLAIN 时,所有子查询都包含在计划中。

还是只先执行 subquery1,如果满足该条件,将执行 subquery2?如果没有,将执行 subquery3 以检查是否满足条件,依此类推...当我将查询重写为存储过程以仅以这种方式执行唯一相关的子查询时,性能有所提高(时间减少)。我很想知道原始查询是否需要更多时间,因为它执行所有子查询,无论是否满足先前的条件。

我尝试打开通用日志,但子查询没有单独记录。它们作为整个查询一起记录,因此我无法确定实际执行了哪个子查询。还尝试查看 SUBQUERY 上的 MySQL 文档,但我还没有找到任何东西。

4

2 回答 2

3

我发现这是一个有趣的问题。

解释计划不能真正告诉你答案,因为它们是静态的,而条件评估发生在运行时。

case表达式的文档没有提供有关when条件评估顺序的详细信息。case 然而,声明的文档指出:

每个WHEN子句 search_condition 表达式都被评估,直到一个为真,此时其对应的THEN子句 statement_list 执行。如果没有 search_condition 相等,则ELSE执行子句 statement_list(如果有)。

这往往表明,一旦满足某个条件,就不会检查其他条件。但是您的代码包含 case 表达式,而不是 case 语句(属于存储过程)。

对于它的价值,这里是一个带有case表达式的(过度简化的)测试场景。考虑以下代码:

select case 
    when (select 1) = 1 then 'should stop here'
    when (select 1 union all select 2) = 1 then 'should not get there, or it will die'
end t

第一个条件评估为真。如果评估第二个条件,则会引发运行时错误Subquery returns more than 1 row

当我们在这个 db fiddle中运行查询时,我们得到了预期的结果,并且没有发生运行时错误:

| t                |
| ---------------- |
| should stop here |

所以这也倾向于表明子查询是按顺序评估的,并且 MySQL 会尽快停止评估条件。但是,请不要想当然:在文档中没有明确声明的情况下,这只是经验性的!

于 2019-12-10T00:53:34.160 回答
1

我发现 CASE 表达式评估很棘手。这是示例:

CREATE TABLE `tt` (
    `id` INT(11) NULL DEFAULT NULL
);

INSERT INTO `tt` (`id`) VALUES (1);

DELIMITER $$

CREATE FUNCTION `ff1`(`f` VARCHAR(15)) RETURNS int(11)
BEGIN
    -- Case EXPRESSION
    RETURN CASE
        WHEN f = 'id' THEN (SELECT id FROM tt LIMIT 1)
        WHEN f = 'z'  THEN (SELECT z/*non-existing column*/ FROM tt LIMIT 1)
    END;
END$$

CREATE FUNCTION `ff2`(`f` VARCHAR(15)) RETURNS int(11)
BEGIN
    -- Case CLAUSE
    CASE
        WHEN f = 'id' THEN SELECT id INTO @result FROM tt LIMIT 1;
        WHEN f = 'z'  THEN SELECT z/*non-existing column*/ INTO @result FROM tt LIMIT 1;
    END CASE;
    RETURN @result;
END$$

DELIMITER ;

SELECT ff1('id'); -- error 'Unknown column z...'
SELECT ff1('z');  -- error 'Unknown column z...'
SELECT ff2('id'); -- 1
SELECT ff2('z');  -- error 'Unknown column z...'
于 2019-12-10T01:48:39.017 回答