多个INNER JOIN太慢SQL SERVER

时间:2015-08-07 17:40:15

标签: sql-server performance inner-join

我遇到了性能问题。

我创建了一个从文件中接收数据的表,我做了BULK INSERT。然后我使用多个SELECT s(11个内部联接)执行INNER JOIN以插入具有正确数据的另一个表。

当我运行这个SELECT时,它需要太长时间(超过一个小时),然后我就停止它。我的解决方案是将此查询分解为3,创建@temp表。令我惊讶的是,这需要3分钟。这就是我试图理解的内容,为什么将我的查询分解为3比一个选择语句更快。这是我的疑问:

SELECT t1.ReturnINT, t1.ReturnBIT, t2.ReturnINT, t3.ReturnINT, t5.ReturnINT, t1.ReturnDateTime
FROM t1
INNER JOIN t2
    ON t2.my_column_varchar = t1.my_column_varchar
INNER JOIN t3
    ON t3.my_column_number = t1.my_column_number AND t2.my_column_ID = t3.my_column_ID
INNER JOIN t4
    ON t4.my_column_varchar = t1.my_column_varchar
INNER JOIN t5
    ON t5.my_column_int = t1.my_column_int AND t5.my_column_int = t4.my_column_int AND t2.my_column_int = t5.my_column_int
INNER JOIN t6
    ON t6.my_column_int = t5.my_column_int AND t6.my_column_int = t2.my_column_int
INNER JOIN t7
    ON t7.my_column_int = t6.my_column_int
INNER JOIN t8
    ON t8.my_column_int = t3.my_column_int AND t8.my_column_datetime = t1.my_column_datetime
INNER JOIN t9
    ON t9.my_column_int = t3.my_column_int AND t8.my_column_datetime BETWEEN t9.my_column_datetime1 AND t9.datetime1 + t9.my_column_datetime2
INNER JOIN t10
    ON t10.my_column_int = t9.my_column_int AND t10.my_column_int = t6.my_column_int
INNER JOIN t11
    ON t11.my_column_int = t9.my_column_int AND t8.my_column_datetime = t11.my_column_datetime

---- ---- EDITED

没有where子句,我的查询与我放在这里完全一样。

这是我的破碎的问题,我忘了把它们放在这里。它运行3分钟。

DECLARE @temp TABLE (
    <Some_columns>
)
INSERT INTO @temp
    SELECT <My_Linked_Columns>
    FROM t1
    INNER JOIN t2
        ON t2.my_column_varchar = t1.my_column_varchar
    INNER JOIN t3
        ON t3.my_column_number = t1.my_column_number AND t2.my_column_ID = t3.my_column_ID
    INNER JOIN t4
        ON t4.my_column_varchar = t1.my_column_varchar
    INNER JOIN t5
        ON t5.my_column_int = t1.my_column_int AND t5.my_column_int = t4.my_column_int AND t2.my_column_int = t5.my_column_int


DECLARE @temp2 TABLE(
    <Some_Columns>
)
INSERT INTO @temp2
    SELECT <More_Linked_Columns>
    FROM @temp as temp
    INNER JOIN t6
        ON t6.my_column_int = temp.my_column_int AND t6.my_column_int = temp.my_column_int
    INNER JOIN t7
        ON t7.my_column_int = t6.my_column_int
    INNER JOIN t8
        ON t8.my_column_int = temp.my_column_int AND t8.my_column_datetime = temp.my_column_datetime


DECLARE @temp3 TABLE(
    <Some_Columns>
)
INSERT INTO @temp3
    SELECT <More_Linked_Columns>
    FROM @temp2 AS temp2
    INNER JOIN t9
        ON t9.my_column_int = temp2.my_column_int AND temp2.my_column_datetime BETWEEN t9.my_column_datetime1 AND t9.datetime1 + t9.my_column_datetime2
    INNER JOIN t10
        ON t10.my_column_int = t9.my_column_int AND t10.my_column_int = temp2.my_column_int
    INNER JOIN t11
        ON t11.my_column_int = t9.my_column_int AND temp2.my_column_datetime = t11.my_column_datetime


SELECT <All_Final_Columns>
FROM @temp3

----编辑3 ----

研究更多的事情我发现执行计划中存在问题。我有一个嵌套循环估计1行,但实际上返回1.204.014行。我想问题就在这里,但我没有找到如何解决这个问题,而不会在3个部分中破坏我的查询(现在我知道为什么打破它更快hehehe)

4 个答案:

答案 0 :(得分:4)

最常见的原因:

原因1:当两个参与INNER JOIN的n行和m行的表具有多对多关系时,INNER JOIN可以靠近CROSS JOIN并且可以生成超过MAX(n,m)行的结果集,理论上可以使用nxm行。

现在想象一下INNER JOIN中的许多这样的表。

这将导致结果集变得越来越大,并开始进入分配的内存区域。

这可能是临时表可能对您有所帮助的原因。

原因2:您没有在要加入表格的列上构建INDEX

原因3:您是否在WHERE子句中有函数?

答案 1 :(得分:1)

通常,您希望查询优化器以尽可能限制结果集的方式连接表。如果你有一个包含100万行的表A,包含100万行的表B和包含10行的表C,那么你首先想要从表C到A或B的内部连接,这将最多给你10条记录(假设1:1匹配)然后加入到最后一个表。如果您首先加入A到B,那么您将加入每个行的所有100万行,这将花费更长的时间。

通常,查询优化器足够好&#34;选择连接顺序,但在你的情况下它不是。我Adam Mechanic in a blog post here演示了强制加入顺序的最佳方法。它涉及在要开始连接的表上使用TOP子句。然后,查询优化器将首先从这些表中获取结果集,您可以真正限制总行数并提高查询性能。我尽可能使用这种方法。

答案 2 :(得分:0)

使用正确的索引或索引,原始查询应该非常快速地执行(如果您分页数据,则不得超过一秒)。不要使用临时表作为黑客,因为无法提出合理的查询。

答案 3 :(得分:0)

可能有些不同,但是从表面上看,您已经检查了索引和执行计划。我建议亚当·米尼克(Adam Mechanic)的有关“行目标”并使用top语句的视频,该视频的工作方式与临时表的工作方式类似。

从( 选择顶部(2000000000)t1.ReturnINT,t1.ReturnBIT,t2.ReturnINT,t3.ReturnINT,t5.ReturnINT,t1.ReturnDateTime 从t1开始 内部联接t2     开启t2.my_column_varchar = t1.my_column_varchar 内胎t3     开启t3.my_column_number = t1.my_column_number AND t2.my_column_ID = t3.my_column_ID 内胎t4     开启t4.my_column_varchar = t1.my_column_varchar 内胎t5     开启t5.my_column_int = t1.my_column_int AND t5.my_column_int = t4.my_column_int AND t2.my_column_int = t5.my_column_int 内胎t6     开启t6.my_column_int = t5.my_column_int和t6.my_column_int = t2.my_column_int 内胎t7     开启t7.my_column_int = t6.my_column_int 内胎t8     开启t8.my_column_int = t3.my_column_int和t8.my_column_datetime = t1.my_column_datetime 内胎t9     开启t9.my_column_int = t3.my_column_int和t8.my_column_datetime在t9.my_column_datetime1和t9.datetime1 + t9.my_column_datetime2之间 内胎t10     开启t10.my_column_int = t9.my_column_int和t10.my_column_int = t6.my_column_int 内连接t11     开启t11.my_column_int = t9.my_column_int和t8.my_column_datetime = t11.my_column_datetime)

我有一个类似的问题,但是在几次连接后有一个where子句,并花了10分钟的查询并将其减少到39秒。