对于我尝试优化的中等复杂查询,我注意到删除TOP n
子句会更改执行计划。我猜想,当查询包含TOP n
数据库引擎时,会运行查询而忽略该TOP
子句,然后最后将结果集缩小到请求的n行数。图形执行计划似乎表明情况确实如此——TOP
是“最后”一步。但似乎还有更多事情发生。
我的问题是,TOP n 子句如何(以及为什么)影响查询的执行计划?
这是我的情况的简化版本:
查询匹配来自两个表 A 和 B 的行。
如果没有该TOP
子句,优化器估计将有来自表 A 的 19k 行和来自表 B 的 46k 行。返回的实际行数是 A 的 16k 和 B 的 13k。哈希匹配用于连接这两个结果集总共 69 行(然后应用排序)。此查询发生得非常快。
当我添加TOP 1001
优化器时不使用哈希匹配;相反,它首先对表 A 的结果进行排序(与 19k/16k 相同的估计值/实际值)并对表 B 执行嵌套循环。表 B 的估计行数现在为 1,奇怪的是TOP n
直接影响对 B 的估计执行次数(索引搜索) - 它似乎总是2n+1,或者在我的情况下是 2003 年。如果我改变,这个估计会相应地改变TOP n
。当然,由于这是嵌套连接,因此实际执行次数为 16k(表 A 中的行数),这会减慢查询速度。
实际场景有点复杂,但这捕获了基本思想/行为。两个表都使用索引查找进行搜索。这是 SQL Server 2008 R2 企业版。
performance sql-server optimization execution-plan query-performance
这是破败:我在做一个选择查询。WHERE
andORDER BY
子句中的每一列都在一个非聚集索引中IX_MachineryId_DateRecorded
,或者作为键的一部分,或者作为INCLUDE
列。我正在选择所有列,因此将导致书签查找,但我只使用TOP (1)
,因此服务器肯定会告诉查找只需要在最后完成一次。
最重要的是,当我强制查询使用 index 时IX_MachineryId_DateRecorded
,它会在不到一秒的时间内运行。如果我让服务器决定使用哪个索引,它会选择IX_MachineryId
,并且最多需要一分钟。这真的向我表明我已经正确地建立了索引,而服务器只是做出了一个错误的决定。为什么?
CREATE TABLE [dbo].[MachineryReading] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Location] [sys].[geometry] NULL,
[Latitude] FLOAT (53) NOT NULL,
[Longitude] FLOAT (53) NOT NULL,
[Altitude] FLOAT (53) NULL,
[Odometer] INT NULL,
[Speed] FLOAT (53) NULL,
[BatteryLevel] INT NULL,
[PinFlags] BIGINT NOT NULL,
[DateRecorded] DATETIME NOT NULL,
[DateReceived] DATETIME NOT NULL,
[Satellites] INT NOT NULL,
[HDOP] FLOAT …
Run Code Online (Sandbox Code Playgroud) 作为这个关于提高查询性能的问题的后续,我想知道是否有办法让我的索引默认使用。
此查询在大约 2.5 秒内运行:
SELECT TOP 1000 * FROM [CIA_WIZ].[dbo].[Heartbeats]
WHERE [DateEntered] BETWEEN '2011-08-30' and '2011-08-31';
Run Code Online (Sandbox Code Playgroud)
这个运行在大约 33 毫秒内:
SELECT TOP 1000 * FROM [CIA_WIZ].[dbo].[Heartbeats]
WHERE [DateEntered] BETWEEN '2011-08-30' and '2011-08-31'
ORDER BY [DateEntered], [DeviceID];
Run Code Online (Sandbox Code Playgroud)
[ID] 字段 (pk) 上有一个聚集索引,[DateEntered],[DeviceID] 上有一个非聚集索引。第一个查询使用聚集索引,第二个查询使用我的非聚集索引。我的问题是两部分: