Table 当过滤器放置在不同 table 上时,扫描非常高 "actual rows"

Table Scan very high "actual rows" when filter placed on different table

我有一个查询,但我没有写,需要 2.5 分钟才能 运行。我试图在无法修改基础 table 的情况下对其进行优化,即无法添加新索引。

在我的优化故障排除过程中,我注释掉了一个过滤器,突然我的查询 运行 在 0.5 秒内完成。我搞砸了那个过滤器的格式和放置,如果它在那里,查询需要 2.5 分钟,没有它 0.5 秒。最大的问题是过滤器不在 table 上 table-扫描(超过 300k 条记录),它在 table 上有 300 条记录。

0:0:0.5 与 0:2:30 的 "Actual Execution Plan" 完全相同,直到所有步骤的确切百分比成本:

Execution Plan

唯一的区别是,在 table 扫描的 table 中,2.5 分钟查询的 "Actual Number of Rows" 显示 370 万行。 table 只有 30 万行。其中 .5 秒查询显示实际行数为 2,063。过滤器实际上被放置在只有 300 行的 FS_EDIPartner table 上。

使用过滤器我得到了正确的 51 条记录,但 return 需要 2.5 分钟。没有过滤器我得到重复,所以我得到 2,796 行,只需要半秒到 return.

我不明白为什么将过滤器添加到具有 300 行和正确索引的 table 会导致不同 table 的 Table 扫描具有如此显着的差异实际行数。在进行连接之前,我什至将 "Table scan" table 作为子查询将其记录从 300k 过滤到 17k。这是当前状态下的实际查询,抱歉 table 没有多大意义,我无法在测试数据中重现此行为。

SELECT dbo.FS_ARInvoiceHeader.CustomerID
    , dbo.FS_EDIPartner.PartnerID
    , dbo.FS_ARInvoiceHeader.InvoiceNumber
    , dbo.FS_ARInvoiceHeader.InvoiceDate
    , dbo.FS_ARInvoiceHeader.InvoiceType
    , dbo.FS_ARInvoiceHeader.CONumber
    , dbo.FS_EDIPartner.InternalTransactionSetCode
    , docs.DocumentName
    , dbo.FS_ARInvoiceHeader.InvoiceStatus
FROM  dbo.FS_ARInvoiceHeader 
    INNER JOIN dbo.FS_EDIPartner ON dbo.FS_ARInvoiceHeader.CustomerID = dbo.FS_EDIPartner.CustomerID
    LEFT JOIN (Select DocumentName
                FROM GentranDatabase.dbo.ZNW_Documents
                WHERE DATEADD(SECOND,TimeCreated,'1970-1-1') > '2016-06-01'
                    AND TransactionSetID = '810') docs on  dbo.FS_ARInvoiceHeader.InvoiceNumber = docs.DocumentName COLLATE Latin1_General_BIN
WHERE docs.DocumentName IS NULL
    AND dbo.FS_ARInvoiceHeader.InvoiceType = 'I'
    AND dbo.FS_ARInvoiceHeader.InvoiceStatus <> 'Y'
    --AND (dbo.FS_EDIPartner.InternalTransactionSetCode = '810') 
    AND (NOT (dbo.FS_ARInvoiceHeader.CONumber LIKE 'CB%')) 
    AND (NOT (dbo.FS_ARInvoiceHeader.CONumber LIKE 'DM%')) 
    AND InvoiceDate > '2016-06-01'

Where 语句中被注释掉的行是罪魁祸首,取消注释会导致 2.5 分钟 运行。

可能是 table 统计数据出了问题。其中包括 table 的记录数,用于选择最佳查询计划。再次尝试 运行 和 运行 查询:

EXEC sp_updatestats

使用@jeremy 的评论作为指导指出实际行数不是我的问题,而是执行次数,我发现哈希匹配是 0.5 秒,嵌套循环是 2.5 分钟.尝试使用 Left HASH Join 强制哈希匹配是不一致的,具体取决于其他过滤器的设置,更改日期有时需要 0.5 秒到 30 秒。所以强制哈希(无论如何都非常不鼓励)不是一个好的解决方案。最后,我求助于将性能不佳的视图移动到存储过程,并将与性能不佳相关的两个 table 拆分为 Table 变量,然后加入这些 table 变量。这导致了获得结果的最一致的良好表现。平均 SP returns 不到 1 秒,这比它开始时的 2.5 分钟要好得多。

@Jeremy 获得了荣誉,但由于他不是答案,我想我会记录实际所做的事情,以防其他人后来偶然发现。