我在 SQL Server 2014 SP2 中有一个 T-SQL 存储过程,它在服务器上花费的时间是我在本地环境中花费的时间的 3 倍。
我将本地数据库恢复到服务器上的数据库,因此架构和数据是相同的。
我是一名程序员,并不是真正的 DBA,所以请耐心等待。
在您查看 XML 之前,执行计划似乎是相同的。在我的本地环境中,Stream Aggregate 用于其中一个查询以进行不同的选择,而在服务器上,它看起来像是 Sort 与散列一起使用。
服务器的处理器比我的(野兽)本地机器少的事实似乎导致了这个问题。每个查询在服务器上都需要更长的时间。这可能是在服务器上选择排序/散列而不是流聚合的原因吗?
有没有办法强制流聚合?
这是存储过程的 SQL:http : //pastebin.com/kkXM3Bsf
这是我本地环境的执行计划:http : //pastebin.com/0u7SHxnM
这是服务器的执行计划:http : //pastebin.com/9sE9DfM0
我有一个非常大的查询,它的运行速度比我想象的要慢,但是对查询执行计划的深入研究并没有帮助揭示这种缓慢。最终我缩小了范围:try_parse是罪魁祸首!
正常查询:
SELECT CloseDate
FROM MyTable
(4959 row(s) affected)
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 17 ms.
Run Code Online (Sandbox Code Playgroud)
使用 try_parse:
SELECT try_parse(CloseDate as datetime using 'en-us')
FROM MyTable
(4959 row(s) affected)
SQL Server Execution Times:
CPU time = 719 ms, elapsed time = 718 ms.
Run Code Online (Sandbox Code Playgroud)
后一种情况下的执行计划看起来很无辜:
有没有什么方法可以让我以后更容易地发现罪魁祸首?缓慢的实际来源完全隐藏在视线之外。
这是现实生活问题的简化版本。GetDate在子选择中使用时,计划更糟且不同。2个查询:
select * , (select count(1)
from hamsfa.customer as sub
where sub.tstamp_nosync > @old
and sub.cus_id > main.cus_id) as x
from hamsfa.customer as main ;
select * , (select count(1)
from hamsfa.customer as sub
where sub.tstamp_nosync > dateadd(year, -100, getdate())
and sub.cus_id > main.cus_id) as x
from hamsfa.customer as main ;
Run Code Online (Sandbox Code Playgroud)
我不完全理解的是为什么。
变量应该按我的理解变差。
还有另一个查询,这导致了几乎 700% 的差异(1s 与 7s)。
所以问题是:为什么一个变量会产生更好的计划,即使根据我的经验它应该更糟?
编辑:统计数据是最新且正确的
我试图在 Postgres 9.5 中从这个查询中挤出更多的性能。我正在运行超过 400,000 行。
在玩弄它时,我注意到这些CASE语句增加了相当多的查询成本 - 如果我用简单地对一些现有列求和来替换它们,它会将执行时间减半。有没有更有效的方法来计算这些总和?
SELECT sum("tag1"), sum("tag2"), sum("total_tags")
FROM (
SELECT people.data->'recruiter_id' AS recruiter_id,
(CASE WHEN people.data->'tags' ? 'tag1' THEN 1 END) AS "tag1",
(CASE WHEN people.data->'tags' ? 'tag2' THEN 1 END) AS "tag2",
((CASE WHEN people.data->'tags' ? 'tag1' THEN 1 ELSE 0 END) +
(CASE WHEN people.data->'tags' ? 'tag2' THEN 1 ELSE 0 END)) AS total_tags
FROM people WHERE people.data->'tags' ?| ARRAY['tag1','tag2'] ) AS target
GROUP BY recruiter_id
Run Code Online (Sandbox Code Playgroud)
的输出EXPLAIN ANALYSE: …
postgresql performance statistics execution-plan json postgresql-performance
我有以下查询:
SELECT id,
email,
first_name as "firstName",
last_name as "lastName",
is_active as "isActive",
password,
access,
CASE
WHEN access < 3 THEN (
SELECT
CASE WHEN count(*) = 1 THEN true ELSE false END
FROM user_rating_entity ure
WHERE ure.user_id = u.id
AND ure.rating_entity_id = :re_id
)
ELSE true
END as "isResponsible"
FROM users u
WHERE u.id = :id
Run Code Online (Sandbox Code Playgroud)
如果access > 3,字段“isResponsible”应直接设置为true,并且不应执行子查询。我在这两种情况下都使用了解释分析,其中 access>=和<to 3但我得到了相同的输出。
为什么呢?
我似乎在对 aSELECT IN和 a使用硬编码值之间存在巨大的性能差距STRING_SPLIT。除了最后一个阶段为STRING_SPLIT代码多次执行索引查找之外,查询计划是相同的。结果是大约 90000 与大约 15000(根据dm_exec_query_stats)的 CPU 时间,因此差异是巨大的。我已经在这里发布了两个计划......
有趣的是查询计划显示的成本几乎相同,但是当我检查dm_exec_query_stats成本 ( last_worker_time)时却大不相同。
这是查询计划的 2 个输出...
0x79DEAD79D1F149CD 16199
select *
from fn_get_samples(1) s
where s.sample_id in
(2495,2496,2497,2498,2499,2500,2501,2502,2503,2504)
0x4A073840486B252C 86689
select *
from fn_get_samples(1) s
where s.sample_id in
(select value as id
from
STRING_SPLIT('2495,2496,2497,2498,2499,2500,2501,2502,2503,2504',','))
Run Code Online (Sandbox Code Playgroud)
功能代码是...
CREATE FUNCTION [dbo].[fn_get_samples]
(
@user_id int
)
RETURNS TABLE
AS
RETURN (
-- get samples
select s.sample_id,language_id,native_language_id,s.source_sentence,s.markup_sentence,s.latin_sentence,
s.translation_source_sentence,s.translation_markup_sentence,s.translation_latin_sentence,
isnull(sample_vkl.knowledge_level_id,1) as vocab_knowledge_level_id,
isnull(sample_gkl.grammar_knowledge_level_id,0) as grammar_knowledge_level_id, …Run Code Online (Sandbox Code Playgroud) performance sql-server execution-plan string-splitting query-performance
我在网上看到的所有示例都暗示OPTIMIZE FOR UNKNOWN应用于特定查询。
可以OPTIMIZE FOR UNKNOWN应用于整个存储过程(而不仅仅是特定查询)?如果是,语法是什么?
所以,我运行了 BrentOzar 脚本,它为同一查询确定了 10195 个计划!!!查询如下:
SELECT *
FROM [table1]
INNER JOIN [table2]
ON [table1].[versionId] = [table2].[VersionId]
INNER JOIN [table3]
ON [table2].[ContentId] = [table3].[nodeId]
INNER JOIN [table4]
ON [table3].[nodeId] = [table4].[id]
WHERE ([table4].[nodeObjectType] = 'abcde123-fgh3-4ijk-8lmn-424f222332ff')
AND ([table1].[published] = 0
AND [table1].[releaseDate] <= '2017-07-22 17:43:47')
AND ([table1].[newest]=1)
ORDER BY [table2].[VersionDate] DESC, [table4].[sortOrder]
Run Code Online (Sandbox Code Playgroud)
所有 10195 个之间的唯一区别是日期字段(发布日期)。每个计划具有不同日期的值。
关于索引,以下适用:
想象一下有一个包含这些字段的表:
Employee: E-Number
E-Name
Department
Salary
Run Code Online (Sandbox Code Playgroud)
我们需要编写一个查询来找到这个表中第二高的薪水。
我发现这个查询:
select distinct salary
from Employee e1
where 2 = ( select count(distinct salary)
from Employee e2
where e1.salary < e2.salary)
Run Code Online (Sandbox Code Playgroud)
我对这部分有点困惑,where 2 =因为我以前从未见过这样的事情。
任何人都可以在这里解释更多关于查询和部分的信息where 2 =吗?子查询的结果是什么,表行(e1,e2)以什么方式相互比较?
实际上这是执行计划,谁能解释更多步骤?
我发现,通过查询存储,一个查询平均执行 297582 次逻辑读取。
我想看看我是否能够稍微调整该查询,然后尝试再次执行该查询以查看是否有任何改进。
问题是我在缓存计划中找不到编译参数值。
我错过了什么吗?也许是一些阻止参数值缓存的原因/设置?
即使我以 XML 格式打开执行计划,我也找不到参数。
附加信息:查询由第三方应用程序执行,该应用程序准备语句,然后使用sp_prepare和执行它们sp_execute。
sql-server execution-plan parameter plan-cache sql-server-2016
execution-plan ×10
sql-server ×8
performance ×4
postgresql ×2
explain ×1
json ×1
optimization ×1
parameter ×1
plan-cache ×1
statistics ×1
subquery ×1