我正在研究一个场景,在这个场景中,我提供了一个变量值。当我传递 Null 值时,查询引擎没有扫描连接表。根据逻辑查询处理,首先执行FROM子句,然后执行ON和JOIN。但在这种情况下,查询引擎直接转到Where子句。当变量的值为 NULL 时,任何人都可以解释行为查询引擎。我正在使用 SQL Server 2016。
当值改变时
performance sql-server optimization execution-plan sql-server-2016 query-performance
来自sys.dm_exec_query_stats 的Query_hash 定义 是:
query_hash:对查询计算的二进制哈希值,用于识别具有相似逻辑的查询。您可以使用查询哈希来确定仅在文字值上有所不同的查询的聚合资源使用情况。
但是当我搜索一个特定的 query_hash(如下所示)时,我得到了多个查询文本,这些文本在逻辑和size_in_bytes(计划)上有很大差异。
注意:我使用的是 SQL Server 2016
DECLARE @QueryHashTest BINARY(8)
SET @QueryHashTest = CONVERT(BINARY(8), 'Ð…U¹üŒv¿')
SELECT
QCP.objtype
,qStat.query_hash,
CONVERT(VARCHAR(100), qStat.query_Hash) AS VARCHAR_query_hash
,sText.text AS QueryText
,QCP.size_in_bytes
,qStat.creation_time
,qp.query_plan
FROM (
SELECT query_hash,
COUNT(query_hash) AS PlanCount
FROM sys.dm_exec_query_stats
GROUP BY query_hash
) AS MultipleQ
INNER JOIN sys.dm_exec_query_stats qStat ON MultipleQ.query_hash = qStat.query_hash
INNER JOIN sys.dm_exec_cached_plans QCP
ON QCP.plan_handle = qStat.plan_handle
CROSS APPLY sys.dm_exec_sql_text(qStat.sql_handle) AS sText
CROSS APPLY sys.dm_exec_query_plan(qStat.plan_handle) AS qp
WHERE PlanCount > …Run Code Online (Sandbox Code Playgroud) 我有以下偶尔运行缓慢的查询:
SELECT C.CustomerID
FROM dbo.Customers C WITH (NOLOCK)
WHERE C.Forename = @Forename
AND C.Surname = @Surname
OPTION (RECOMPILE)
Run Code Online (Sandbox Code Playgroud)
CustomerID 是Customers 表上的主键。客户表还有以下两个非聚集索引:
CREATE NONCLUSTERED INDEX idx_Forename ON Customers (Forename ASC)
CREATE NONCLUSTERED INDEX idx_Surname ON Customers (Surname ASC)
Run Code Online (Sandbox Code Playgroud)
当我使用输入的姓氏和名字运行查询时,查询优化器使用索引“idx_Surname”,如以下执行计划所示:
对于此特定搜索,此查询需要两分钟多的时间才能完成,并且未找到任何结果。对于输入的值,@Forename 在 Customers 表中没有匹配项,而 @Surname 匹配 31,162 条记录。当我只按 @surname 搜索时,31,162 条记录会在不到一秒钟的时间内返回,并采用以下计划:
为了优化包含 Forename 和 Surname 的搜索的查询,我添加了以下覆盖索引:
CREATE NONCLUSTERED INDEX idx_Surname_Covering ON dbo.Customers (Surname) INCLUDE (Forename)
Run Code Online (Sandbox Code Playgroud)
带有 Forename 和 Surname 的查询将在不到一秒的时间内返回。但是,实际执行计划中并没有使用覆盖索引:
所以,
ps 上面的查询是一个孤立的例子,在使用时,可以搜索姓氏或名字,或者两者都可以搜索,并且客户表还包括其他具有自己索引的可搜索列。这个细节被认为与问题无关,所以我没有包括它。
performance index sql-server execution-plan sql-server-2016 query-performance
我试图了解强制使用全扫描更新统计信息对执行计划估计的影响。
我目前在一个非常简单的 SELECT 查询的执行计划中有以下结果:

如您所见,它相差 5 行。
然后我运行:
UPDATE STATISTICS Person.Address WITH FULLSCAN
UPDATE STATISTICS Person.Address [PK_Address_AddressID] WITH FULLSCAN
GO
EXEC sp_recompile 'Person.Address';
GO
SELECT * FROM Person.Address OPTION(RECOMPILE)
Run Code Online (Sandbox Code Playgroud)
但是,它仍然相差 5 行。为什么?
我知道除非有性能问题,否则我不应该担心。但是,我试图了解完整统计信息更新的实际效果
我正在尝试调整以下查询,无论将什么值作为参数传入,该查询都需要 15-16 秒,查询是:
select distinct d.documentpath as path, d.documentname as name, d.datecreated as created, pc.DateProcessed
from datagatheringruntime dgr
inner join processentitymapping pem on pem.entityid = dgr.entityid
inner join document d on d.entityid = pem.entityid or d.unitofworkid = pem.processid
left join PendingCorrespondence pc on pc.PendingCorrespondenceId = d.PendingCorrespondenceId
where rootid = @P0 and dgr.name in('cust_pn', 'case_pn')
OPTION(RECOMPILE)
Run Code Online (Sandbox Code Playgroud)
我已经更新了查询涉及的所有表的统计信息(不包括DataGatheringRuntime在 ~ 处相当大的表100GB),并尝试使用 a 重新分解查询,CTE但获得相同的执行计划并需要一些帮助。
实际的执行计划可以在这里找到:
https://www.brentozar.com/pastetheplan/?id=ByUVIqlFE
这是从执行计划明确指出,问题在于对外部输入nested loop join与特别是lazy table spool以下的scan非群集的IX_Camunda_1 …
performance sql-server t-sql execution-plan sql-server-2016 query-performance
我的公司有一些使用大量动态查询(无参数)的遗留系统。在较新的系统中,我们使用存储过程和参数化 SQL。然而,我们发现我们的存储过程经常出现性能峰值。
我查看了它,似乎计划缓存会定期清除存储过程计划,但在计划缓存中保留了大量动态 SQL 语句。
我对 SQL Server (SQL Server 2017) 这样做的原因有点困惑。SQL Server 如何决定删除哪一个?
这是我的查询(这是一个 Microsoft Axapta 查询):
(@P1 bigint)
SELECT TOP 1 T1.JOURNALNUM,T1.LINENUM,T1.ACCOUNTTYPE,T1.COMPANY,T1.TXT,
T1.AMOUNTCURDEBIT,T1.CURRENCYCODE,T1.EXCHRATE,T1.TAXGROUP,
T1.CASHDISCPERCENT,T1.QTY,T1.BANKNEGINSTRECIPIENTNAME,
-- *Snipped lots of columns in T1* --
T1.MODIFIEDDATETIME,T1.RECVERSION,T1.PARTITION,T1.RECID
FROM LEDGERJOURNALTRANS T1
WHERE (((PARTITION=123123123) AND (DATAAREAID=N'test')) AND (REVRECID=@P1))
Run Code Online (Sandbox Code Playgroud)
当前执行计划:
实际上,表上有一个合适的索引。
索引列:(PARTITION,DATAAREAID,REVRECID)
我试过索引力。这个执行计划(索引查找+键查找)比执行计划(索引扫描)要快:
我试图:
更新统计
更改了列顺序,例如 (REVRECID,PARTITION,DATAAREAID)
MSSQL 为什么选择聚集索引?
在一周内,我在批处理作业中遇到过几次糟糕的执行计划,为了避免强制执行计划,我继续添加本地连接提示(当这些连接类型是好的和坏的执行计划之间的区别时)。通过这种方式,我可以让 SQL Server 选择大部分计划,同时强制执行我知道的少数连接来完成查询。
在下面的执行计划中,我想强制连接类型有些相同,因此也会对这些使用本地连接提示。但是,我想知道我是否也能够触发执行计划中的其他操作,例如:
项目清单
这些操作是我可以选择的,还是取决于查询期间选择的连接类型/顺序?
这两个计划都是由从查询存储中提取的 XML 创建的。
好的执行计划:https : //www.brentozar.com/pastetheplan/?id=HyYMn7K2V
错误的执行计划:https : //www.brentozar.com/pastetheplan/?id=Hka6i7Yh4
我正在尝试诊断一个问题,即 2 个非常相似的查询导致执行时间非常不同,即使执行计划非常简单。
大体上(我已经修剪了选择和重命名的表),我们有一个主表 ( [Primary]),我们试图根据相关表中至少 1 个匹配行的存在进行过滤。然后我们返回前 20 行(用于分页)
查询之间唯一的区别是相关表不同(尽管具有相似的结构)。快速查询 ( [PrimaryResult]) 需要 < 1 秒,而慢查询 ( [PrimaryScore]) 需要 20 秒左右。
我检查了执行计划,主要区别在于主表上的键查找。在快速查询中,Actual number of rows read大约为 10k,而对于慢速查询,它超过 360 万。
我观察到的另一件事是快速查询似乎并行执行所有操作(由执行计划中的双箭头表示,但慢速查询没有)。
查询是通过 Entity Framework 6 LINQ 生成的(因此所有别名)。
慢查询
SELECT
[Project5].[Id] AS [Id]
FROM ( SELECT
[Project1].[Id] AS [Id]
FROM ( SELECT
[Extent1].[Id] AS [Id]
FROM [dbo].[Primary] AS [Extent1]
INNER JOIN [dbo].[GuidBatch] AS [Extent2] ON ([Extent1].[DeviceRegistrationId] = [Extent2].[Ref]) AND (@p__linq__0 = [Extent2].[Id])
INNER JOIN [dbo].[Place] AS …Run Code Online (Sandbox Code Playgroud) 我希望你们能在这里帮助我。我们的应用程序每 3 秒轮询一次消息表,寻找要发送的通知。这适用于我们所有的客户(单租户数据库),除了一个。他们将一天 23 小时没有活动,然后一次加载数千条消息(3000+)。在其他情况下,这个卷什么都不是,我们可以轻松处理它,除了在这种情况下,下面的 SQL 查询需要大约 30 秒才能运行,并且随着队列在更新时备份而变得更糟,需要排他锁和因此阻止所有其他查询,因此问题会导致各种破坏。这都是由于糟糕的查询计划造成的。
我们每天早上 5 点进行每日重新索引(重组 < 30%,重建 > 30%,忽略 <5%)以及更新统计信息。这些都来自 Ola Hallengren 维护解决方案。我们也在 SQL Server 2016 上并且完全是最新的 (13.0.5492.2)
我手头没有这 2 个计划,但基本上坏计划会执行 MessagesSent 表(3.5m 行)的全表扫描。
我的理论是,由于查询一整天都没有返回任何内容,因此某些部分没有执行,因此错误查询是最有效的 SQL 查询。
这将在刷新查询计划后继续,因为它只生成相同的计划,但是当我在 MessagesSent 表上更新统计信息时,创建好的计划并且一切正常,查询在大约 10-30 毫秒内执行。
有谁知道我如何微调它以始终使用更好的计划,即使查询返回的数据不存在?作为修补程序,我们向应用程序添加了重新编译选项,但我认为这不是每 3 秒执行一次的查询的理想解决方案。
这是查询:
WITH TopMessage
AS
(
SELECT TOP 1 ID, BatchID FROM MessagesSent
JOIN Units ON Unit = idUnit
WHERE MessageDate <= GETDATE()
AND Active = 'True'
AND Status = 'Queued'
AND NOT(DialString = 'null')
AND Unit = ('29') …Run Code Online (Sandbox Code Playgroud) execution-plan ×10
sql-server ×10
performance ×3
index ×2
statistics ×2
t-sql ×2
join ×1
optimization ×1
plan-cache ×1