sql - T-SQL Select where "IN"非常糟糕 性能影响

标签 sql sql-server t-sql

当使用以下代码时:

SELECT * INTO #StoreIdsPermision FROM (SELECT StoreId FROM dbo.FN_Inv_GetListOfStoreIdCheckPermission(15,3019)) StoreIdsPermision;

SELECT distinct

        Id,
        StoreName,
        ......,
        ......,

    from INV_Transactions
        inner join ....
        left outer join ....

    WHERE StoreId in (select Id from #StoreIdsPermision)

执行时间为 4 分钟。

当在“WHERE IN”语句中使用相同的逗号语法代码时,执行时间为3秒,为什么?以及如何解决这个问题?

SELECT distinct

        Id,
        StoreName,
        ......,
        ......,

    from INV_Transactions
        inner join ....
        left outer join ....

    WHERE StoreId in (4,7,9,15,22,........)

注意:以下语句的执行时间不到1秒,并且#StoreIdsPermision仅约140行

SELECT * INTO #StoreIdsPermision FROM (SELECT StoreId FROM dbo.FN_Inv_GetListOfStoreIdCheckPermission(15,3019)) StoreIdsPermision;

第 1 部分的实际执行计划 Actual Execution Plan

第 2 部分的实际执行计划 Actual Execution Plan

使用逗号语法时的实际执行计划 Actual Execution Plan

更新1:

来自“Epon​​yme Web”建议二号的非常好的建议,当在第一个查询中添加 SET FORCEPLAN ON 并在最后一个查询中添加 SET FORCEPLAN OFF 时,执行时间正常,会发生什么情况?

更新2:

我将所有内连接替换为左外连接,并且在没有 FORCEPLAN ON 的情况下也能正常工作

最佳答案

您已确认第一个查询的第一部分不会导致问题?

SELECT * 
INTO #StoreIdsPermision 
FROM 
    (SELECT StoreId 
     FROM dbo.FN_Inv_GetListOfStoreIdCheckPermission(15, 3019)) StoreIdsPermision;

如果上述代码不是性能问题的根源,您可以向 #StoreIdsPermision 临时表添加索引

CREATE INDEX sip1 ON #StoreIdsPermision (StoreId); 

我会尝试另外两件事(始终将创建的索引保留在临时表上)

1 - 用这个替换你的 where 子句

WHERE EXISTS (SELECT 1 from #StoreIdsPermision SIP WHERE INV_Transactions.StoreId  = SIP.StoreId)

2 - 在第二个查询开始时启用强制计划,并在最后关闭强制计划。 99.9% 的情况下,优化器都会正确或至少足够正确,但有时却不会。在您的情况下,我预计这两种方法的性能不会有如此大的差异。

关于sql - T-SQL Select where "IN"非常糟糕 性能影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54978531/

相关文章:

php - MySQL 在单个 php 脚本中使用 2 个 mysql_query() 更新 2 个表

mysql - 复制表之间除一行之外的所有记录

php - 将 PHP 当前时间戳与数据库中的时间戳进行比较

sql-server - 在 0-30 范围内设置一个值

sql-server - SQL Server 2005 - 使用前导零格式化十进制数(包括带符号的小数!)

SQL 如何使用公用表表达式和动态 SQL 对表进行 PIVOT

sql - 缺少列结果(应该很容易修复)

sql - 替换或删除字符,然后转换为十进制

mysql - 返回计数以及结果集

t-sql - 如何使用重叠的开始时间和停止时间对 15 分钟间隔内发生的事件时间求和 (SQL)(t-SQL)