我已经对OPTION (FAST XXX)查询提示在SELECT语句中的作用做了一些挖掘,但我仍然对此感到困惑。根据 MSDN:
指定为快速检索第一个 number_rows 优化查询。这是一个非负整数。返回第一个 number_rows 后,查询将继续执行并生成其完整结果集。
对我来说这没有多大意义,但基本上查询可以非常快地获得前 XXX 行,然后以正常速度获得其余行?
让我想到这一点的 Microsoft Dynamics 查询是:
select pjproj.project,pjproj.project_desc,pjproj.customer,pjproj.cpnyid
from pjproj WITH (NOLOCK)
where project like '%'
order by project OPTION(FAST 500)
Run Code Online (Sandbox Code Playgroud)
谁能准确解释这个查询提示在做什么以及它比不使用它的优势?
表Client字段上有一个聚集索引LastName。
当我简单地从表中转储所有记录时,它们会按字母顺序出现,除非(nolock)在相关查询中使用了提示。该提示会更改记录的顺序。应该是?。我很肯定没有其他会话有更改该表的开放事务(至少sp_who2没有向我显示任何内容)。
如何解释顺序上的差异?
从评论中提取的其他信息:
没有顺序。非聚集索引是否应该强制执行顺序?
即使使用指定聚集索引的索引提示,查询仍然返回不同的顺序。他们应该吗?我想知道为什么nolock在没有明显改变计划的情况下更改返回记录的顺序。
我对它们做了一个 WinDiff - 除了 [the] (nolock)[query hint]之外相同。
我有一个有点复杂的 SQL Server 2008 查询(大约 200 行相当密集的 SQL),它没有按照我的需要执行。随着时间的推移,性能从大约 0.5 秒下降到大约 2 秒。
查看执行计划,很明显,通过重新排序连接,可以提高性能。我做到了,它做到了……下降到大约 0.3 秒。现在查询有“OPTION FORCE ORDER”提示,生活很好。
今天我来了,清理数据库。我归档了大约 20% 的行,除了删除行之外,在相关数据库中没有采取任何行动……执行计划完全被控制。它完全错误地判断了某些子树将返回多少行,并且(例如)替换了一个:
<Hash>
Run Code Online (Sandbox Code Playgroud)
和
<NestedLoops Optimized='false' WithUnorderedPrefetch='true'>
Run Code Online (Sandbox Code Playgroud)
现在查询时间从大约 0.3 秒飙升到大约 18 秒。(!) 只是因为我删除了行。如果我删除查询提示,我将回到大约 2 秒的查询时间。更好,但更糟。
将数据库恢复到多个位置和服务器后,我重现了该问题。简单地从每个表中删除大约 20% 的行总是会导致这个问题。
如果您想查看执行计划,请建议我可以发布它们的位置。否则,我已经采样了最令人惊叹的一点。这是基本的错误估计,括号中的数字是(估计:实际)行。
/ Clustered Index Scan (908:7229)
Nested Loops (Inner Join) --<
\ NonClustered Index Seek (1:7229)
Run Code Online (Sandbox Code Playgroud)
请注意,内循环预期扫描 908 行,但扫描 52,258,441。如果它是准确的,这个分支会运行大约 2 毫秒,而不是 12 秒。在删除行之前,这个内部连接估计值仅相差 2 倍,并且作为两个聚集索引的哈希匹配执行。
performance sql-server-2008 sql-server optimization hints query-performance
我正在研究使用READPAST提示来减少我们应用程序财务子系统中的资源锁定。
这似乎是一个不错的方法,因为金融交易记录只会被添加,不会被更新或删除。唯一会被跳过的行是插入事务中的全新行;在事务提交之前,它们实际上不存在于外部世界。
但是,我注意到使用我已READPAST提示的索引视图的查询性能较差。比较查询计划,通过提示,查询优化器选择不使用索引视图,而是退回到将其视为常规视图。
我不确定为什么会这样;我想索引视图就像任何其他索引一样,因为键可以在操作期间被锁定,并且添加的READPAST工作方式类似。
SELECT TOP 1 isa.InvoiceId
FROM Financial_InvoiceSummaryAmounts isa WITH (READPAST)
WHERE isa.TotalOwedAmount = 0.0
Run Code Online (Sandbox Code Playgroud)
SELECT TOP 1 isa.InvoiceId
FROM Financial_InvoiceSummaryAmounts isa
WHERE isa.TotalOwedAmount = 0.0
Run Code Online (Sandbox Code Playgroud)
添加NOEXPAND提示似乎也有效,但我有兴趣了解更多关于可能READPAST导致查询优化器首先做出该选择的原因(作为完整答案的一部分)。
performance sql-server hints materialized-view query-performance
从SQL Server 2008 开始的From 子句文档简要提到了 3 个连接提示及其基本机制:
然而,似乎没有太多关于何时可能需要使用它们的信息。
似乎它们可以与散列、循环和合并结合使用,这些已经被理解为这个问题的目的。
文档中的相关部分:
对于 SQL 数据仓库和并行数据仓库,这些联接提示适用于两个分布不兼容的列上的 INNER 联接。它们可以通过限制查询处理期间发生的数据移动量来提高查询性能。SQL 数据仓库和并行数据仓库的允许连接提示如下:
REDUCE
减少要为联接右侧的表移动的行数,以使两个分布不兼容的表兼容。REDUCE 提示也称为半连接提示。REPLICATE
将连接左侧表的连接列中的值复制到所有节点。右侧的表连接到这些列的复制版本。REDISTRIBUTE
强制将两个数据源分布在 JOIN 子句中指定的列上。对于分布式表,Parallel Data Warehouse 会执行shuffle move。对于复制表,并行数据仓库将执行修剪移动。要了解这些移动类型,请参阅并行数据仓库产品文档中“了解查询计划”主题中的“DMS 查询计划操作”部分。当查询计划使用广播移动来解决分发不兼容的连接时,此提示可以提高性能。
join sql-server hints sql-server-pdw azure-sql-data-warehouse
这是 2 个问题中的第 1 个问题,与 OPTION (FAST 1);
我们刚刚将 ERP 数据库从 SQL 2000 EE 升级到 2008 R2 EE,我们注意到数据库中的阻塞有所增加。我已将其范围缩小到我认为是供应商代码中的违规语句,即:
SELECT MAX(column)
FROM [table]
WHERE <condition>
OPTION (FAST 1);
Run Code Online (Sandbox Code Playgroud)
spid 留下一个打开的事务并锁定表,阻塞所有其他客户端。但是,调用客户端似乎不再与服务器交互以告诉服务器它已收到结束会话的数据。
阅读有关 Query Hints的文档,我看到了这个声明
FAST number_rows
指定为快速检索第一个 number_rows 优化查询。这是一个非负整数。返回第一个 number_rows 后,查询将继续执行并生成其完整结果集。
这让我想知道客户端是否以某种方式中断了通信,服务器是否会保持事务打开,n在返回第一行后处理完整的结果集并使事务保持打开状态?该流程是一个内部流程,因此我无法真正看到最终用户执行会话来执行此操作,而且这并不是每次发生内部流程时都会发生的事情。但是,它只被内部进程使用。
阅读了Remus对 SO的回答后,对于查询的简单性来说,这似乎是矫枉过正。查看查询,如果他们从未分组的结果中收到更多的结果,MAX那么事情就很可疑了。
因此,当我准备与供应商合作时,我想知道是否可以开始准确地将我们的阻塞问题归结为正在使用此查询提示的事实。
请随时编辑/请求编辑,因为我知道这实际上可能不清楚。
Microsoft建议OPTION (QUERYTRACEON 9481)对在兼容性级别 120 下运行的 SQL Server 2014 数据库性能“降低”的查询使用。
在我的情况下,“降级”意味着从几秒钟到几分钟或更长时间。性能方面,9481 工作得非常好;然而,普通用户会得到一个很好的错误而不是查询结果(运行 SSRS 报告):
User 'xxxxx' does not have permission to run DBCC TRACEON.
Run Code Online (Sandbox Code Playgroud)
该文档表明用户必须是 sysadmin 角色的成员才能运行DBCC TRACEON。
是否有任何解决方法可以允许非系统管理员运行使用此提示的查询?
我宁愿不将兼容性级别降低回 110,因为我们的大多数查询都可以接受或工作得更好。
我正在尝试将远程视图中的几行加入本地表。该视图有大约 3 亿行,所以我想使用 REMOTE 查询提示,以便不必将所有 300 万行传输到我的计算机。
SELECT R.Something, L.ID, L.Something
FROM [dbo].[LocalTable] L
INNER JOIN (
SELECT TOP 100 Something, L_ID FROM [RemoteServer].[RemoteDB].[dbo].[RemoteTable]
) R
ON L.ID = R.L_ID
Run Code Online (Sandbox Code Playgroud)
正如我所料,这将返回 100 行,并且基本上不需要时间,正如我所料。
然而,
SELECT R.Something, L.ID, L.Something
FROM [dbo].[LocalTable] L
INNER REMOTE JOIN (
SELECT TOP 100 Something, L_ID FROM [RemoteServer].[RemoteDB].[dbo].[RemoteTable]
) R
ON L.ID = R.L_ID
Run Code Online (Sandbox Code Playgroud)
开始返回数千行。几秒钟后我退出了它,但它是数万 - 数十万。
查询提示如何更改我的结果集?
我从其他问题和帖子中知道,当 SQL 编译查询计划时,它只能使用过滤索引,前提是保证每次查询运行时都可以使用过滤索引。这意味着您不能在 where 子句中使用变量,因为有时它可能能够使用过滤索引,有时则不能。
解决此问题的一种方法是使用OPTION(RECOMPILE),以便它可以使用它的次数,它将获得过滤后的索引。
做一些测试,我发现这个查询可以使用过滤索引(注意,我强制使用索引只是为了证明一个观点):
SELECT MAX(table1.SomeDateField)
FROM dbo.table1 WITH(INDEX(MyFilteredIndex))
WHERE table1.filteredColumn = @variable
OPTION (RECOMPILE)
Run Code Online (Sandbox Code Playgroud)
但是,如果我想将结果分配给一个变量,我就不走运了:
SELECT @OutputVariable = MAX(table1.SomeDateField)
FROM dbo.table1 WITH(INDEX(MyFilteredIndex))
WHERE table1.filteredColumn = @variable
OPTION (RECOMPILE)
Run Code Online (Sandbox Code Playgroud)
结果是:
消息 8622,级别 16,状态 1,第 15 行 由于此查询中定义的提示,查询处理器无法生成查询计划。在不指定任何提示且不使用 SET FORCEPLAN 的情况下重新提交查询。
当我不想将输出保存到变量时,查询可以清楚地使用过滤后的索引,因为它运行 find 。
我有办法将此查询重写为硬编码@variable以消除问题,但有人可以解释为什么第一个查询可以使用过滤索引,而第二个查询不能?
我可以理解,如果我加入“单独快速”的单个查询,组合可能会变慢,因为默认执行计划可能不是最佳的。但是,当我知道一个查询的行数非常少时,我想我应该能够使用提示来控制连接。
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_ 或使用交叉应用,它会很快,但我真的必须求助于它吗?如果我使用临时表并尝试“任何”连接提示(循环/合并/散列),它会很慢,所以这可能是一个关键点。
我不相信深入查询计划的深度(两者都是复杂的开始)是解决一般问题所必需的:我只想保证隔离而不诉诸临时表 - 这真的不可能?
hints ×10
sql-server ×9
join ×2
optimization ×2
performance ×2
index ×1
merge ×1
order-by ×1
permissions ×1
t-sql ×1