sql-server - 使用巨大的 IN 语句帮助优化此查询

标签 sql-server optimization

我有一个插入,它使用条件检查 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/

相关文章:

sql - 自动从 MS Excel 导出到 MS SQL Server

.net - TransactionScope/SqlTransaction 超时扩展

algorithm - 任何更快的算法来计算除数

c# - CommandBehavior.SequentialAccess 是否有任何性能提升?

sql-server - 无法打开新数据库 'DB Name'。创建数据库被中止(SQL Server,错误 : 948)

sql - 使用 SQL 中另一个表中的列更新表

optimization - 在使用许多 SWIG 生成的模块时避免重复的 SWIG 样板

c++ - 程序员的错误或 gcc-5.1.0 的错误?

php - 我应该如何重构我的代码(PHP 和 MySQL)以更有效地使用主/从数据库配置?

linux - 如何在 linux 上从 php 运行 imageoptim?