由于一个简单的 IN 语句,大量的全表扫描(大约 600 次)

Posted

技术标签:

【中文标题】由于一个简单的 IN 语句,大量的全表扫描(大约 600 次)【英文标题】:Lot of full table scans (around 600) because of a simple IN statement 【发布时间】:2015-06-23 11:22:26 【问题描述】:

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

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

当我没有 where 条件时,查询速度足够快(大约 5 秒)以获得超过 5 k 的结果。

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

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

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

见下面的三个查询。 你能描述一下为什么会发生这种情况以及如何防止这种情况发生吗?

/* 大约需要 5 秒 6k 结果*/ WITH First_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5) 作为 ( …… ) WITH Second_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5) 作为 ( …… ) 选择 * FROM First_CTE AS t1 左连接 Second_CTE AS t2 ON t1.COLUMN2 = t2.COLUMN2 /* 大约需要 4 分钟 600 结果*/ WITH First_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5) 作为 ( …… ) WITH Second_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5) 作为 ( …… ) 选择 * FROM First_CTE AS t1 左连接 Second_CTE AS t2 ON t1.COLUMN2 = t2.COLUMN2 WHERE t2.SomeColumn IN ( 22,23,24) -- 2 或更多值 /* 大约需要 1 秒 600 结果 */ WITH First_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5) 作为 ( …… ) WITH Second_CTE(ID,COLUMN2,COLUMN3,COLUMN4,COLUMN5) 作为 ( …… ) 选择 * 从 ( 选择 * FROM First_CTE AS t1 左连接 Second_CTE AS t2 ON t1.COLUMN2 = t2.COLUMN2 )X WHERE x.SomeColumn IN ( 22,23,24) -- 2 或更多值

【问题讨论】:

查询计划显示什么?如果将WHERE 条件向上移动到合适的 CTE 一半会发生什么? 【参考方案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

【讨论】:

【参考方案2】:

你可以试试这个,看看它是否有所作为?

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

【讨论】:

这是执行计划为 4 分钟的查询。我看不出您的查询与我的第二个示例之间的区别。我错过了什么吗? 我将条件移至JOIN 并删除了WHERE 子句 啊我现在看到了,但是结果不一样,你知道的,因为左连接。 @LóriNóda 结果不同,因为现在它实际上是左连接。 where 中的那些条件将其变成了常规连接。

以上是关于由于一个简单的 IN 语句,大量的全表扫描(大约 600 次)的主要内容,如果未能解决你的问题,请参考以下文章

Mongodb全表扫描分析

Mongodb全表扫描分析

Oracle SQL优化必要的全表扫描思路分析

条件查询之or和union

mysql 优化-数据类型不匹配导致的全表扫描

MySQL--07 explain用法