我需要使用一个查询从多个表中获取数据,该查询提供大约 10600 个结果(行)。问题是查询需要很长时间来执行。就像..很长时间..90秒。
有什么方法可以在不添加索引的情况下改进查询?表格不断更新(插入、更新、删除行)。
这是查询:
SELECT
t1.ID
, t1.ref
, t1.type
, GROUP_CONCAT(DISTINCT t3.name) AS parish
, GROUP_CONCAT(DISTINCT t2.village) AS village
, GROUP_CONCAT(DISTINCT t2.code) AS code
, GROUP_CONCAT(DISTINCT t4.year) AS year
FROM table1 t1
LEFT OUTER JOIN table2 AS t2 ON t2.teade_ID = t1.ID
LEFT OUTER JOIN table3 AS t3 ON t2.parish_ID = t3.ID
LEFT OUTER JOIN table4 AS t4 ON t4.teade_ID = t1.ID
GROUP BY t1.ID, t1.ref, t1.type
ORDER BY t1.ID DESC
非常感谢任何帮助!
答案 0 :(得分:0)
加入前聚合:
SELECT t1.ID, t1.ref, t1.type,
t2.villages, t2.codes,
t3.villages, t4.years
FROM table1 t1 LEFT JOIN
(SELECT t2.teade_ID, GROUP_CONCAT(t2.code) AS codes,
GROUP_CONCAT(t2.village) as villages
FROM table2 t2
GROUP BY t2.teade_ID
) t2
ON t2.teade_ID = t1.ID LEFT JOIN
(SELECT t2.teade_ID, GROUP_CONCAT(t3.village) as villages
FROM table2 t2 JOIN
table3 t3
ON t2.parish_ID = t3.ID
GROUP BY t2.teade_ID
) t3
ON t3.teade_id = t.id LEFT JOIN
(SELECT GROUP_CONCAT(t4.year) AS year
FROM table4 t4
GROUP BY t2.teade_ID
) t4
ON t4.teade_ID = t1.ID
ORDER BY t1.ID DESC;
您可能仍需要 DISTINCT
中的 GROUP_CONCAT()
。从您的问题中不清楚是否还需要这样做。
为什么这样更快?您的版本正在为每个 ID
生成所有表的叉积 - 可能会大大增加数据的大小。更多的数据会使 GROUP BY
变慢。
另请注意,外部查询中没有聚合。
答案 1 :(得分:0)
计划 A - 使 GROUP BY 和 ORDER BY 匹配:
通常索引主要用于 WHERE
子句。但是没有过滤,所以索引可以移动到 GROUP BY
。你有什么索引?如果您有 PRIMARY KEY(id)
,则更改为简单的可能会起作用:
GROUP BY t1.ID
ORDER BY t1.ID DESC
如果 ONLY_FULL_GROUP_BY
有问题,您可能需要
GROUP BY t1.ID, t1.ref, t1.type
ORDER BY t1.ID DESC, t1.ref DESC, t1.type DESC
无论哪种情况,请注意 GROUP BY 和 ORDER BY 如何相互“匹配”。有了这个(与您所拥有的不同),两个子句都可以在一个步骤中完成。因此无需收集所有行,进行分组,然后排序。摆脱排序是您获得速度的地方。
B 计划 - 延迟访问麻烦的 ref
和 type
:
SELECT ID, t1x.ref, t1x.type
FROM (
SELECT
t1.ID
, GROUP_CONCAT(DISTINCT t3.name) AS parish
, GROUP_CONCAT(DISTINCT t2.village) AS village
, GROUP_CONCAT(DISTINCT t2.code) AS code
, GROUP_CONCAT(DISTINCT t4.year) AS year
FROM table1 t1
LEFT OUTER JOIN table2 AS t2 ON t2.teade_ID = t1.ID
LEFT OUTER JOIN table3 AS t3 ON t2.parish_ID = t3.ID
LEFT OUTER JOIN table4 AS t4 ON t4.teade_ID = t1.ID
GROUP BY t1.ID
) x
JOIN t1 AS t1x USING(ID)
ORDER BY t1.ID DESC
ORDER BY
在派生表中被忽略; GROUP BY
在外部表中不是必需的。
计划 C - 在 ID
是 PK 的假设下摆脱 GROUP BY:
SELECT ID, ref, type
( SELECT GROUP_CONCAT(DISTINCT t3.name)
FROM t3 WHERE t3.ID = t1.ID ) AS parish,
( ... ) AS ...,
( ... ) AS ...,
( ... ) AS ...
FROM t1
ORDER BY ID DESC
子查询具有与原始 LEFT JOIN
相同的语义。
您的原始查询受到“explode-implode”的影响。首先 JOIN 收集所有教区等,导致一个大的中间表。然后分组将其收缩回仅您需要的内容。计划 C 避免了爆炸-内爆,从而避免了 GROUP BY。
此外,不会有排序,因为它可以简单地以相反的顺序扫描表格。