在查询与存储过程加密相关的计划缓存时,我遇到了一个非常奇怪的问题。但是,查询加密计划缓存的是存储过程,而不是计划缓存本身中的查询。让我解释...
下面的过程只是在计划缓存中搜索匹配的字符串并输出查询计划(最后一列)。
ALTER PROCEDURE spQueryPlanCache @textstring nvarchar(max)
AS
BEGIN
SELECT
databases.name,
dm_exec_sql_text.text AS TSQL_Text,
dm_exec_query_stats.creation_time,
dm_exec_query_stats.execution_count,
dm_exec_query_stats.total_worker_time AS total_cpu_time,
dm_exec_query_stats.total_elapsed_time,
dm_exec_query_stats.total_logical_reads,
dm_exec_query_stats.total_physical_reads,
dm_exec_query_plan.query_plan
FROM sys.dm_exec_query_stats
CROSS APPLY sys.dm_exec_sql_text(dm_exec_query_stats.plan_handle)
CROSS APPLY sys.dm_exec_query_plan(dm_exec_query_stats.plan_handle)
INNER JOIN sys.databases
ON dm_exec_sql_text.dbid = databases.database_id
WHERE dm_exec_sql_text.text LIKE @textstring
END
Run Code Online (Sandbox Code Playgroud)
这是最后一列中输出的计划 XML 的示例:
ALTER PROCEDURE spQueryPlanCache @textstring nvarchar(max)
AS
BEGIN
SELECT
databases.name,
dm_exec_sql_text.text AS TSQL_Text,
dm_exec_query_stats.creation_time,
dm_exec_query_stats.execution_count,
dm_exec_query_stats.total_worker_time AS total_cpu_time,
dm_exec_query_stats.total_elapsed_time,
dm_exec_query_stats.total_logical_reads,
dm_exec_query_stats.total_physical_reads,
dm_exec_query_plan.query_plan
FROM sys.dm_exec_query_stats
CROSS APPLY sys.dm_exec_sql_text(dm_exec_query_stats.plan_handle)
CROSS APPLY sys.dm_exec_query_plan(dm_exec_query_stats.plan_handle)
INNER JOIN sys.databases …Run Code Online (Sandbox Code Playgroud) 我正在努力说服查询计划按照我认为应该的方式行事。在查询索引视图时添加 TOP 子句会导致次优计划,我希望在排序方面得到一些帮助。
环境
设置:
首先,我创建了一个视图来回报每个人的高声誉:
CREATE VIEW vwHighReputation
WITH SCHEMABINDING
AS
SELECT [Id],
[DisplayName],
[Reputation]
FROM [dbo].[Users]
WHERE [Reputation] > 10000
Run Code Online (Sandbox Code Playgroud)
接下来,由于我将按显示名称进行搜索,因此我在视图上创建了几个索引:
CREATE UNIQUE CLUSTERED INDEX IX_Users_Id ON [dbo].[vwHighReputation]([Id])
GO
CREATE NONCLUSTERED INDEX IX_Users_DisplayName ON [dbo].[vwHighReputation]([DisplayName]) INCLUDE (Reputation)
GO
Run Code Online (Sandbox Code Playgroud)
如果我通过视图查询,我可以看到我的非聚集索引正在被使用:
SELECT *
FROM [dbo].[vwHighReputation]
WHERE [DisplayName] LIKE 'J%'
Run Code Online (Sandbox Code Playgroud)
计划:(https://www.brentozar.com/pastetheplan/?id=Sy2EoJaiv)
到现在为止还挺好。我什至可以使用我的视图作为带有 OUTER APPLY 的更复杂查询的一部分,并且我仍然只对索引进行了 63 次读取(这显然是一个人为的示例,但有助于说明我将要解决的问题) ):
SELECT [U].[Id],
[A].[Reputation],
[A].[DisplayName]
FROM [dbo].[Users] AS [U]
OUTER APPLY (
SELECT * …Run Code Online (Sandbox Code Playgroud) 请有人帮助我理解为什么标量函数的存在会改变先前索引扫描的估计?
我正在使用 StackOverflow2013 数据库的副本。SQL Server 2019(兼容模式100)
为了演示这个问题,我创建了一个简单的函数,它检查 User.DisplayName 中是否有“s”:
CREATE FUNCTION dbo.IsUserS (@DisplayName nvarchar(80))
RETURNS bit
AS
BEGIN
RETURN CHARINDEX('S', @DisplayName)
END
Run Code Online (Sandbox Code Playgroud)
这是使用该函数的查询:
SELECT U.ID,
U.[DisplayName],
U.[Reputation]
FROM [dbo].[Users] AS [U]
WHERE [U].[CreationDate] > '20100101'
AND [U].[Reputation] > 100
AND dbo.[IsUserS](u.[DisplayName]) = 1
Run Code Online (Sandbox Code Playgroud)
我正在将此查询的计划与完全相同的查询进行比较,但没有函数调用。以下是计划:
https://www.brentozar.com/pastetheplan/?id=ByLy1LlNi
在这两个计划中,我们都从聚集索引扫描开始。对于底部计划(没有过滤器的计划),扫描运算符的估计值与实际值很接近。对于带有过滤器的计划,估计值相差很大(实际行数的 36%)。
我的问题是,为什么 UDF 的存在会改变先前索引扫描的估计?
请注意,我正在 Compat' 模式 100 下运行。如果我翻转到 150,估计值与实际值实际上会更差,除非我打开旧基数估计器(在这种情况下,它与 100 相同,所以仍然很糟糕)。
我们的一位应用程序开发人员向我提出了一个有趣的问题。在下面的代码中,您将看到更新语句将当前列值分配给两个变量,同时还将这些相同的列更新为新值。
\n问题是,是否保证变量@oStart和@oFinish将被分配给[Start]和[Finish]的旧值而不是新值?在测试中,情况确实如此,但是,我想确认这是有保证的行为。
\n我预计答案是“不 - 不能保证”,最终,这取决于优化器所做的决定。无论如何,无论如何,这种模棱两可的代码都是不鼓励的(有更优雅和可读的编写方式),但有兴趣听到每个人的想法。
\n-- Parameters\nDECLARE @StartDate smalldatetime = '2022-01-01',\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 @EndDate smalldatetime = '2022-12-31';\n\n-- Body\nDECLARE @oStart smalldatetime,\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 @oFinish smalldatetime;\n\nUPDATE\xc2\xa0 [dbo].[MyTable]\nSET\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 @oStart = [Start],\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 @oFinish = [Finish],\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 [Start] = @StartDate,\n\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0 [Finish] = @EndDate\nWHERE\xc2\xa0\xc2\xa0 [ID] = 12;\nRun Code Online (Sandbox Code Playgroud)\n 我试图理解为什么 SQL Server (2014) 在死锁场景中放置独占键锁。我已将整个死锁图粘贴在下面。
我很困惑,因为死锁发生在两个 SELECT 语句之间,两者都作为单个 READ COMMITTED 语句运行,而不是在事务内运行(因此同一事务中的其他地方没有发生更新等)。
我相信发生死锁是因为每个进程都在索引上创建一系列键锁,并且由于获取它们的顺序,所以发生了死锁。但是,如果进程仅创建共享锁,则不应出现死锁(根据我的理解)!
所以根本问题是 - 为什么这些 SELECT 语句会获取独占键锁?
我希望这只是我对锁定的误解。任何建议将不胜感激。
<deadlock>
<victim-list>
<victimProcess id="processd7f647848" />
</victim-list>
<process-list>
<process id="processd7f647848" taskpriority="0" logused="25948" waitresource="KEY: 32:72057594051428352 (e2d15ad895e9)" waittime="5014" ownerId="394724294049" transactionname="user_transaction" lasttranstarted="2022-04-06T09:46:18.770" XDES="0x67bf873350" lockMode="S" schedulerid="15" kpid="26196" status="suspended" spid="306" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2022-04-06T09:46:18.783" lastbatchcompleted="2022-04-06T09:46:18.783" lastattention="1900-01-01T00:00:00.783" clientapp=".Net SqlClient Data Provider" hostname="myhost" hostpid="1500" loginname="myuser" isolationlevel="read committed (2)" xactid="394724294049" currentdb="32" lockTimeout="4294967295" clientoption1="673185824" clientoption2="128056">
<executionStack>
<frame procname="MyDatabase.Main.GetMessages" line="154" stmtstart="11934" stmtend="12156" sqlhandle="0x03002000ebd98264d1bfae0066ae000001000000000000000000000000000000000000000000000000000000">
SELECT ID, Message FROM [dbo].[Messages] WHERE MessageType = @Type …Run Code Online (Sandbox Code Playgroud)