这两个 SQL 查询之间是否存在性能差异?

时间:2021-01-25 09:17:49

标签: mysql sql sql-tuning

我是一个新的 SQL 学习者,也是 StackOverflow 的新手。希望我第一次发帖时没有错过任何重要的东西。

我碰巧从我的导师那里得到两个以下问题,说他们有不同的表现。但我不明白为什么它们在逻辑和计算成本方面不同。

查询 1:

SELECT First_Name,
SUM(total_sales_amount) AS sub_total_sales_amount  FROM
(
select A.First_Name, C.product_quantity * D.Retail_Price AS t  otal_sales_amount From join_demo.customer as A
inner join join_demo.customer_order as B  on A.customer_id = B.customer_id
inner join join_demo.order_details C  on B.order_id = C.order_id
inner join join_demo.product as D  on C.product_id= D.product_id
) E
GROUP BY 1
ORDER BY sub_total_sales_amount DESC  LIMIT 1;

查询 2(有人告诉我这个有更好的性能):

SELECT A.First_Name,  SUM(C.product_quantity * D.Retail_Price)  AS  sub_total_sales_amount
From join_demo.customer as A
inner join join_demo.customer_order as B  on A.customer_id = B.customer_id
inner join join_demo.order_details C  on B.order_id = C.order_id
inner join join_demo.product as D  on C.product_id= D.product_id  GROUP BY 1
ORDER BY sub_total_sales_amount DESC  LIMIT 1;

我在本地 Mac 上运行 MySQL。但我想这将是一个关于 SQL 性能调优的一般问题。 有人可以解释这个问题吗?非常感谢!

更新: 感谢@Tim 和@MatBailie。我在每个查询之前都添加了 EXPLAIN。 结果完全一样。我猜两个查询的性能水平相同。

<头>
id 选择类型 分区 类型 possible_keys key_len 参考 过滤 额外
1 简单 A NULL 全部 NULL NULL NULL NULL 3 100 使用临时;使用文件排序
1 简单 B NULL 全部 NULL NULL NULL NULL 4 25 使用哪里;使用连接缓冲区(哈希连接)
1 简单 C NULL 全部 NULL NULL NULL NULL 5 20 使用哪里;使用连接缓冲区(哈希连接)
1 简单 D NULL 全部 NULL NULL NULL NULL 5 20 使用哪里;使用连接缓冲区(哈希连接)

3 个答案:

答案 0 :(得分:1)

旧版本的 MySQL 用于自动物化派生表(FROM 子句中的子查询)。 “Materialize”意味着 MySQL 运行子查询并将结果保存在一个临时位置(在这种情况下,在进行聚合之前)。

我认为从 5.7 版开始优化器得到了改进(尽管历史可能是错误的)。现在,MySQL 在物化方面更加智能,通常会将子查询与外部查询合并。

因此,更新版本的 MySQL 应该产生相同的执行计划。当然,优化器可能会混淆,优化器可能会决定具体化子查询,这在大多数情况下会减慢查询速度。

您可以在 documentation 中阅读更多相关信息。

您还应该学习使用有意义的表别名,例如 c 代表 customers。并且,限定所有 列引用,以便清楚列的来源。任意字母可能比根本没有别名更糟糕(假设列都是限定的)。

答案 1 :(得分:0)

第一个查询使用显式子查询首先生成一个中间结果,其中包含每个名字的每个总金额。然后,它在外部查询中聚合 name 以生成您想要的总和。第二个版本不使用任何这样的中间子查询,而是直接在连接的表上聚合。因此,第一个查询可能会在内存和性能方面产生额外的开销,因为 MySQL 必须聚合中间表。

但是,您应该检查两个查询的 EXPLAIN 计划以验证这一点。也有可能 MySQL 足够聪明,可以使用与第二个相同的计划来执行第一个查询。

答案 2 :(得分:0)

请提供SHOW CREATE TABLE

听起来好像缺少这些索引:

B:  INDEX(customer_id)
C:  INDEX(order_id)
D:  INDEX(product_id)