MySQL 优化器 - 成本规划器不知道 DuplicateWeedout 策略何时创建磁盘表

Posted

技术标签:

【中文标题】MySQL 优化器 - 成本规划器不知道 DuplicateWeedout 策略何时创建磁盘表【英文标题】:MySQL Optimiser - cost planner doesn't know when DuplicateWeedout Strategy creates disk table 【发布时间】:2021-03-24 08:41:37 【问题描述】:

这是我的示例查询

Select table1.id 
from table1 
where table.id in (select table2.id 
                    from table2 
                    where table2.id in (select table3.id 
                                        from table3)
                    ) 
order by table1.id  
limit 100

检查上述查询的优化器跟踪。 优化器跟踪成本

    DUPLICATE-WEEDOUT 策略 - 成本:1.08e7 FIRST MATCH 策略 - 成本:1.85e7

由于 DUPLICATE-WEEDOUT 成本较低,mysql 对上述查询采用了 DUPLICATE-WEEDOUT 策略。

在 join_optimization 部分似乎一切都很好。但最后,在检查了 join_execution 部分之后。 DUPLICATE-WEEDOUT 通常创建临时表。但是这里由于临时表的堆大小不够,它继续创建ondisk临时表(converting_tmp_table_to_ondisk)。

由于磁盘临时表,我的查询执行速度变慢了。


那么这里发生了什么?

优化器跟踪不计算连接优化部分本身的磁盘表成本。如果计算磁盘表成本,它将高于第一次匹配。 那么 final_semijoin_strategy 将是 FIRST-MAT​​CH 策略,这样我的查询会更快。

MYSQL 有没有办法计算连接优化部分本身的磁盘表成本或针对此特定问题的任何其他解决方法?

MYSQ-5.7,INNODB


注意:这是一个非常动态的查询,其中将根据查询中的请求添加多个条件。所以我已经以所有可能的方式优化了查询。最后坚持这个磁盘表成本问题。请避免优化查询(例如更改查询结构,强制首次匹配策略)。并且为了增加堆大小(我不太确定,在不同的论坛上很多人说它可能会在其他查询中带来不同的问题)

【问题讨论】:

鉴于成本与性能没有直接关系,您怎么知道,即使您可以让优化器为您提供所需的结果,查询的运行速度也会明显加快?另外,你为什么不直接加入你的 3 个表而不是使用 IN ? 您是否过度简化了查询?我假设 真正的 问题是“我怎样才能加快这个查询”。 【参考方案1】:

IN( SELECT ... ) 效率低下是出了名的。尽量避免。

所呈现的查询可能等同于

SELECT  t1.id
    FROM  t1
    JOIN  t2 USING(id)
    JOIN  t3 USING(id)
    ORDER BY  id
    LIMIT  100

这将很好地优化。

这个公式不需要构建任何临时表,更不用说基于磁盘的了。

【讨论】:

是的,它相当于上面的查询。但是如果使用 JOIN 而不是 IN,我需要 group by 来删除重复项。这使得查询执行对我们的案例来说真的很糟糕,所以我选择了 IN flow。 id是每张表的PRIMARY KEY吗?如果没有,请为每张桌子提供SHOW CREATE TABLE 是的,我使用的每个 ID 都是主键。 @vinieth - 那么表格是 1:1。你会是什么GROUPing BY 那么,输出可能是相同 t1.id 的 100 个副本?请重新开始——使用真正的查询和真正的SHOW CREATE TABLEs。我怀疑您已将其简化到我们无法直接回答您的地步并且它可能不适用于原始查询。

以上是关于MySQL 优化器 - 成本规划器不知道 DuplicateWeedout 策略何时创建磁盘表的主要内容,如果未能解决你的问题,请参考以下文章

SQL,未使用的 LEFT JOIN 速度变慢,优化器不起作用?

为啥优化器不使用我的唯一过滤索引?

pennylane优化器不更新参数

Oracle 优化器不接受索引提示

MySQL8.0 优化器介绍

mysql查询优化器为什么可能会选择错误的执行计划