对在两台服务器上具有显著性能差异的查询进行故障排除
适用范围:SQL Server
本文提供了性能问题的故障排除步骤,其中查询在一台服务器上运行速度比另一台服务器上慢。
现象
假设有两台安装了 SQL Server 的服务器。 其中一个 SQL Server 实例包含另一个 SQL Server 实例中的数据库副本。 针对两台服务器上的数据库运行查询时,查询在一台服务器上运行的速度比另一个服务器慢。
以下步骤可帮助排查此问题。
步骤 1:确定这是多个查询的常见问题
使用以下两种方法之一比较两台服务器上两个或多个查询的性能:
在两台服务器上手动测试查询:
- 选择多个查询,以便对以下查询进行优先级测试:
- 一台服务器上的速度比另一台服务器上要快得多。
- 对用户/应用程序很重要。
- 经常执行或设计为按需重现问题。
- 足够长的时间捕获其上的数据(例如,而不是 5 毫秒的查询,请选择 10 秒的查询)。
- 在两台服务器上运行查询。
- 比较每个查询的两个服务器上的已用时间(持续时间)。
- 选择多个查询,以便对以下查询进行优先级测试:
使用 SQL Nexus 分析性能数据。
- 为两台服务器上的查询收集 PSSDiag/SQLdiag 或 SQL LogScout 数据。
- 使用 SQL Nexus 导入收集的数据文件,并比较两个服务器的查询。 有关详细信息,请参阅两个日志集合之间的性能比较(例如慢速和快速)。
方案 1:在两个服务器上只执行一个查询不同
如果只有一个查询以不同的方式执行,则问题更有可能特定于单个查询,而不是特定于环境。 在这种情况下,请转到 步骤 2:收集数据并确定性能问题的类型。
方案 2:在两个服务器上执行多个查询的方式不同
如果多个查询在一台服务器上运行速度比另一个服务器慢,则最可能的原因是服务器或数据环境的差异。 转到 “诊断环境差异 ”,查看两个服务器之间的比较是否有效。
步骤 2:收集数据并确定性能问题的类型
收集已用时间、CPU 时间和逻辑读取
若要在两台服务器上收集查询的运行时间和 CPU 时间,请使用最适合你的情况的以下方法之一:
对于当前正在执行的语句,请检查sys.dm_exec_requests中的total_elapsed_time和cpu_time列。 运行以下查询以获取数据:
SELECT req.session_id , req.total_elapsed_time AS duration_ms , req.cpu_time AS cpu_time_ms , req.total_elapsed_time - req.cpu_time AS wait_time , req.logical_reads , SUBSTRING (REPLACE (REPLACE (SUBSTRING (ST.text, (req.statement_start_offset/2) + 1, ((CASE statement_end_offset WHEN -1 THEN DATALENGTH(ST.text) ELSE req.statement_end_offset END - req.statement_start_offset)/2) + 1) , CHAR(10), ' '), CHAR(13), ' '), 1, 512) AS statement_text FROM sys.dm_exec_requests AS req CROSS APPLY sys.dm_exec_sql_text(req.sql_handle) AS ST ORDER BY total_elapsed_time DESC;
对于查询的过去执行,请检查sys.dm_exec_query_stats中的last_elapsed_time和last_worker_time列。 运行以下查询以获取数据:
SELECT t.text, (qs.total_elapsed_time/1000) / qs.execution_count AS avg_elapsed_time, (qs.total_worker_time/1000) / qs.execution_count AS avg_cpu_time, ((qs.total_elapsed_time/1000) / qs.execution_count ) - ((qs.total_worker_time/1000) / qs.execution_count) AS avg_wait_time, qs.total_logical_reads / qs.execution_count AS avg_logical_reads, qs.total_logical_writes / qs.execution_count AS avg_writes, (qs.total_elapsed_time/1000) AS cumulative_elapsed_time_all_executions FROM sys.dm_exec_query_stats qs CROSS apply sys.Dm_exec_sql_text (sql_handle) t WHERE t.text like '<Your Query>%' -- Replace <Your Query> with your query or the beginning part of your query. The special chars like '[','_','%','^' in the query should be escaped. ORDER BY (qs.total_elapsed_time / qs.execution_count) DESC
注意
如果
avg_wait_time
显示负值,则它是并行 查询。如果可以在 SQL Server Management Studio(SSMS)或 Azure Data Studio 中按需执行查询,请使用 SET STATISTICS TIME 和 SET STATISTICS IO
ON
运行它。ON
SET STATISTICS TIME ON SET STATISTICS IO ON <YourQuery> SET STATISTICS IO OFF SET STATISTICS TIME OFF
然后,从 消息中,你将看到 CPU 时间、已用时间和逻辑读取,如下所示:
Table 'tblTest'. Scan count 1, logical reads 3, physical reads 0, page server reads 0, read-ahead reads 0, page server read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob page server reads 0, lob read-ahead reads 0, lob page server read-ahead reads 0. SQL Server Execution Times: CPU time = 460 ms, elapsed time = 470 ms.
如果可以收集查询计划,请检查执行计划属性中的数据。
运行包含 实际执行计划的 查询。
从 执行计划中选择最左侧的运算符。
从 “属性”中 展开 QueryTimeStats 属性。
检查 运行时间 和 CpuTime。
比较查询的运行时间和 CPU 时间,以确定这两个服务器的问题类型。
类型 1:CPU 绑定(运行程序)
如果 CPU 时间接近、等于或高于已用时间,则可以将其视为 CPU 绑定查询。 例如,如果已用时间为 3000 毫秒(ms),并且 CPU 时间为 2900 毫秒,则表示大部分已用时间都花在 CPU 上。 然后,我们可以说这是一个 CPU 绑定的查询。
运行(CPU 绑定)查询的示例:
已用时间 (ms) | CPU 时间(毫秒) | 读取数(逻辑) |
---|---|---|
3200 | 3000 | 300000 |
1080 | 1000 | 20 |
逻辑读取 - 读取缓存中的数据/索引页 - 通常是 SQL Server 中 CPU 使用率的驱动因素。 在某些情况下,CPU 使用来自其他源:一个 while 循环(在 T-SQL 或其他代码(如 XProcs 或 SQL CRL 对象)中)。 表中的第二个示例演示了这种情况,其中大多数 CPU 不是来自读取。
注意
如果 CPU 时间大于持续时间,则表示执行并行查询;多个线程同时使用 CPU。 有关详细信息,请参阅 并行查询 - 运行程序或服务员。
类型 2:等待瓶颈(服务员)
如果已用时间明显大于 CPU 时间,则查询正在等待瓶颈。 已用时间包括对 CPU(CPU 时间)执行查询的时间,以及等待释放资源的时间(等待时间)。 例如,如果经过的时间为 2000 毫秒,并且 CPU 时间为 300 毫秒,则等待时间为 1700 毫秒(2000 - 300 = 1700)。 有关详细信息,请参阅 “等待类型”。
等待查询的示例:
已用时间 (ms) | CPU 时间(毫秒) | 读取数(逻辑) |
---|---|---|
2000 | 300 | 28000 |
10080 | 700 | 80000 |
并行查询 - 运行程序或服务员
并行查询可能会使用比总持续时间更多的 CPU 时间。 并行度的目标是允许多个线程同时运行查询的各个部分。 在时钟时间的 1 秒内,查询可以通过执行 8 个并行线程来使用 8 秒的 CPU 时间。 因此,根据已用时间和 CPU 时间差确定 CPU 绑定或等待查询变得困难。 但是,作为一般规则,请遵循上述两节中列出的原则。 摘要为:
- 如果已用时间远远大于 CPU 时间,请考虑它为服务员。
- 如果 CPU 时间大于已用时间,请考虑它为运行程序。
并行查询的示例:
已用时间 (ms) | CPU 时间(毫秒) | 读取数(逻辑) |
---|---|---|
1200 | 8100 | 850000 |
3080 | 12300 | 1500000 |
步骤 3:比较两台服务器中的数据、找出方案并排查问题
假设有两台名为 Server1 和 Server2 的计算机。 查询在 Server1 上运行的速度比 Server2 慢。 比较两个服务器中的时间,然后按照最符合以下部分中你情况的操作进行操作。
方案 1:Server1 上的查询使用更多的 CPU 时间,而 Server1 上的逻辑读取数比 Server2 上的逻辑读取更高
如果 Server1 上的 CPU 时间远大于 Server2,并且运行时间与两台服务器上的 CPU 时间匹配,则不会发生重大等待或瓶颈。 Server1 上的 CPU 时间增加很可能是由逻辑读取增加引起的。 逻辑读取的重大更改通常表示查询计划的差异。 例如:
服务器 | 已用时间 (ms) | CPU 时间(毫秒) | 读取数(逻辑) |
---|---|---|---|
Server1 | 3100 | 3000 | 300000 |
服务器 2 | 1100 | 1000 | 90200 |
操作:检查执行计划和环境
- 比较两台服务器上的查询的执行计划。 为此,请使用以下两种方法之一:
- 直观地比较执行计划。 有关详细信息,请参阅显示实际执行计划。
- 保存执行计划,并使用 SQL Server Management Studio 计划比较功能对其进行比较。
- 比较环境。 不同的环境可能会导致查询计划差异或 CPU 使用率的直接差异。 环境包括服务器版本、数据库或服务器配置设置、跟踪标志、CPU 计数或时钟速度以及虚拟机与物理机。 有关详细信息,请参阅诊断查询计划差异。
方案 2:查询是 Server1 而不是 Server2 上的服务员
如果两台服务器上的查询的 CPU 时间相似,但 Server1 上的已用时间远大于 Server2,则 Server1 上的查询会花费更长的时间 等待瓶颈。 例如:
服务器 | 已用时间 (ms) | CPU 时间(毫秒) | 读取数(逻辑) |
---|---|---|---|
Server1 | 4500 | 1000 | 90200 |
服务器 2 | 1100 | 1000 | 90200 |
- Server1 上的等待时间:4500 - 1000 = 3500 毫秒
- Server2 上的等待时间:1100 - 1000 = 100 毫秒
操作:检查 Server1 上的等待类型
识别并消除 Server1 上的瓶颈。 等待示例包括阻塞(锁定等待)、闩锁等待、磁盘 I/O 等待、网络等待和内存等待。 若要排查常见瓶颈问题,请继续 诊断等待或瓶颈。
方案 3:两台服务器上的查询都是服务员,但等待类型或时间不同
例如:
服务器 | 已用时间 (ms) | CPU 时间(毫秒) | 读取数(逻辑) |
---|---|---|---|
Server1 | 8000 | 1000 | 90200 |
服务器 2 | 3000 | 1000 | 90200 |
- Server1 上的等待时间:8000 - 1000 = 7000 毫秒
- Server2 上的等待时间:3000 - 1000 = 2000 毫秒
在这种情况下,两台服务器上的 CPU 时间相似,这表示查询计划可能相同。 如果两个服务器没有等待瓶颈,查询将同样执行。 因此,持续时间差异来自不同的等待时间量。 例如,查询在 Server1 上的锁上等待 7000 毫秒,而它在 Server2 上的 I/O 上等待 2000 毫秒。
操作:检查两台服务器上的等待类型
解决每个瓶颈在每个服务器上单独等待,并加快这两个服务器上的执行速度。 此问题的故障排除很费力,因为你需要消除两个服务器上的瓶颈,并使性能可比。 若要排查常见瓶颈问题,请继续 诊断等待或瓶颈。
方案 4:Server1 上的查询使用的 CPU 时间多于 Server2,但逻辑读取已关闭
例如:
服务器 | 已用时间 (ms) | CPU 时间(毫秒) | 读取数(逻辑) |
---|---|---|---|
Server1 | 3000 | 3000 | 90200 |
服务器 2 | 1000 | 1000 | 90200 |
如果数据符合以下条件:
- Server1 上的 CPU 时间比 Server2 上的 CPU 时间要大得多。
- 经过的时间与每个服务器上的 CPU 时间紧密匹配,这表示没有等待。
- 逻辑读取(通常是 CPU 时间的最高驱动程序)在两台服务器上相似。
然后,额外的 CPU 时间来自其他一些 CPU 绑定的活动。 此方案是所有方案中最罕见的情况。
原因:跟踪、UDF 和 CLR 集成
此问题可能是由以下原因引起的:
- XEvents/SQL Server 跟踪,尤其是对文本列进行筛选(数据库名称、登录名、查询文本等)。 如果在一台服务器上启用了跟踪,但另一台服务器上未启用跟踪,这可能是差异的原因。
- 用户定义函数(UDF)或其他执行 CPU 绑定操作的 T-SQL 代码。 这通常是 Server1 和 Server2 上其他条件不同的原因,例如数据大小、CPU 时钟速度或电源计划。
- SQL Server CLR 集成 或 扩展存储过程(XP) 可能会驱动 CPU,但不执行逻辑读取。 DLL 的差异可能会导致不同的 CPU 时间。
- CPU 绑定的 SQL Server 功能的差异(例如字符串操作代码)。
操作:检查跟踪和查询
检查两台服务器上的跟踪是否存在以下内容:
- 如果在 Server1 上启用了任何跟踪,但未在 Server2 上启用跟踪。
- 如果启用了任何跟踪,请禁用跟踪并在 Server1 上再次运行查询。
- 如果这次查询运行速度更快,请启用跟踪回溯,但从中删除文本筛选器(如果有)。
检查查询是否使用执行字符串操作的 UDF,或者对列表中的数据列
SELECT
执行大量处理。检查查询是否包含循环、函数递归或嵌套。
诊断环境差异
检查以下问题,并确定两个服务器之间的比较是否有效。
两个 SQL Server 实例是同一版本还是内部版本?
如果没有,则可能存在导致差异的一些修复。 运行以下查询以获取两个服务器上的版本信息:
SELECT @@VERSION
这两台服务器上的物理内存量是否相似?
如果一台服务器具有 64 GB 内存,而另一台服务器的内存为 256 GB,那将是一个重大差异。 由于有更多的内存可用于缓存数据/索引页和查询计划,可以根据硬件资源可用性以不同的方式优化查询。
这两台服务器上的 CPU 相关硬件配置是否相似? 例如:
计算机(一台计算机上的 24 个 CPU 与另一台计算机上的 96 个 CPU)之间存在差异。
电源计划 - 均衡与高性能。
虚拟机(VM)与物理(裸机)计算机。
Hyper-V 与 VMware - 配置的差异。
时钟速度差异(时钟速度较低,时钟速度高于更高的时钟速度)。 例如,2 GHz 与 3.5 GHz 可能会有所作为。 若要在服务器上获取时钟速度,请运行以下 PowerShell 命令:
Get-CimInstance Win32_Processor | Select-Object -Expand MaxClockSpeed
使用以下两种方法之一测试服务器的 CPU 速度。 如果它们不产生可比的结果,则问题不在 SQL Server 之外。 这可能是电源计划差异、CPU 减少、VM 软件问题或时钟速度差异。
在两台服务器上运行以下 PowerShell 脚本,并比较输出。
$bf = [System.DateTime]::Now for ($i = 0; $i -le 20000000; $i++) {} $af = [System.DateTime]::Now Write-Host ($af - $bf).Milliseconds " milliseconds" Write-Host ($af - $bf).Seconds " Seconds"
在两个服务器上运行以下 Transact-SQL 代码,并比较输出。
SET NOCOUNT ON DECLARE @spins INT = 0 DECLARE @start_time DATETIME = GETDATE(), @time_millisecond INT WHILE (@spins < 20000000) BEGIN SET @spins = @spins +1 END SELECT @time_millisecond = DATEDIFF(millisecond, @start_time, getdate()) SELECT @spins Spins, @time_millisecond Time_ms, @spins / @time_millisecond Spins_Per_ms
诊断等待或瓶颈
若要优化正在等待瓶颈的查询,请确定等待的时间以及瓶颈的位置(等待类型)。 确认等待类型后,请减少等待时间或完全消除等待时间。
若要计算近似等待时间,请从查询运行时间中减去 CPU 时间(工作时间)。 通常,CPU 时间是实际执行时间,查询生存期的剩余部分正在等待。
如何计算近似等待持续时间的示例:
已用时间 (ms) | CPU 时间(毫秒) | 等待时间(ms) |
---|---|---|
3200 | 3000 | 200 |
7080 | 1000 | 6080 |
确定瓶颈或等待
若要标识历史长时间等待查询(例如, >20% 的总运行时间是等待时间),请运行以下查询。 自 SQL Server 启动以来,此查询使用缓存查询计划的性能统计信息。
SELECT t.text, qs.total_elapsed_time / qs.execution_count AS avg_elapsed_time, qs.total_worker_time / qs.execution_count AS avg_cpu_time, (qs.total_elapsed_time - qs.total_worker_time) / qs.execution_count AS avg_wait_time, qs.total_logical_reads / qs.execution_count AS avg_logical_reads, qs.total_logical_writes / qs.execution_count AS avg_writes, qs.total_elapsed_time AS cumulative_elapsed_time FROM sys.dm_exec_query_stats qs CROSS apply sys.Dm_exec_sql_text (sql_handle) t WHERE (qs.total_elapsed_time - qs.total_worker_time) / qs.total_elapsed_time > 0.2 ORDER BY qs.total_elapsed_time / qs.execution_count DESC
若要识别当前执行时间超过 500 毫秒的查询,请运行以下查询:
SELECT r.session_id, r.wait_type, r.wait_time AS wait_time_ms FROM sys.dm_exec_requests r JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id WHERE wait_time > 500 AND is_user_process = 1
如果可以收集查询计划,请从 SSMS 中的执行计划属性检查 WaitStats:
- 运行包含 实际执行 计划的查询。
- 在“执行计划”选项卡中右键单击最左侧的运算符
- 选择“属性”,然后选择 WaitStats 属性。
- 检查 WaitTimeMs 和 WaitType。
如果熟悉 PSSDiag/SQLdiag 或 SQL LogScout LightPerf/GeneralPerf 方案,请考虑使用其中任一方案收集性能统计信息并识别 SQL Server 实例上的等待查询。 可以使用 SQL Nexus 导入收集的数据并分析性能数据。
帮助消除或减少等待的参考
每种等待类型的原因和解决方法各不相同。 没有一种常规方法来解析所有等待类型。 下面是排查和解决常见等待类型问题的文章:
- 了解和解决阻止问题(LCK_M_*)
- 了解并解决 Azure SQL 数据库阻塞问题
- 排查 I/O 问题导致的 SQL Server 性能缓慢问题(PAGEIOLATCH_*、WRITELOG、IO_COMPLETION、BACKUPIO)
- 解决 SQL Server 中的最后一页插入 PAGELATCH_EX 争用
- 内存授予解释和解决方案(RESOURCE_SEMAPHORE)
- 排查ASYNC_NETWORK_IO等待类型导致的慢查询问题
- 使用 AlwaysOn 可用性组排查高HADR_SYNC_COMMIT等待类型问题
- 工作原理:CMEMTHREAD 和调试它们
- 使并行度等待可操作(CXPACKET 和 CXCONSUMER)
- THREADPOOL 等待
有关许多等待类型及其指示的说明,请参阅“等待类型”中的表。
诊断查询计划差异
下面是查询计划差异的一些常见原因:
数据大小或数据值差异
是否在两台服务器上使用相同的数据库 - 使用相同的数据库备份? 与另一台服务器相比,数据是否已修改? 数据差异可能会导致不同的查询计划。 例如,将表 T1(1000 行)与表 T2(2,000,000 行)联接与联接表 T1(100 行)与表 T2(2,000,000 行)不同。 操作的类型和速度
JOIN
可能大相径庭。统计信息差异
是否已 更新一个数据库而不是另一个数据库上的统计信息 ? 统计信息是否已使用不同的采样率进行更新(例如,30% 与 100% 完全扫描)? 确保使用相同的采样率更新两端的统计信息。
数据库兼容性级别差异
检查两个服务器之间的数据库兼容性级别是否不同。 若要获取数据库兼容性级别,请运行以下查询:
SELECT name, compatibility_level FROM sys.databases WHERE name = '<YourDatabase>'
服务器版本/生成差异
两个服务器之间的 SQL Server 版本或内部版本是否不同? 例如,一台服务器 SQL Server 版本 2014 和另一个 SQL Server 版本 2016 吗? 可能存在产品更改,这可能会导致查询计划选择方式的变化。 请确保比较相同的 SQL Server 版本和版本。
SELECT ServerProperty('ProductVersion')
基数估算器 (CE) 版本差异
检查旧基数估算器是否在数据库级别激活。 有关 CE 的详细信息,请参阅基数估计 (SQL Server)。
SELECT name, value, is_value_default FROM sys.database_scoped_configurations WHERE name = 'LEGACY_CARDINALITY_ESTIMATION'
已启用/禁用优化器修补程序
如果在一台服务器上启用了查询优化器修补程序,但在另一台服务器上禁用,则可以生成不同的查询计划。 有关详细信息,请参阅 SQL Server 查询优化器修补程序跟踪标志 4199 服务模型。
若要获取查询优化器修补程序的状态,请运行以下查询:
-- Check at server level for TF 4199 DBCC TRACESTATUS (-1) -- Check at database level USE <YourDatabase> SELECT name, value, is_value_default FROM sys.database_scoped_configurations WHERE name = 'QUERY_OPTIMIZER_HOTFIXES'
跟踪标志差异
某些跟踪标志会影响查询计划选择。 检查是否在一台服务器上启用了跟踪标志,另一台服务器上是否启用了跟踪标志。 在两台服务器上运行以下查询并比较结果:
-- Check at server level for trace flags DBCC TRACESTATUS (-1)
硬件差异(CPU 计数、内存大小)
若要获取硬件信息,请运行以下查询:
SELECT cpu_count, physical_memory_kb/1024/1024 PhysicalMemory_GB FROM sys.dm_os_sys_info
根据查询优化器的硬件差异
OptimizerHardwareDependentProperties
检查查询计划,看看硬件差异是否被认为对不同的计划很重要。WITH xmlnamespaces(DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan') SELECT txt.text, t.OptHardw.value('@EstimatedAvailableMemoryGrant', 'INT') AS EstimatedAvailableMemoryGrant , t.OptHardw.value('@EstimatedPagesCached', 'INT') AS EstimatedPagesCached, t.OptHardw.value('@EstimatedAvailableDegreeOfParallelism', 'INT') AS EstimatedAvailDegreeOfParallelism, t.OptHardw.value('@MaxCompileMemory', 'INT') AS MaxCompileMemory FROM sys.dm_exec_cached_plans AS cp CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) AS qp CROSS APPLY qp.query_plan.nodes('//OptimizerHardwareDependentProperties') AS t(OptHardw) CROSS APPLY sys.dm_exec_sql_text (CP.plan_handle) txt WHERE text Like '%<Part of Your Query>%'
优化器超时
是否存在 优化器超时 问题? 如果正在执行的查询过于复杂,查询优化器可以停止评估计划选项。 停止时,它会选取当时成本最低的计划。 这可能会导致一台服务器与另一台服务器上的任意计划选择。
SET 选项
某些 SET 选项会影响计划,例如 SET ARITHABORT。 有关详细信息,请参阅 SET 选项。
查询提示差异
一个查询是否使用 查询提示,另一个查询不使用查询提示 ? 手动检查查询文本以建立查询提示的存在。
参数敏感计划(参数探查问题)
是否使用完全相同的参数值测试查询? 如果没有,则可以从那里开始。 计划之前是否已基于不同的参数值在一台服务器上编译? 使用 RECOMPILE 查询提示测试这两个查询,以确保不会重复使用计划。 有关详细信息,请参阅调查并解决参数敏感问题。
不同的数据库选项/范围配置设置
这两个服务器上是否使用相同的数据库选项或作用域配置设置? 某些数据库选项可能会影响计划选择。 例如,数据库兼容性、旧 CE 与默认 CE 以及参数探查。 从一台服务器运行以下查询,以比较两台服务器上使用的数据库选项:
-- On Server1 add a linked server to Server2 EXEC master.dbo.sp_addlinkedserver @server = N'Server2', @srvproduct=N'SQL Server' -- Run a join between the two servers to compare settings side by side SELECT s1.name AS srv1_config_name, s2.name AS srv2_config_name, s1.value_in_use AS srv1_value_in_use, s2.value_in_use AS srv2_value_in_use, Variance = CASE WHEN ISNULL(s1.value_in_use, '##') != ISNULL(s2.value_in_use,'##') THEN 'Different' ELSE '' END FROM sys.configurations s1 FULL OUTER JOIN [server2].master.sys.configurations s2 ON s1.name = s2.name SELECT s1.name AS srv1_config_name, s2.name AS srv2_config_name, s1.value srv1_value_in_use, s2.value srv2_value_in_use, s1.is_value_default, s2.is_value_default, Variance = CASE WHEN ISNULL(s1.value, '##') != ISNULL(s2.value, '##') THEN 'Different' ELSE '' END FROM sys.database_scoped_configurations s1 FULL OUTER JOIN [server2].master.sys.database_scoped_configurations s2 ON s1.name = s2.name
计划指南
是否有任何计划指南用于一台服务器上的查询,但不用于另一个服务器上的查询? 运行以下查询来建立差异:
SELECT * FROM sys.plan_guides