在 SQL Server 2016 上查询系统表 EXTENDED_PROPERTIES 比 SQL Server 2008 慢得多

Querying system tables EXTENDED_PROPERTIES much slower on SQL Server 2016 than SQL Server 2008

我们有一个应用程序使用扩展属性来保存列元数据。这些列具有扩展属性以保存字段描述、选项值、屏幕上的位置等。有一个查询这些扩展属性的视图,在应用程序启动时查询一次。

最近我们从 SQL Server 2008 升级到 SQL Server 2016,问题是这个视图现在慢得多,这会在启动时冻结应用程序。

CREATE VIEW dbo.VW_FIELD_METADATA
AS
    SELECT
        CAST(UPPER(o.NAME) AS VARCHAR) AS TABLE_NAME, 
        CAST(UPPER(c.name) AS VARCHAR) AS COLUMN_NAME, 
        CONVERT(VARCHAR(250), VarLabel.Value) AS ColDescr,
        ValLabel.Name AS ValueName,
        CONVERT(VARCHAR(250), ValLabel.Value) AS ValueLabel
    FROM
        SYSOBJECTS O
    JOIN 
        SYSCOLUMNS C ON O.id = C.id 
    JOIN 
        SYS.EXTENDED_PROPERTIES VarLabel ON c.id = VarLabel.major_id  
                                         AND c.colid = VarLabel.minor_id 
                                         AND VarLabel.Name = 'VarLabel'
    LEFT JOIN 
        (SELECT MAJOR_ID, MINOR_ID, NAME, VALUE 
         FROM SYS.EXTENDED_PROPERTIES 
         WHERE Name LIKE 'ValLabel%') ValLabel ON c.id = ValLabel.major_id 
                                               AND c.colid = ValLabel.minor_id
    LEFT JOIN 
        SYS.EXTENDED_PROPERTIES Groep ON c.id = Groep.major_id 
                                      AND c.colid = Groep.minor_id 
                                      AND Groep.Name = 'Groep'
    --LEFT JOIN 
    --    SYS.EXTENDED_PROPERTIES Minimum ON c.id = Minimum.major_id AND c.colid = Minimum.minor_id AND Minimum.Name = 'Minimum'
    --LEFT JOIN 
    --    SYS.EXTENDED_PROPERTIES Maximum ON c.id = Maximum.major_id AND c.colid = Maximum.minor_id AND Maximum.Name = 'Maximum'
    --etc there are 8 more JOINS
WHERE
    (o.xtype = 'U' OR o.xtype = 'V')
GO

有很多表、列和扩展属性,所以这会产生 > 17000 行

TABLE_NAME  |COLUMN_NAME   |ColDescr            |ValueName   |ValueLabel
------------+--------------+--------------------+------------+----------
PATIENT     |PATNR         |Registration number |NULL        |NULL
PATIENT     |FIRSTNAME     |First name          |NULL        |NULL
PATIENT     |SEX           |Patient sex         |ValLabel001 |1 = Male
PATIENT     |SEX           |Patient sex         |ValLabel002 |2 = Female
etc.

在旧的 SQL Server 2008 上花费的时间不到一秒,在新的 SQL Server 2016 上花费的时间长达两分钟,这会导致应用程序超时。

顺便说一句,视图的实际查询甚至更长,大约有 8 个额外的 LEFT JOIN,但随后查询似乎完全陷入死锁并且永远不会完成,所以我在这里缩短了它以进行测试。

无论如何,我知道我们可以通过将数据库设置为较旧的兼容级别来解决此问题,因此 Properties -> Options -> Compatibility level 并将其设置为 "SQL Server 2008 (100)" 但这完全否定了服务器升级并阻止了更新的功能.

我的问题是,有没有办法在使数据库保持兼容级别 "SQL Server 2016 (130)" 的同时使此查询正常工作?与早期的 SQL 服务器版本相比,为什么查询这些系统表花费的时间要长得多?

(顺便说一句,新服务器在 "Always On availability groups" 但我不知道这是否与此问题相关)

我也在 Microsoft SQL Server forum 上问了这个问题,有人指出您可以强制使用所谓的 legacy cardinality estimator 进行查询。 所以最后添加 OPTION(USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION')) 像这样:

..
WHERE
    (o.xtype = 'U' OR o.xtype = 'V')
OPTION(USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION'));

使用此提示可显着提高此查询的性能。