跨链接服务器查询视图时出现的性能问题

适用范围:SQL Server

现象

对链接服务器上的视图执行查询所需的时间比直接对链接服务器上的基表执行同一查询所需的时间要长。

原因

对视图执行查询和基表会导致不同的行为,因为数据 基数估计用于计算返回的预期行数。 查询视图的数字设置为常量值 10,000,而查询基表的数字派生自 统计信息

链接服务器查询的基数估计

Microsoft OLE DB 提供程序 (SQLOLEDB) (不再维护)或 Microsoft® OLE DB Driver 18 for SQL Server® (MSOLEDBSQL)都支持基表上的分发统计信息。 SQL Server 可以像任何常规查询一样,通过链接服务器利用统计信息和直方图。 例如,如果创建一个名为 LS1 的链接服务器,该服务器具有AdventureWorks2019Sales.SalesOrderDetail表的数据库,则以下查询可以利用统计直方图:

SELECT * FROM LS1.AdventureWorks2019.Sales.SalesOrderDetail;
SELECT * FROM LS1.AdventureWorks2019.Sales.SalesOrderDetail WHERE SalesOrderID=43659;

以下图形查询计划显示每个远程查询返回的估计行数。

链接服务器中表查询的屏幕截图。

链接服务器查询的视图的基数估计

针对视图的链接服务器查询不使用基于统计信息的基数估计。 视图的基数估计值为 10,000。 以下测试说明了这一点:

  1. 创建从链接服务器 LS1 的数据库引用Sales.SalesOrderDetailAdventureWorks2019的视图dbo.View1

    USE AdventureWorks2019;
    GO
    CREATE VIEW [dbo].[view1]
    AS
    SELECT * FROM Sales.SalesOrderDetail;
    
  2. 远程查询视图。

    SELECT * FROM LS1.AdventureWorks2019.dbo.view1;
    
  3. 查询的基数估计显示完全相同 的 10,000 行。

    链接服务器中视图的查询的屏幕截图。

链接服务器使用 WHERE 子句查询的视图的基数估计

如果对链接服务器上的视图执行包含 WHERE 子句的查询,则对视图的基数估计也是常量值。 但是,该值因数据库的兼容级别而异。

注意

基数估计值不会受到定义视图的数据库兼容性级别的影响。

  • 对于数据库兼容级别为 120 或更高版本(新版基数估算器),基数估计为 100。
  • 对于数据库兼容性级别为 110 或更低(旧基数估算器),基数估计为 1,000。

有关示例,请参阅以下查询:

SELECT * FROM LS1.AdventureWorks2019.dbo.view1
WHERE SalesOrderID=43659 
    OPTION (USE HINT ('FORCE_DEFAULT_CARDINALITY_ESTIMATION'));
GO
SELECT * FROM LS1.AdventureWorks2019.dbo.view1 
WHERE SalesOrderID=43659
OPTION (USE HINT ('FORCE_LEGACY_CARDINALITY_ESTIMATION'));

有关示例,请参阅查询的以下基数估计。

链接服务器中查看 CE 的查询的屏幕截图。

解决方法

在大多数情况下,不需要执行任何操作,因为从链接服务器查询时,大多数应用程序工作负荷不会受到视图基数估计的影响。 如果工作负荷受到影响,请使用以下方法之一:

  • 将视图更新并更改为 索引视图。 索引视图至少有一个索引具有相应的统计信息。 请参阅以下查询来创建和查询索引视图。

    注意

    此方法将公开表示基础数据的实际统计信息。

    --Set the options to support indexed views.
    SET NUMERIC_ROUNDABORT OFF;
    SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT,
       QUOTED_IDENTIFIER, ANSI_NULLS ON;
    GO
    IF OBJECT_ID ('Sales.vOrderDetails1', 'view') IS NOT NULL
       DROP VIEW Sales.vOrderDetails1;
    GO
    --Create view with schemabinding
    CREATE VIEW Sales.vOrderDetails1
       WITH SCHEMABINDING
       AS  
          SELECT SalesOrderID, 
           SalesOrderDetailID, 
           CarrierTrackingNumber, 
           OrderQty, 
           ProductID,
           UnitPrice,
           UnitPriceDiscount,
           LineTotal,
           ModifiedDate
          FROM Sales.SalesOrderDetail
    GO
    --Create an index on the view
    CREATE UNIQUE CLUSTERED INDEX IDX_V1
       ON Sales.vOrderDetails1 (SalesOrderID, ProductID);
    --Select from the materialized view
    SELECT * FROM LS1.adventureworks2019.Sales.vOrderDetails1;
    

    有关示例,请参阅查询的以下基数估计。

    链接服务器中索引视图的查询的屏幕截图。

  • 如果使用子句执行查询 WHERE ,则可以使用 Query Hint OPTIONUSE HINT ('FORCE_LEGACY_CARDINALITY_ESTIMATION')) 增加基数估计。 在某些情况下,此方法可能会有所帮助,尤其是在与大型表联接时。

    注意

    此方法适用于视图公开许多行的情况。

  • 如果适用,请直接对基表执行查询,而不是链接服务器上的视图。

另请参阅