聚类索引新基数运算符灾难性估计

问题描述

最近一段时间后,我们将sql Server的兼容性级别从110(sql server 2012)更改为150(2019),

我们正在观察一个查询,它变得非常慢并且超时。该查询涉及以下2个表:

CREATE TABLE [Workflow].[Transaction](
    [TransactionId] [uniqueidentifier] NOT NULL,[StartDate] [datetimeoffset](7) NOT NULL)

CREATE TABLE [Workflow].[TransactionData](
    [Id] [bigint] IDENTITY(1,1) NOT NULL,[TransactionId] [uniqueidentifier] NOT NULL,[Date] [datetimeoffset](7) NOT NULL,[StateId] [int] NOT NULL)

每个订单交易记录都保存在[Workflow].[Transaction]的100M行中,这些行是交易通过的状态,例如“开始”,“进行中”,“成功”,“失败”保存在[Workflow].[TransactionData] 200M行中。

[Workflow]。[Transaction] .StartDate上的Clusterdindex,大多数情况下,查询是根据时间范围完成的。 TransactionId上的非聚集索引。 TransactionData在TransactionId中也有一个非集群索引,其中StateId和Date为包含列,

我们的查询想要获取每个交易的最后状态:

SELECT
        T.TransactionId,LastState.StateId,T.StartDate
    FROM Workflow.[Transaction] T
    CROSS APPLY (
        SELECT 
            TOP 1 
            StateId 
        FROM Workflow.[TransactionData] td
        WHERE td.TransactionId = t.TransactionId
        ORDER BY [Date] DESC,StateId DESC
    ) LastState
    WHERE   
            @startDate <= t.StartDate 
            AND t.StartDate < @endDate
    ORDER BY T.StartDate asc

使用兼容性级别150,并且基本上使用2014年发布的新基数运算符,由于估算非常错误,因此查询花费了很长时间,因此计划很糟糕。索引假脱机190M行。您可以看到完整的计划here

enter image description here

如果我们使用传统基数运算符,请在提示添加选择的结尾:

OPTION (USE HINT ('FORCE_LEGACY_CARDINALITY_ESTIMATION'))

我们得到了更好的估算和计划。您可以看到完整的计划here

enter image description here

看到这一点,我们检查了两个表的统计信息,它们都在1天之内更新了。

运行简单的select时,问题更加明显

 SELECT
        TransactionId
    FROM Workflow.[Transaction]
    where StartDate >= '2020-11-05 00:00:00 +02:00' and 
          StartDate < '2020-11-06 00:00:00 +02:00'

enter image description here

估计:7791,实际108855。查询计划可见here。 如果我们再次通过HINT启用传统基数运算符,则会得到更好的估计:131315(82%)。可以看到新的查询计划here

集群索引统计的要点:

                Histogram Steps
                    RANGE_HI_KEY                      RANGE_ROWS                         EQ_ROWS             disTINCT_RANGE_ROWS                  AVG_RANGE_ROWS
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    10/27/2020 2:58:32 AM +02:00                        731904.2                               1                          727784                        1.005661
   10/31/2020 12:14:20 PM +02:00                          470738                               1                          468159                        1.005508
     11/6/2020 3:40:41 PM +02:00                        805856.3                               1                          802208                        1.004547

为什么新的基数运算符会对看起来很琐碎的情况做出如此糟糕的估计?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...