我有一个查询 带有 GROUP BY 子句,该查询在 3-4s 内执行。如果我删除 GROUP BY,执行时间会下降到 0.05 秒。 GROUP BY 已经使用索引值(-> 其中一个表的主键)。 当然,我需要 GROUP BY 子句,我无法摆脱它。
我可以做什么来加快此查询速度? (这是我的应用程序中最常用的查询之一。)
这是查询:
SELECT col1, col2, (...)
FROM table1 AS t1
JOIN table2 AS t2
ON t2.fk_id = t1.a_id
JOIN table3 AS t3
ON t3.fk_id = t2.id
JOIN table4 AS t4
ON t4.fk_id = t1.b_id
JOIN table5 AS t5
ON t5.fk_id = t4.id
LEFT JOIN table6 AS t6
ON t6.fk_id = t1.c_id
LEFT JOIN table7 AS t7
ON t7.fk_id = t6.id
WHERE t3.user_id = 12345
AND t5.slug NOT IN ( 'slug_a','slug_b')
GROUP BY t1.id
编辑: 这是 EXPLAIN 命令的结果: (表名显然和我之前写的查询中的不一样......)
id | 选择类型 | 桌子 | 类型 | 可能的键 | 键 | key_len | 参考 | 行 | 额外信息 |
---|---|---|---|---|---|---|---|---|---|
1 | 简单 | p (=t3) | 参考 | 主要,partners_index_32 | partners_index_32 | 4 | 常量 | 1 | 临时使用;使用文件排序 |
1 | 简单 | o (=t2) | 参考 | 主要,orders_index_1,id_client_id | orders_index_1 | 4 | apicg.p.id | 228 | |
1 | 简单 | i (=t1) | 参考 | items_index_7,item_gid | items_index_7 | 4 | apicg.o.id | 1 | 使用地点 |
1 | 简单 | v (=t4) | 参考 | product_variants_index_17、product_variants_index_18、global_id_product_id | product_variants_index_17 | 9 | apicg.i.item_gid | 1 | |
1 | 简单 | pr (=t5) | eq_ref | 主要,产品索引_16,id_名称 | 小学 | 4 | apicg.v.product_id | 1 | 使用地点 |
1 | 简单 | d (=t6) | 参考 | to_provide,object_gid_to_validate | object_gid_to_validate | 8 | apicg.i.global_id | 6 | 使用地点 |
1 | 简单 | inv (=t7) | 参考 | unique_2,invalidities_ibfk_3_idx | invalidities_ibfk_3_idx | 5 | apicg.d.id | 99503 | 使用地点 |
https://dev.mysql.com/doc/refman/8.0/en/internal-temporary-tables.html 说:
服务器在以下条件下创建临时表:
...
评估包含 ORDER BY 子句和不同的 GROUP BY 子句的语句,或者 ORDER BY 或 GROUP BY 包含连接队列中第一个表以外的表中的列。
(强调我的)
这对于您的查询意味着什么:
EXPLAIN 显示表
t3
是连接队列中的第一个表。但是你GROUP BY t1.id
,优化器已将其放在连接队列中的第三位。
优化器可以选择对表重新排序,以便以与您在查询中指定的顺序不同的顺序访问它们。通常优化器这样做是有充分理由的,以提供更好的性能优势。
但是,如果您 GROUP BY
优化器未首先对表中的列进行排序,那么您总是会在 EXPLAIN 中看到
使用临时表。
您可以尝试强制表顺序,覆盖优化器的选择。但这可能会因其他原因导致性能变差。
您可以尝试避免在磁盘上使用临时表。就像确保结果中没有
TEXT
或 BLOB
或 JSON
列(如果不需要)。或者干脆省略其他不需要的列。
您可以尝试更改磁盘临时表存储引擎。
您可以获得更快的存储设备。
您可以减少数据,使临时表更小。
您可以减少运行查询的频率,并在大多数时间依赖缓存的结果。