带有“not in”的 SQL 查询非常慢
Posted
技术标签:
【中文标题】带有“not in”的 SQL 查询非常慢【英文标题】:SQL query with "not in" is very slow 【发布时间】:2019-09-09 05:25:00 【问题描述】:我有以下非常慢的 SQL 查询。如何以不同的方式编写脚本?
select
pws_name
from
pws_asset ass
join
Account acc on acc.AccountId = ass.pws_AccountId
where
acc.AccountNumber in ('188012', '172146', '214727', '13636', '201194', '280294', '34328')
and ass.pws_name not in ('1018684', '1018784', '1019584', '1019784', '1019884', '1070838', '1277139', '1277339'.........)
【问题讨论】:
尝试提高查询性能时要做的第一件事是查看执行计划。请edit您的问题与执行计划的链接(您可以使用 Brent Ozar 的paste the plan。 添加EXPLAIN
输出
NOT
子句中实际有多少个值?
有一些不同的问题。首先你应该把索引放到AccountNumber
和pws_name
。其次,您应该查看 AccountNumber
和 pws_name
列类型。如果列类型与in
语句中的给定值类型不同,则应使用相同类型
"超过 5000 条记录" ...您实际上是在执行 5000 条 OR 语句.. 尝试将数据放入临时表中(并尝试对其进行索引)并加入它。跨度>
【参考方案1】:
请按照以下步骤操作,这将有助于提高查询性能。
第 1 步:声明两个变量
DECLARE @AccNumList VARCHAR(4000)
DECLARE @PwsNameList VARCHAR(4000)
SET @AccNumList = '188012,172146,214727,13636,201194,280294,34328'
SET @PwsNameList = '1018684,1018784,1019584,1019784,1019884,1070838,1277139,1277339'
第 2 步:创建两个不同的临时表。 1 代表帐号
Create table #tblAcNum(AccountNumber VARCHAR(50))
pws_name 不需要 2
Create table #tblPwsNameNotNeeded(pws_name VARCHAR(50))
第三步:在上面的两个表中添加记录,分别用于IN和NOT IN。 请查看此Split csv string using XML in SQL Server 以供参考。
INSERT INTO #tblAcNum(AccountNumber)
SELECT
l.value('.','VARCHAR(50)') AcNum
FROM
(
SELECT CAST('<a>' + REPLACE(@AccNumList,',','</a><a>') + '</a>' AS XML) AcNumXML
) x
CROSS APPLY x.AcNumXML.nodes('a') Split(l)
INSERT INTO #tblPwsNameNotNeeded(pws_name)
SELECT
l.value('.','VARCHAR(50)') pws_name
FROM
(
SELECT CAST('<a>' + REPLACE(@PwsNameList,',','</a><a>') + '</a>' AS XML) PwsNameXML
) x
CROSS APPLY x.PwsNameXML.nodes('a') Split(l)
第 3 步:INNER JOIN #tblAcNum table with account table with accountnumber column
第 4 步:对不需要的 pws_name 使用 NOT EXISTS() 函数,如下所示
WHERE NOT EXISTS
(
SELECT 1
FROM #tblPwsNameNotNeeded pn
Where pn.pws_name = ass.pws_name
)
第 5 步:在选择查询后删除临时表。
DROP TABLE tblAcNum;
DROP TABLE #tblPwsNameNotNeeded;
请检查以下查询。
DECLARE @AccNumList VARCHAR(4000)
DECLARE @PwsNameList VARCHAR(4000)
SET @AccNumList = '188012,172146,214727,13636,201194,280294,34328'
SET @PwsNameList = '1018684,1018784,1019584,1019784,1019884,1070838,1277139,1277339'
Create table #tblAcNum(AccountNumber VARCHAR(50))
Create table #tblPwsNameNotNeeded(pws_name VARCHAR(50))
INSERT INTO #tblAcNum(AccountNumber)
SELECT
l.value('.','VARCHAR(50)') AcNum
FROM
(
SELECT CAST('<a>' + REPLACE(@AccNumList,',','</a><a>') + '</a>' AS XML) AcNumXML
) x
CROSS APPLY x.AcNumXML.nodes('a') Split(l)
INSERT INTO #tblPwsNameNotNeeded(pws_name)
SELECT
l.value('.','VARCHAR(50)') pws_name
FROM
(
SELECT CAST('<a>' + REPLACE(@PwsNameList,',','</a><a>') + '</a>' AS XML) PwsNameXML
) x
CROSS APPLY x.PwsNameXML.nodes('a') Split(l)
select
ass.pws_name
from pws_asset ass
join Account acc on acc.AccountId = ass.pws_AccountId
INNER JOIN #tblAcNum an ON an.AccountNumber = acc.AccountNumber
WHERE NOT EXISTS
(
SELECT 1
FROM #tblPwsNameNotNeeded pn
Where pn.pws_name = ass.pws_name
)
DROP TABLE tblAcNum;
DROP TABLE #tblPwsNameNotNeeded;
【讨论】:
【参考方案2】:试试这个:
; with cte_excludepws as
(select AccountId from pws_asset where pws_name not in ('1018684', '1018784', '1019584', '1019784', '1019884', '1070838', '1277139', '1277339'.........))
select
pws_name
from
pws_asset ass
join
Account acc on acc.AccountId = ass.pws_AccountId
where ass.AccountId not in (select AccountId from cte_excludepws)
and acc.AccountNumber in ('188012', '172146', '214727', '13636', '201194', '280294', '34328')
如果可以的话,也可以选择将 AccountID 放入临时表而不是 cte 并在其上创建索引。
【讨论】:
【参考方案3】:首先,请确保帐户数字 是真正的字符串。如果它们是数字,请去掉单引号!
那么,对于这个查询
select a.pws_name
from pws_asset a join
Account ac
on ac.AccountId = a.pws_AccountId
where ac.AccountNumber in ('188012', '172146', '214727', '13636', '201194', '280294', '34328') and
a.pws_name not in ('1018684', '1018784', '1019584', '1019784', '1019884', '1070838', '1277139', '1277339'.........);
我会推荐以下索引:account(accountNumber, AccountId)
和 pws_asset(pws_AccountId, pws_name)
。
【讨论】:
以上是关于带有“not in”的 SQL 查询非常慢的主要内容,如果未能解决你的问题,请参考以下文章
MySQL:在 WHERE 子句中带有 NOT IN 的从属子查询非常慢