[敬礼]
(检查一个)
[ ] Well trained professional, [ ] Casual reader, [ ] Hapless wanderer,
Run Code Online (Sandbox Code Playgroud)
我有一个(检查所有适用的)
[ ] query [ ] stored procedure [ ] database thing maybe
Run Code Online (Sandbox Code Playgroud)
运行良好(如果适用)
[ ] yesterday [ ] in recent memory [ ] at some point
Run Code Online (Sandbox Code Playgroud)
但现在突然变慢了。
我已经检查过以确保它没有被阻止,并且它不是某些长时间运行的维护任务、报告或其他带外进程的受害者。
有什么问题,我应该怎么做,我可以提供哪些信息来获得帮助?
[*Insert appropriate closing remarks*]
Run Code Online (Sandbox Code Playgroud) performance sql-server execution-plan parameter-sniffing query-performance
查看运行缓慢的查询的执行计划,我注意到有些节点是索引查找,有些是索引扫描。
索引查找和索引扫描有什么区别?
哪个表现更好?
SQL 如何选择一个?
我意识到这是 3 个问题,但我认为回答第一个会解释其他问题。
为什么这个简单的查询被授予如此多的内存?
-- Demo table
CREATE TABLE dbo.Test
(
TID integer IDENTITY NOT NULL,
FilterMe integer NOT NULL,
SortMe integer NOT NULL,
Unused nvarchar(max) NULL,
CONSTRAINT PK_dbo_Test_TID
PRIMARY KEY CLUSTERED (TID)
);
GO
-- 100,000 example rows
INSERT dbo.Test WITH (TABLOCKX)
(FilterMe, SortMe)
SELECT TOP (100 * 1000)
CHECKSUM(NEWID()) % 1000,
CHECKSUM(NEWID())
FROM sys.all_columns AS AC1
CROSS JOIN sys.all_columns AS AC2;
GO
-- Query
SELECT
T.TID,
T.FilterMe,
T.SortMe,
T.Unused
FROM dbo.Test AS T
WHERE
T.FilterMe = 567
ORDER BY
T.SortMe;
Run Code Online (Sandbox Code Playgroud)
对于估计 …
我开始学习执行计划,并且对哈希匹配的工作原理以及为什么在简单连接中使用它感到困惑:
select Posts.Title, Users.DisplayName
From Posts JOIN Users on
Posts.OwnerUserId = Users.Id
OPTION (MAXDOP 1)
Run Code Online (Sandbox Code Playgroud)

据我了解,顶部索引扫描的结果变为可散列的,底部索引聚集扫描中的每一行都被查找。我至少在某种程度上了解哈希表是如何工作的,但我对在这样的示例中究竟哪些值进行了哈希处理感到困惑。
我认为它们之间的公共字段,即 id 被散列是有意义的——但如果是这种情况,为什么要散列一个数字?
所以今天早上我们有一个长时间运行的 proc 导致问题(30 秒 + 运行时间)。我们决定检查参数嗅探是否是罪魁祸首。因此,我们重写了 proc 并将传入的参数设置为变量,以阻止参数嗅探。一种尝试过的/真实的方法。Bam,查询时间得到改善(不到 1 秒)。在查看查询计划时,在原始未使用的索引中发现了改进。
为了验证我们没有得到误报,我们对原始 proc 进行了 dbcc freeproccache 并重新运行以查看改进的结果是否相同。但是,令我们惊讶的是,原来的 proc 仍然运行缓慢。我们再次尝试使用 WITH RECOMPILE,但仍然很慢(我们尝试在对 proc 的调用以及在 proc 内部进行重新编译)。我们甚至重新启动了服务器(显然是开发箱)。
所以,我的问题是……当我们在空计划缓存上得到相同的慢查询时,参数嗅探怎么会受到指责……不应该有任何参数嗅探???
我们是否会受到与计划缓存无关的表统计信息的影响。如果是这样,为什么将传入参数设置为变量会有所帮助??
在进一步的测试中,我们还发现,将在PROC的内部的OPTION(OPTIMIZE未知)DID得到预期的改进计划。
所以,你们中的一些人比我更聪明,你能提供一些关于幕后发生了什么来产生这种结果的线索吗?
另一方面,慢计划也有理由提前中止,GoodEnoughPlanFound而快计划在实际计划中没有提前中止原因。
总之
更新:
在此处查看慢速执行计划:https : //www.dropbox.com/s/cmx2lrsea8q8mr6/plan_slow.xml
在此处查看快速执行计划:https : //www.dropbox.com/s/b28x6a01w7dxsed/plan_fast.xml
注意:出于安全原因,表、架构、对象名称已更改。
SELECT CAST (
REPLACE (
REPLACE (
XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)'),
'<victim-list>', '<deadlock><victim-list>'),
'<process-list>', '</victim-list><process-list>')
AS XML) AS DeadlockGraph
FROM (SELECT CAST (target_data AS XML) AS TargetData
FROM sys.dm_xe_session_targets st
JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
WHERE [name] = 'system_health') AS Data
CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report';
Run Code Online (Sandbox Code Playgroud)
在我的机器上完成大约需要 20 分钟。报告的统计数据是
Table 'Worktable'. Scan count 0, logical reads 68121, physical reads 0, read-ahead reads 0,
lob logical reads 25674576, lob …Run Code Online (Sandbox Code Playgroud) xml sql-server execution-plan database-internals sql-server-2012
对于我尝试优化的中等复杂查询,我注意到删除TOP n子句会更改执行计划。我猜想,当查询包含TOP n数据库引擎时,会运行查询而忽略该TOP子句,然后最后将结果集缩小到请求的n行数。图形执行计划似乎表明情况确实如此——TOP是“最后”一步。但似乎还有更多事情发生。
我的问题是,TOP n 子句如何(以及为什么)影响查询的执行计划?
这是我的情况的简化版本:
查询匹配来自两个表 A 和 B 的行。
如果没有该TOP子句,优化器估计将有来自表 A 的 19k 行和来自表 B 的 46k 行。返回的实际行数是 A 的 16k 和 B 的 13k。哈希匹配用于连接这两个结果集总共 69 行(然后应用排序)。此查询发生得非常快。
当我添加TOP 1001优化器时不使用哈希匹配;相反,它首先对表 A 的结果进行排序(与 19k/16k 相同的估计值/实际值)并对表 B 执行嵌套循环。表 B 的估计行数现在为 1,奇怪的是TOP n直接影响对 B 的估计执行次数(索引搜索) - 它似乎总是2n+1,或者在我的情况下是 2003 年。如果我改变,这个估计会相应地改变TOP n。当然,由于这是嵌套连接,因此实际执行次数为 16k(表 A 中的行数),这会减慢查询速度。
实际场景有点复杂,但这捕获了基本思想/行为。两个表都使用索引查找进行搜索。这是 SQL Server 2008 R2 企业版。
performance sql-server optimization execution-plan query-performance
为什么以下查询返回无限行?我本来希望该EXCEPT条款终止递归..
with cte as (
select *
from (
values(1),(2),(3),(4),(5)
) v (a)
)
,r as (
select a
from cte
where a in (1,2,3)
union all
select a
from (
select a
from cte
except
select a
from r
) x
)
select a
from r
Run Code Online (Sandbox Code Playgroud)
我有一个要优化的 SQL 查询:
DECLARE @Id UNIQUEIDENTIFIER = 'cec094e5-b312-4b13-997a-c91a8c662962'
SELECT
Id,
MIN(SomeTimestamp),
MAX(SomeInt)
FROM dbo.MyTable
WHERE Id = @Id
AND SomeBit = 1
GROUP BY Id
Run Code Online (Sandbox Code Playgroud)
MyTable 有两个索引:
CREATE NONCLUSTERED INDEX IX_MyTable_SomeTimestamp_Includes
ON dbo.MyTable (SomeTimestamp ASC)
INCLUDE(Id, SomeInt)
CREATE NONCLUSTERED INDEX IX_MyTable_Id_SomeBit_Includes
ON dbo.MyTable (Id, SomeBit)
INCLUDE (TotallyUnrelatedTimestamp)
Run Code Online (Sandbox Code Playgroud)
当我完全按照上面写的方式执行查询时,SQL Server 扫描第一个索引,导致 189,703 次逻辑读取和 2-3 秒的持续时间。
当我内联@Id变量并再次执行查询时,SQL Server 寻找第二个索引,导致只有 104 次逻辑读取和 0.001 秒的持续时间(基本上是即时的)。
我需要变量,但我希望 SQL 使用好的计划。作为临时解决方案,我在查询上放置了索引提示,查询基本上是即时的。但是,我尽量避免使用索引提示。我通常假设如果查询优化器无法完成它的工作,那么我可以做(或停止做)一些事情来帮助它,而无需明确告诉它该做什么。
那么,当我内联变量时,为什么 SQL Server 会提出更好的计划?
查询中未使用的 CTE 是否会影响性能和/或更改生成的查询计划?
execution-plan ×10
sql-server ×9
performance ×5
cache ×1
cte ×1
except ×1
index ×1
memory-grant ×1
optimization ×1
recursive ×1
xml ×1