我可以理解,如果我加入“单独快速”的单个查询,组合可能会变慢,因为默认执行计划可能不是最佳的。但是,当我知道一个查询的行数非常少时,我想我应该能够使用提示来控制连接。
select cj.a, cv.b
from (select distinct a from complexJoin) cj -- 2 rows
inner loop join complexView cv
on cj.a = cv.a
order by cj.a, cv.b
Run Code Online (Sandbox Code Playgroud)
如果 cj <1s 和 cv <1s 期望这是 <~2s 但使用任何提示(合并/散列/循环)通常> 1分钟。
我还尝试使用 CROSS APPLY,因为文档声称内部选择对于每个外部行只执行一次。该查询比手动运行两次内部查询需要大约 100 倍的时间,所以也许我不理解文档。
select cj.a, cv.b
from (select distinct a from complexJoin) cj -- 2 rows
cross apply (select * from complexView
where a = cj.a) cv
order by cj.a, cv.b
Run Code Online (Sandbox Code Playgroud)
如果我用“cj”的结果填充临时表,然后加入 _with_no_hint_ 或使用交叉应用,它会很快,但我真的必须求助于它吗?如果我使用临时表并尝试“任何”连接提示(循环/合并/散列),它会很慢,所以这可能是一个关键点。
我不相信深入查询计划的深度(两者都是复杂的开始)是解决一般问题所必需的:我只想保证隔离而不诉诸临时表 - 这真的不可能?
给定两个级联的、独立的(没有真正的表)递归 CTE:
create view NumberSequence_0_100_View
as
with NumberSequence as
(
select 0 as Number
union all
select Number + 1
from NumberSequence
where Number < 100
)
select Number
from NumberSequence;
go
create view NumberSequence_0_10000_View
as
select top 10001
v100.Number * 100 + v1.Number as Number
from Common.NumberSequence_0_100_View v100
cross join Common.NumberSequence_0_100_View v1
where v1.Number < 100
and v100.Number * 100 + v1.Number <= 10000
-- please resist complaining about "order by in view" for this question
order by v100.Number …Run Code Online (Sandbox Code Playgroud) sql-server cte sql-server-2012 recursive cardinality-estimates
我目前正在使用此灾难通过读取system_health扩展事件环形缓冲区来定位最近的死锁。
select top 2000000000
XEvent.value('@timestamp', 'datetime2(3)') as CreationDateUtc,
--
-- Extract the <deadlock>...</deadlock> tag from within the event
-- Todo: Surely there is a better (xml) way to do this.
--
substring(convert(varchar(max), XEvent.query('.')),
-- start
patindex('%<deadlock%', convert(varchar(max), XEvent.query('.'))),
-- end
patindex('%</deadlock%', convert(varchar(max), XEvent.query('.'))) -
patindex('%<deadlock%', convert(varchar(max), XEvent.query('.'))) + 11 -- 11 to include for '</deadlock>'
) AS XdlFile
from
(
select cast (target_data as xml) as TargetData
from sys.dm_xe_session_targets st with (nolock)
join sys.dm_xe_sessions s with (nolock)
on …Run Code Online (Sandbox Code Playgroud) 给定一个简单的基于行的表,没有 PK 但有一个基于行的聚集索引,如下所示:
create clustered index [CX_PropertyValue] ON [dbo].[PropertyValue] ([PropertyId], [Value])
Run Code Online (Sandbox Code Playgroud)
然后我希望添加一个列存储索引,该索引按与上面的聚集索引相同的顺序进行分段:
create nonclustered columnstore index CS_IX_PropertyValue on dbo.PropertyValue(
PropertyId, Value
)
with (drop_existing = on, maxdop = 1); -- maxdop=1 to preserve the order by property
Run Code Online (Sandbox Code Playgroud)
MaxDop 保留顺序的提示来自:这里
然后使用以下查询报告 PropertyId 列的最小/最大 data_id,并报告 7 个段中的每个段的完整范围:
create view [Common].[ColumnStoreSegmentationView]
as
/*---------------------------------------------------------------------------------------------------------------------
Purpose: List ColumnStore table segment min/max of columns.
Source: https://joyfulcraftsmen.com/blog/cci-how-to-load-data-for-better-columnstore-segment-elimination/
https://dba.stackexchange.com/a/268329/9415
Modified By Description
---------- ---------- -----------------------------------------------------------------------------------------
2020.06.02 crokusek/inet Initial Version
---------------------------------------------------------------------------------------------------------------------*/
select --top 20000000000
s.Name as SchemaName,
t.Name …Run Code Online (Sandbox Code Playgroud) 我无法得到这个相当简单的查询来并行化联合操作:
select va.ObjectId, 0 as IsFlag
from Oav.ValueArray va
where va.PropertyId = @pPropertyId
and va.value in (select value from #MatchValues)
group by va.ObjectId
having count(distinct va.Value) = (select count(*) from #MatchValues)
union all
select odv.ObjectId, 1 as IsFlag
from Pub.OtherTable codv
where PropertyId = 2551
and Id in (select value from #Ids)
and Flag = @pFlag
and Value in (select value from #MatchValues)
group by codv.ObjectId
having count(distinct codv.Value) = (select count(*) from #MatchValues)
Run Code Online (Sandbox Code Playgroud)
使用 MAXDOP 1 运行会得到预期的 0.8s (.5 …
为一个查询的两次执行捕获了两个实际的查询计划:
计划“快速”花费了大约 1 秒,大约 90% 的时间都会发生。
计划“慢”花了大约 16 秒。
由于图形计划看起来与我相同,因此我转储了 XML 版本并执行了差异以查看文本差异以确保。
快侧有 2 个“SpillToTempDb”警告,慢侧有 4 个警告。看着 2 个额外的慢端:
One SpillToTempDb warning on "Parallelism (Repartition Streams) Cost 1%":
<SpillToTempDb SpillLevel="0" />
On SpillToTempDb warning on "Parallelism (Distribute Streams) Cost 1%":
<SpillToTempDb SpillLevel="0" />
Run Code Online (Sandbox Code Playgroud)
慢速和快速情况下的成本是相同的 (1%)。这是否意味着可以忽略警告?有没有办法显示“实际”时间或成本。那会好很多!对于溢出操作,实际行数是相同的。
除了执行 xml 执行计划的手动文本差异以查找警告中的差异之外,我怎么知道运行时间增加 1500% 的实际原因是什么?
除了“RunTimeCountersPerThread”行之外的差异:
Left file: C:\Users\chrisr\Desktop\fast.sqlplan Right file: C:\Users\chrisr\Desktop\slow.sqlplan
10 <ThreadStat Branches="10" UsedThreads="85">
10 <ThreadStat Branches="10" UsedThreads="73">
------------------------------------------------------------------------
------------------------------------------------------------------------
19 <MemoryGrantInfo SerialRequiredMemory="1536" SerialDesiredMemory="10816" RequiredMemory="124224" DesiredMemory="133536" RequestedMemory="133536" GrantWaitTime="0" GrantedMemory="133536" MaxUsedMemory="105440" />
19 <MemoryGrantInfo …Run Code Online (Sandbox Code Playgroud) 以下查询在约 60 个数据库上并行运行。在没有提示的情况下,至少 10% 的数据库存在大量溢出和非最佳计划。
使用更大的数据库作为指导,查询被锁定并带有提示(1 个 CPU 上约 75 毫秒),以减少运行时的差异,因为 1 个错误的计划会导致整体运行时间终止。我们主要反对让每个DB自由调整其计划,因为从长远来看,某些DB可能会在生产平台上着火。我们对大型数据库的近乎最佳计划感到非常满意,但对于较小的数据库可能不是最佳的。
即使在添加带有完整扫描的统计信息后,一些(~5)较小的数据库仍然表现出小的 1 级溢出(参见计划)。运行时间仍然可以(125 毫秒),但希望消除溢出。
这是 Sql Server 2019。自适应授权功能 (2017) 是否应该因溢出而调整授权?在 SSMS 和查看计划中重复运行它似乎表明没有变化。
select top (@pMax)
aig.ObjectId,
iif((@pA in (1, 2, 3, 4, 5, 6, 9, 11, 12) and ttm.ObjectId is not null) or
(@pA in (7, 8, 10, 13, 14, 15)), 1.0, 0.0) as Rank
from oav.value aig
inner merge join Pub.CachedObjectHierarchyAttributes coha
on coha.ObjectId = aig.ObjectId
and coha.IsActiveForPublisher = 1
and coha.IsToolItem = 1
inner merge …Run Code Online (Sandbox Code Playgroud) sql-server execution-plan cardinality-estimates query-performance
以下查询转换表示 13k 行 x 2 列的打包 CSV 的单个字符串。A 列是一个 bigint。B 列是一个smallint。
declare
@dataCsv nvarchar(max) = '29653,36,19603,36,19604,36,29654,36'; -- abbreviated, actually 13k rows
with Input as
(
select Value,
Row = row_number() over (order by (select null)) - 1
from string_split(@dataCsv, ',') o
)
--insert into PubCache.TableName
select 78064 as CacheId,
convert(bigint, i.Value) as ObjectId,
convert(smallint, i2.Value) as BrandId
from Input i
inner hash join Input i2 -- hash to encourage string_split() only once per column
on i2.Row = i.Row + 1 …Run Code Online (Sandbox Code Playgroud) 表的 CacheId 列存在自定义统计信息。隔夜统计更新后:
Statistics for INDEX 'ST_TableName_CacheId'.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Name Updated Rows Rows Sampled Steps Density Average Key Length String Index
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ST_TableName_CacheId Apr 26 2014 2:04AM 121482 121482 6 0 4 NO 121482
All Density Average Length Columns
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0.1666667 4 CacheId
Histogram Steps
RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
39968 0 20247 0 1
40058 0 20247 0 1
40062 0 20247 0 1
40066 0 20247 0 1
40069 0 20247 0 1
41033 0 20247 0 1 …Run Code Online (Sandbox Code Playgroud) 给定 2 个 SQL Server 实例,其中第二个实例配置有用于 tempdb 的 RAMDisk 和以下测试用例。
-- Create source data
select top(1000000) * /* ~10 cols */ into #t1 from SomeData;
Run Code Online (Sandbox Code Playgroud)
然后测量这些级联选择的总运行时间;
-- Benchmark
select * into #t4 from #t1;
select * into #t5 from #t4;
select * into #t6 from #t5;
Run Code Online (Sandbox Code Playgroud)
我的运行时间是一样的~(15s vs ~15s)。一个 CPU 在整个测试期间都达到最大值。
有没有办法加快跨 CPU 的查询(是 tempdb 文件分区)吗?
通过评论请求数据:
The 1 CPU is the SQL Server 2012 process on a 12 CPU server circa 2012.
Machine: 24GMb RAM, HardDrives: 10kRpm x 2 …Run Code Online (Sandbox Code Playgroud) sql-server ×11
optimization ×3
tempdb ×2
columnstore ×1
cte ×1
deadlock ×1
hints ×1
join ×1
merge ×1
recursive ×1
statistics ×1
union ×1
xml ×1