如何提高 SQL 服务器中一个数据库同步而另一个数据库不同步的多数据库查询的性能

How to improve performance of multi-database queries in SQL Server where one database is synchronized and the other is not

我有两个数据库。一个我称为 a 的是只读同步数据库,它是可用性组的一部分,另一个是普通的 ol 数据库,我将在与同步数据库相同的服务器上调用 b

我需要在 b 中编写从 a 读取的视图,但它们在此环境中的性能很差。

例如,我可能有:

create view dbo.v1    --> in b
as
    select
        t1.col_a,
        t2.col_b
    from
        a.dbo.Table1 t1
    left outer join
        a.dbo.Table2 t2 on t1.t2_id = t2.Id

我们无法将工件添加到数据库 a...例如视图、函数等...但我们可以自由地从中读取。 OpenQuery 将不可用,因为我们不是在谈论链接服务器...ab 在同一台服务器上。

鉴于以上情况,我可以在数据库 ab.

的视图中执行 select 语句

例如:

use a;

select
    t1.col_a,
    t2.col_b
from
    a.dbo.Table1 t1
left outer join
    a.dbo.Table2 t2 on t1.t2_id = t2.Id

...对...

use b;

select
    t1.col_a,
    t2.col_b
from
    a.dbo.Table1 t1
left outer join
    a.dbo.Table2 t2 on t1.t2_id = t2.Id

在像这个例子这样的超级简单的例子中,速度上的差异并不是太糟糕......但是随着查询变得复杂,第一个运行时间几乎为 0,而第二个等待 - 看似 - 永远并最终运行...在几分钟或更短的时间内。

是否有我可能会查看的配置错误?是否有一些神奇的查询命中可能会有所帮助?服务器是Windows Server 2012 R2,数据库版本是SQL Server 2016 Enterprise。

Dan 将我的 ab .sqlplan 文件发布到 PasteThePlan (a.sqlplan and b.sqlplan)。谢谢丹!

我在 b 计划中注意到的一点是它建议在其中一个表中缺少索引(影响为 91)...而 a 计划(运行速度很快)没有找到任何建议

我将你的查询计划上传到 PasteThePlan 并添加了指向你问题的链接。

两个计划之间的第一个明显区别是基数估计版本:

计划一:

<StmtSimple ... CardinalityEstimationModelVersion="70"

方案b:

<StmtSimple ... CardinalityEstimationModelVersion="130"

SQL 服务器根据上下文数据库的基数估计器版本优化查询。由于上下文数据库的 CE 版本不同,您会针对同一查询获得不同的计划。 CE 版本与数据库兼容级别相关联,除非被数据库范围的配置或查询提示覆盖。

遗留基数估计器(在 SQL 2012 和更早的版本中使用)可以为某些查询提供更好的计划。根据您的总体工作负载,您可以选择使用带有目标查询提示的旧版 CE 或用于所有数据库查询。

查询提示示例:

use b;

select
    t1.col_a,
    t2.col_b
from
    a.dbo.Table1 t1
left outer join
    a.dbo.Table2 t2 on t1.t2_id = t2.Id
OPTION(USE HINT ('FORCE_LEGACY_CARDINALITY_ESTIMATION'));

数据库范围的配置示例:

use b;

ALTER DATABASE SCOPED CONFIGURATION SET LEGACY_CARDINALITY_ESTIMATION = ON;

如果这是唯一有问题的查询,查询提示可能是更好的选择。但是,我通常建议首先对查询和索引调优进行尽职调查(注意较新的 CE 计划中缺少的索引建议)。

我要补充一点,较新的 CE 版本为某些查询引入性能回归而使其他查询受益的情况并不少见。根据我的经验,已经需要 query/index 调优的查询最容易回归。将工作负载性能测试和 CE 分析作为 SQL 升级计划的一部分是一个很好的做法。