我有一台装有 SQL Server 2016 的全新服务器。
它有 24 个 CPU,大约 80go 的 RAM。
问题是,有时,CPU 会变得非常高(> 70%),而没有任何具体原因。
如果我查看“execute sp_WhoIsActive @get_locks=1”,我会运行大约 40 个查询,但没有锁定,其中一些查询超过 30 秒而不是几毫秒。
这在生产中大约每天附加一次。到目前为止,我唯一的解决方法是将选项“并行成本阈值”从 90 更改为 89,从 89 更改为 90。更改此值实际上可以在不到 10 秒的时间内解决问题,并且 CPU 费用越来越低,并且我的用户更快乐。
你们知道这个问题的根源吗?我已经考虑过计划缓存,但我不知道如何处理这个想法......
编辑:我已禁用英特尔超线程,但问题仍然存在。我已经安排了一个每小时清理缓存的任务。你有什么主意吗 ?
编辑 2:我在 Microsoft 支持上打开了一个问题。显然,重新启动 SQL Server 2016 解决了页面保留问题。如果我有一个“真正的”修复程序,我会尽快通知您。
清除 SQL Server 上的计划缓存后,如何重新生成存储过程的执行计划而不执行存储过程本身?
当我今天早上更新统计数据时,我的一个存储过程运行得非常缓慢。根据一些谷歌,我发现清除计划缓存可以解决这个问题 - 确实如此。但是,如果我必须再次执行此操作,我希望避免在用户等待响应时重新生成计划对性能造成影响。
SQL Server 的版本/版本是 2016 Enterprise。
我们的应用程序使用 SQL Server 2014,我们遇到了与计划缓存相关的问题。
我们有一个参数化查询,它的执行计划取决于参数值。服务器缓存在某些情况下不是最佳的执行计划,然后将其用于所有后续查询。
细节:
我们有一个由以下列组成的表:
(
[Revision] [bigint] IDENTITY(1,1) NOT NULL,
[UserId] [uniqueidentifier] NOT NULL,
...A WHOLE LOT OF OTHER COLUMNS...
)
Run Code Online (Sandbox Code Playgroud)
这两列的含义很清楚,UserId是记录所属用户的Id,是记录Revision的自增索引。其他列并不重要,但它们存在并影响执行计划。
该表包含 ~40.000.000 行和 ~200.000 个不同UserId值,因此每个用户平均有 200 条记录。行永远不会更新,我们只使用 INSERT 和 DELETE 来修改数据。
我们的应用程序对此表执行以下查询:
SELECT * FROM SampleTable WHERE Revision > {someRevision} AND UserId = {someId}
Run Code Online (Sandbox Code Playgroud)
该表有两个索引:
Revision ascUserId asc, Revision asc当我手动执行此查询时,我看到执行计划取决于someRevision.
如果是比较接近的修订目前的最高值,则服务器使用Clustered Index Seek与Seek Predicate: Revision > someRevision
如果它没有关闭,服务器使用Index Seek …
所以我跑去sp_Blitz处理一些系统。有一些代码可以像往常一样清理。一些应该是聚集索引的堆。等等。
这个特定的查询使用了文字,似乎产生了很多计划。在此查询中的表上整理了索引和内容,甚至为最新的代码/数据库将查询参数化以投入生产。
但是查询仍然显示为参数化问题。(DBA 帮助将计划缓存查询转换为 SSRS 报告,因此我可以从浏览器在 PROD 环境中快速运行它们)。
然后去哪儿?忽略它?(似乎很多计划都很重要)
使用强制参数化?(但显式参数化的那个出现了)。
呃 - 我看到开发人员没有接受我的建议,认为它LEFT JOIN正在变成INNER JOIN......我必须把它修好......
我的公司有一些使用大量动态查询(无参数)的遗留系统。在较新的系统中,我们使用存储过程和参数化 SQL。然而,我们发现我们的存储过程经常出现性能峰值。
我查看了它,似乎计划缓存会定期清除存储过程计划,但在计划缓存中保留了大量动态 SQL 语句。
我对 SQL Server (SQL Server 2017) 这样做的原因有点困惑。SQL Server 如何决定删除哪一个?
我看到由于编译特定存储过程时的锁定而导致阻塞(如KB 263889 中所述)。基本上,有几个进程在同一个资源“TAB:8:1044511100:0 [COMPILE]”上等待 LCK_M_X,如果我查找对象,它就是我的存储过程之一。
试图缩小为什么不缓存该过程的执行计划的范围,我发现sp_executesql的@params 参数的大小是一个因素:如果@params 超过 4000 个字符,有时执行计划会被缓存,但是如果@params 为 4000 个字符或更少,则每次都会缓存计划。
这可以通过以下过程重现:
CREATE PROCEDURE [dbo].ObviouslyAnonymizedProcedure (
@SchemaId int = Null
, @TypeDesc varchar(60) = Null
, @paramFoo varchar(100) = null
, @paramBar datetime2(4) = null
, @paramBaz numeric(4,3) = null
-- Parameter names have been changed. I added a "param" prefix and set type
-- varchar(100) to more easily get up to 4000 characters in this example.
, @paramQux varchar(100) = null
, @paramQuux …Run Code Online (Sandbox Code Playgroud) 我发现,通过查询存储,一个查询平均执行 297582 次逻辑读取。
我想看看我是否能够稍微调整该查询,然后尝试再次执行该查询以查看是否有任何改进。
问题是我在缓存计划中找不到编译参数值。
我错过了什么吗?也许是一些阻止参数值缓存的原因/设置?
即使我以 XML 格式打开执行计划,我也找不到参数。
附加信息:查询由第三方应用程序执行,该应用程序准备语句,然后使用sp_prepare和执行它们sp_execute。
sql-server execution-plan parameter plan-cache sql-server-2016
我正在使用Brent Ozar 的sp_Blitz,其结果之一是:
一个查询的多个计划
计划缓存中的单个查询有 1146 个计划 - 这意味着我们可能存在参数化问题。
SELECT q.PlanCount,
q.DistinctPlanCount,
qs.query_hash,
st.text AS QueryText,
qp.query_plan AS QueryPlan
FROM ( SELECT query_hash,
COUNT(DISTINCT(query_hash)) AS DistinctPlanCount,
COUNT(query_hash) AS PlanCount
FROM sys.dm_exec_query_stats
GROUP BY query_hash
) AS q
JOIN sys.dm_exec_query_stats qs ON q.query_hash = qs.query_hash
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp
WHERE PlanCount > 1
ORDER BY q.PlanCount DESC, q.query_hash;
Run Code Online (Sandbox Code Playgroud)
...它显示了计划数量最多的查询。
当我运行它时,我得到的最重要的结果之一(对于相同的查询哈希有大约 1150 个计划)让我感到困惑:
也许在屏幕截图上有点难以识别 -这是一个完整的CREATE …
我正在分析支持 3rd 方应用程序的 2008 实例。
该应用程序将生成 SQL 代码,然后将其作为临时查询发送到数据库。
我正在使用此查询(基于 Glenn Berry 脚本):
SELECT
qs.creation_time
,qs.last_execution_time
,qs.execution_count
,qs.total_worker_time
,qs.total_physical_reads
,qs.total_logical_writes
,qs.total_logical_reads
,qs.plan_handle
,qt.text
,qt.dbid
FROM
sys.dm_exec_query_stats AS qs WITH (NOLOCK)
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE
qt.dbid >= 7
OPTION (RECOMPILE)
Run Code Online (Sandbox Code Playgroud)
我的问题是我正在为非常相似的查询获得数千个计划,即
SELECT * FROM customers WHERE name = 'bob'
SELECT * FROM customers WHERE name = 'bill'
Run Code Online (Sandbox Code Playgroud)
(实际上查询非常大,最多 3000 个字符)
这使得将数据转换为适合高级分析的格式几乎是不可能的。
是否可以快速比较 2 个 SQL 查询并查看它们是否几乎相同?然后我会随机选择其中一个查询,并将所有活动与该查询进行分组。(我试过 DIFFERENCE 但速度很慢)
SQL 是否已经存储了一个类似于 MD5 Hash sql_handle 的值,它允许它查看两个查询是否相似并因此重用相同的计划?(如果存在这样的值,那么我会对此进行分组)
我对存储过程没有这个问题,因为正在重用相同的计划。我只想将所有类似的临时人员组合在一起。
我有一些参数化的查询,但它们每次仍在创建一个新的执行计划。我正在使用 SQL Server 2016。
查询如下:
(@P1 varchar(1043),@P2 varchar(6))
UPDATE table
SET FILEDATA=@P1
WHERE FILEID=@P2
Run Code Online (Sandbox Code Playgroud)
这个查询没有使用缓存中已经生成的执行计划,而是每次都创建一个新计划。
plan-cache ×10
sql-server ×9
parameter ×2
sp-blitz ×2
dmv ×1
index ×1
parallelism ×1
performance ×1