[英]Does MySQL optimize selected aggregations on related tables to avoid N+1?
Is this query optimal in MySQL? 这个查询在MySQL中最优吗? I mean: Is there a constant amount of queries being executed? 我的意思是:是否有恒定数量的查询正在执行?
OR does it fall in the N+1 problem? 还是它属于N + 1问题? Found nothing too detailed in the official MySQL docs regarding optimization. 在官方MySQL文档中没有发现关于优化的任何细节。
SELECT t.*, (SELECT COUNT(1) from related_table rt where rt.t_id = t.id)
FROM table t
In a naive sight, there's a query and N queries, so it would fall in the N+1 problem. 天真地看,有一个查询和N个查询,因此它属于N + 1问题。
Does MySQL 5.5+ automagically+internally improve this query to make a constant number of queries? MySQL 5.5+是否会在内部自动地+改进此查询以进行恒定数量的查询? perhaps transforming it internally to something like: 也许将其内部转换为:
SELECT t.*, COUNT(rt.id)
FROM table t LEFT OUTER JOIN related_table rt
GROUP BY t.id
I mean: I know how to improve it by hand, but I'm asking this because: 我的意思是:我知道如何手动进行改进,但是我之所以这样问是因为:
No, a correlated subquery in the select-list is not optimized out by MySQL. 不,MySQL没有优化选择列表中的相关子查询。
You can confirm this by using EXPLAIN to get a report of the optimization plan. 您可以使用EXPLAIN来获取优化计划的报告来确认这一点。 Here's a similar query using a test database: 这是一个使用测试数据库的类似查询:
mysql> explain select *, (SELECT COUNT(*) FROM cast_info where cast_info.role_id = role_type.id) AS c
from role_type\G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: role_type
partitions: NULL
type: index
possible_keys: NULL
key: role
key_len: 98
ref: NULL
rows: 12
filtered: 100.00
Extra: Using index
*************************** 2. row ***************************
id: 2
select_type: DEPENDENT SUBQUERY
table: cast_info
partitions: NULL
type: ref
possible_keys: cr
key: cr
key_len: 4
ref: imdb.role_type.id
rows: 2534411
filtered: 100.00
Extra: Using index
The select type of DEPENDENT SUBQUERY means that the subquery will be executed many times, probably once for each row of the outer query. DEPENDENT SUBQUERY的选择类型意味着该子查询将执行多次,可能对外部查询的每一行执行一次。
Compare with the EXPLAIN for the manually optimized query: 与EXPLAIN进行比较,以进行手动优化的查询:
mysql> explain select r.*, COUNT(c.id) AS c from role_type AS r left outer join cast_info as c on r.id = c.role_id group by r.id\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: r
partitions: NULL
type: index
possible_keys: PRIMARY,role
key: PRIMARY
key_len: 4
ref: NULL
rows: 12
filtered: 100.00
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: c
partitions: NULL
type: ref
possible_keys: cr
key: cr
key_len: 4
ref: imdb.r.id
rows: 2534411
filtered: 100.00
Extra: Using index
This shows the access to the second table is just a simple join by reference. 这表明对第二张表的访问只是一个简单的引用联接。
You can also test with the MySQL query profiler . 您也可以使用MySQL查询分析器进行测试。 Here's the second query, that uses join: 这是第二个查询,它使用join:
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000167 |
| checking permissions | 0.000015 |
| checking permissions | 0.000016 |
| Opening tables | 0.000050 |
| init | 0.000059 |
| System lock | 0.000044 |
| optimizing | 0.000011 |
| statistics | 0.000151 |
| preparing | 0.000099 |
| Sorting result | 0.000019 |
| executing | 0.000010 |
| Sending data | 9.700879 |
| end | 0.000024 |
| query end | 0.000022 |
| closing tables | 0.000017 |
| freeing items | 0.000243 |
| cleaning up | 0.000056 |
+----------------------+----------+
And here's the one with the dependent subquery: 这是带有依赖子查询的子查询:
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000152 |
| checking permissions | 0.000014 |
| checking permissions | 0.000013 |
| Opening tables | 0.000050 |
| init | 0.000067 |
| System lock | 0.000042 |
| optimizing | 0.000010 |
| statistics | 0.000367 |
| preparing | 0.000033 |
| optimizing | 0.000015 |
| statistics | 0.000032 |
| preparing | 0.000020 |
| executing | 0.000010 |
| Sending data | 0.000191 |
| executing | 0.000010 |
| Sending data | 4.103899 |
| executing | 0.000018 |
| Sending data | 2.413570 |
| executing | 0.000018 |
| Sending data | 0.043924 |
| executing | 0.000022 |
| Sending data | 0.037834 |
| executing | 0.000020 |
| Sending data | 0.014127 |
| executing | 0.000021 |
| Sending data | 0.089977 |
| executing | 0.000023 |
| Sending data | 0.045968 |
| executing | 0.000024 |
| Sending data | 0.000044 |
| executing | 0.000005 |
| Sending data | 0.190935 |
| executing | 0.000034 |
| Sending data | 1.046394 |
| executing | 0.000018 |
| Sending data | 0.017567 |
| executing | 0.000021 |
| Sending data | 0.882959 |
| end | 0.000046 |
| query end | 0.000023 |
| closing tables | 0.000018 |
| freeing items | 0.000248 |
| cleaning up | 0.000025 |
+----------------------+----------+
You can see that the subquery causes multiple executions. 您可以看到子查询导致多次执行。 In my case, I had just a few rows in the role_type table, but if you have hundreds or thousands, the number of subquery executions can get so long that the profiler truncates that report. 以我为例,role_type表中只有几行,但是如果您有成百上千的子查询执行次数,则可能会很长,以至于探查器会截断该报告。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.