由于简单的IN语句,很多全表扫描(大约600)

时间:2015-06-23 11:22:26

标签: sql-server tsql common-table-expression query-performance

我的查询中有2个CTE。在查询结束时,我只需加入它们并将结果写入页面。

在页面上我有过滤器选项,所以当我有过滤器时,我必须在查询的末尾放置一个简单的IN语句。

当我没有where条件时,查询足够快(约5秒),结果超过5 k。

但是当我有条件时,查询需要大约3-4分钟,这很奇怪。

所以我在SQL MS中对它进行了检查,并检查了实际的执行计划。我意识到,如果没有where条件,我只有一个全表扫描,但是结果数量的where条件。

之后我简单地将查询放入内联表()x中,并使用where之外的where条件,结果大约为1秒。

见下面的三个查询。 你能描述一下为什么会发生这种情况吗?我怎样才能防止这种情况发生?

/* Takes about 5 second 6k result*/

WITH First_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
)
WITH Second_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
)
SELECT *
FROM First_CTE AS t1
LEFT JOIN Second_CTE AS t2 ON t1.COLUMN2 = t2.COLUMN2

/* Takes about 4 minutes 600 result*/

WITH First_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
)
WITH Second_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
)
SELECT *
FROM First_CTE AS t1
LEFT JOIN Second_CTE AS t2 ON t1.COLUMN2 = t2.COLUMN2
WHERE t2.SomeColumn IN ( 22,23,24) -- 2 or more value

/* Takes about 1 second 600 result */

WITH First_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
)
WITH Second_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
)
SELECT * FROM (
    SELECT *
    FROM First_CTE AS t1
    LEFT JOIN Second_CTE AS t2 ON t1.COLUMN2 = t2.COLUMN2
)x 
WHERE x.SomeColumn IN ( 22,23,24) -- 2 or more value

2 个答案:

答案 0 :(得分:1)

CTE只是语法(它没有实现)
很确定缓慢的IN创建了一个循环,其中CTE被多次评估

在最后一次运行1秒内最像每个CTE被评估一次,然后将where应用于结果

你知道t2.SomeColumn IN(22,23,24)否定了左边 你也可以使用一个连接

试试这个

SELECT *
FROM First_CTE AS t1
JOIN Second_CTE AS t2 
ON t1.COLUMN2 = t2.COLUMN2
AND t2.SomeColumn IN ( 22,23,24) -- 2 or more value

更好的是将t2.SomeColumn IN(22,23,24)移动到CTE中,为查询优化器提供更少的机会来获取愚蠢

WITH First_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
)
WITH Second_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
    WHERE SomeColumn IN ( 22,23,24)
)
SELECT *
FROM First_CTE  AS t1
JOIN Second_CTE AS t2 
ON t1.COLUMN2 = t2.COLUMN2

答案 1 :(得分:0)

你可以尝试一下,看看它是否有所作为?

WITH First_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
)
WITH Second_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5)
AS
(
    ....
)
SELECT *
FROM First_CTE AS t1
LEFT JOIN Second_CTE AS t2 ON t1.COLUMN2 = t2.COLUMN2
AND t2.SomeColumn IN ( 22,23,24) -- 2 or more value