我有一个插入,它使用条件检查 NOT IN。 NOT IN 子查询中有大约 230k 行。
INSERT INTO Validate.ItemError (ItemId, ErrorId, DateCreated)
(
SELECT ItemId, 10, GetUTCDate()
FROM Validate.Item
INNER JOIN Refresh.Company
ON Validate.Item.IMCompanyId = Refresh.Company.IMCompanyId
WHERE Refresh.Company.CompanyId = 14
AND
(
IMAccountId IS NULL OR NOT IMAccountId IN
(
SELECT RA.IMAccountId
FROM Refresh.Account RA
INNER JOIN Refresh.BalancePool BP
ON RA.BalancePoolId = BP.BalancePoolId
WHERE BP.CompanyId = 14
)
)
)
当我按原样运行此程序时,大约需要 30 多分钟(哎呀!)。 Validate.Item 表中的值数量可能从 150 行到超过 200k,因此您可以看到这可能是多么痛苦。
表中所有相关字段都有索引,并且没有一个过于分散。
我的第一个想法是分段执行此操作,并将其放入 WHILE 循环中:
DECLARE @StartId int, @EndId int, @MaxId int
SELECT @MaxId = MAX(AccountId) FROM Refresh.Account
SET @StartId = 1
SET @EndId = 1000
WHILE (@StartId < @MaxId)
BEGIN
INSERT INTO Validate.ItemError (ItemId, ErrorId, DateCreated)
(
SELECT ItemId, 10, GetUTCDate()
FROM Validate.Item
INNER JOIN Refresh.Company
ON Validate.Item.IMCompanyId = Refresh.Company.IMCompanyId
WHERE Refresh.Company.CompanyId = 14
AND
(
IMAccountId IS NULL
OR NOT IMAccountId IN
(
SELECT RA.IMAccountId
FROM Refresh.Account RA
INNER JOIN Refresh.BalancePool BP
ON RA.BalancePoolId = BP.BalancePoolId
WHERE BP.CompanyId = 14
AND RA.AccountId BETWEEN @StartId AND @EndId
)
)
)
SET @StartId = @StartId + 1000
SET @EndId = @EndId + 1000
END
这样做可以让我每次循环花费大约一分钟的时间;将其乘以 230 倍,我们得到一个更荒谬的数字。
请告诉我你们有更好的想法如何优化它。如果没有这一次查询,整个过程只需要8秒;只是 Refresh.Account 表的庞大规模让一切陷入困惑。
TIA!
瓦尔基里
最佳答案
摆脱OR
条件。
它添加了全扫描并防止优化器使用原本会使用的ANTI JOIN
。
此查询返回相同的结果:
SELECT ItemId, 10, GetUTCDate()
FROM Validate.Item
INNER JOIN
Refresh.Company
ON Validate.Item.IMCompanyId = Refresh.Company.IMCompanyId
WHERE Refresh.Company.CompanyId = 14
AND NOT EXISTS
(
SELECT RA.IMAccountId
FROM Refresh.Account RA
INNER JOIN
Refresh.BalancePool BP
ON RA.BalancePoolId = BP.BalancePoolId
WHERE BP.CompanyId = 14
AND RA.IMAccounID = Validate.Item.IMAccountId
)
关于sql-server - 使用巨大的 IN 语句帮助优化此查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1770944/