SQL 查询非常慢 - 我该如何改进它?

Posted

技术标签:

【中文标题】SQL 查询非常慢 - 我该如何改进它?【英文标题】:SQL query very slow - How can I improve it? 【发布时间】:2016-06-15 19:20:28 【问题描述】:

我正在管理一个数据库,我想知道是否有更酷的方法来进行此查询。

我的实际查询:

SELECT * FROM mytable 
LEFT JOIN table1 AS m1 ON mytable.idA=m1.K 
LEFT JOIN table1 AS m2 ON mytable.idB=m2.K 
LEFT JOIN table1 AS m3 ON mytable.idC=m3.K 
LEFT JOIN table1 AS m4 ON mytable.idD=m4.K 
LEFT OUTER JOIN table2 AS t1 ON mytable.idK1= t1.idK1 AND mytable.idK2= t1.idK2
LEFT OUTER JOIN table3 ON t1.idT = table3.idT
WHERE m1.K = "my_value" OR m2.K = "my_value" OR m3.K = "my_value" OR m4.K = "my_value"

我有一个查询在同一个其他表上进行 4 次连接,因为我可以在字段 idA、idB、idC 或 idD 中获得值。 之后,我与其他表进行其他 2 个联接。

我的问题是: 我可以改进这段代码吗?有没有更聪明的方法或更好的逻辑可以遵循? 非常感谢,即使是理论上的解释。

【问题讨论】:

你的表格有正确的索引吗? 我会 (1) 确保索引 idA 等,并且 (2) 与 ON idA=K OR idB=K OR idC=K OR idD=K 进行一次联接,这不是完全相同的登录,但可以做你想做的事。想想吧。 并按名称调用列。 * 太贵了 你对idA,idB,idC,idD的值做了什么? 通过WHERE 子句将INNER JOINs 转换为INNER JOINs,你正在扼杀你的LEFT JOINs。这与您的表现无关,但您的查询没有在做您认为它正在做的事情。 【参考方案1】:

考虑您可以索引以下哪些列:mytable.idAmytable.idBmytable.idCmytable.idDtable1.Ktable2.idTtable2.idT

还要考虑是否可以为table2.idK1table2.idK2 创建索引;另一个用于mytable.idK1mytable.idK2

【讨论】:

从长远来看,不建议只为一个查询创建索引。根据表的大小,您最终将至少使表的大小增加一倍(如果您经常访问索引会占用大量磁盘和内存)。当您有 6 个表时,引擎必须计算 6!决策树并对其进行优化。如果您共享整个表格结构和表格状态以查看基数,这将有所帮助。 在推荐任何索引更改之前,请仔细考虑。否则是不负责任的。 表的大小是 mytable 的 250k 值,其他的小于 50k。 @Shago 如何使用和索引?我不知道利弊 @emish89 看看这个答案***.com/a/29842947/2576398【参考方案2】:

我试过这样做,执行时间确实更好:

SELECT * FROM (
SELECT * FROM mytable WHERE idA = "my_value" OR idB = "my_value" OR idC = "my_value" OR idD = "my_value"
) as p1
LEFT JOIN table1 AS m1 ON p1.idA=m1.K 
LEFT JOIN table1 AS m2 ON p1.idB=m2.K 
LEFT JOIN table1 AS m3 ON p1.idC=m3.K 
LEFT JOIN table1 AS m4 ON p1.idD=m4.K 
LEFT OUTER JOIN table2 AS t1 ON p1.idK1= t1.idK1 AND p1.idK2=  t1.idK2
LEFT OUTER JOIN table3 ON t1.idT = table3.idT

现在执行时间是 0.06 秒,之前是 1.5 - 2 秒。

我能引起一些问题吗?查询似乎运行良好

【讨论】:

以上是关于SQL 查询非常慢 - 我该如何改进它?的主要内容,如果未能解决你的问题,请参考以下文章

如何改进热图的大型数据集的 KQL 查询

我将性能计数器的值发送到 Graphite 的方法非常慢。瓶颈是啥?以及如何改进?

SQL 查询优化——真的没有啥可改进的了吗?

更新表时如何改进 Spark 中的 SQL 查询? (子查询中的'NOT IN')

如何改进具有多个子查询的 SELECT 语句

SQL查询很慢。没有索引如何改进?