1

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

最近我们从 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 上用时长达两分钟,这会导致应用程序超时。

  • SQL Server 2008 - 00:00:00 - 17371 行
  • SQL Server 2016 - 00:01:46 - 17371 行

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

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

我的问题是,有没有办法让这个查询工作,同时将数据库保持在兼容级别“SQL Server 2016 (130)”?与早期的 SQL Server 版本相比,为什么查询这些系统表的时间要长得多?

(顺便说一句,新服务器位于“始终在线可用性组”中,但我不知道这是否与此问题有关)

4

1 回答 1

0

我还在Microsoft SQL Server 论坛上问过这个问题,有人指出您可以强制使用所谓的遗留基数估计器进行查询。所以最后添加OPTION(USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION'))如下:

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

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

于 2019-10-01T08:33:12.613 回答