我遇到了性能问题。
我创建了一个从文件中接收数据的表,我做了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)
答案 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秒。