这两个 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别名,比如c
为customers
。并且,限定 all 列引用,以便清楚列的来源。任意字母可能比根本没有别名更糟糕(假设列都是合格的)。
请提供SHOW CREATE TABLE
.
听起来好像缺少这些索引:
B: INDEX(customer_id)
C: INDEX(order_id)
D: INDEX(product_id)
我是 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别名,比如c
为customers
。并且,限定 all 列引用,以便清楚列的来源。任意字母可能比根本没有别名更糟糕(假设列都是合格的)。
请提供SHOW CREATE TABLE
.
听起来好像缺少这些索引:
B: INDEX(customer_id)
C: INDEX(order_id)
D: INDEX(product_id)