这两个 SQL 查询之间有任何性能差异吗?

Is there any performance difference between those two SQL queries?

我是 SQL 新手,也是 Whosebug 的新手。希望我第一次没有错过任何重要的事情 post。

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

查询 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;

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

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

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE A NULL ALL NULL NULL NULL NULL 3 100 Using temporary; Using filesort
1 SIMPLE B NULL ALL NULL NULL NULL NULL 4 25 Using where; Using join buffer (hash join)
1 SIMPLE C NULL ALL NULL NULL NULL NULL 5 20 Using where; Using join buffer (hash join)
1 SIMPLE D NULL ALL NULL NULL NULL NULL 5 20 Using where; Using join buffer (hash join)

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

上聚合

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

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

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

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

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

你还应该学会使用有意义的table别名,比如ccustomers。并且,限定 all 列引用,以便清楚列的来源。任意字母可能比根本没有别名更糟糕(假设列都是合格的)。

请提供SHOW CREATE TABLE.

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

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