The*_*war 5 performance sql-server optimization query-performance
这个问题来自 SO,如果它移动到 DBA.SE ..
下面是测试数据:
--Main Table
CREATE TABLE [dbo].[LogTable]
(
[LogID] [int] NOT NULL
IDENTITY(1, 1) ,
[DateSent] [datetime] NULL,
)
ON [PRIMARY]
GO
ALTER TABLE [dbo].[LogTable] ADD CONSTRAINT [PK_LogTable] PRIMARY KEY CLUSTERED ([LogID]) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_LogTable_DateSent] ON [dbo].[LogTable] ([DateSent] DESC) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_LogTable_DateSent_LogID] ON [dbo].[LogTable] ([DateSent] DESC) INCLUDE ([LogID]) ON [PRIMARY]
GO
--Cross table
CREATE TABLE [dbo].[LogTable_Cross]
(
[LogID] [int] NOT NULL ,
[UserID] [int] NOT NULL
)
ON [PRIMARY]
GO
ALTER TABLE [dbo].[LogTable_Cross] WITH NOCHECK ADD CONSTRAINT [FK_LogTable_Cross_LogTable] FOREIGN KEY ([LogID]) REFERENCES [dbo].[LogTable] ([LogID])
GO
CREATE NONCLUSTERED INDEX [IX_LogTable_Cross_UserID_LogID]
ON [dbo].[LogTable_Cross] ([UserID])
INCLUDE ([LogID])
GO
-- Script to populate them
INSERT INTO [LogTable]
SELECT TOP 100000
DATEADD(day, ( ABS(CHECKSUM(NEWID())) % 65530 ), 0)
FROM sys.sysobjects
CROSS JOIN sys.all_columns
INSERT INTO [LogTable_Cross]
SELECT [LogID] ,
1
FROM [LogTable]
ORDER BY NEWID()
INSERT INTO [LogTable_Cross]
SELECT [LogID] ,
2
FROM [LogTable]
ORDER BY NEWID()
INSERT INTO [LogTable_Cross]
SELECT [LogID] ,
3
FROM [LogTable]
ORDER BY NEWID()
GO
Run Code Online (Sandbox Code Playgroud)
当我们使用下面的简单查询时,
SELECT DI.LogID
FROM LogTable DI
INNER JOIN LogTable_Cross DP ON DP.LogID = DI.LogID
WHERE DP.UserID = 1
ORDER BY DateSent DESC
Run Code Online (Sandbox Code Playgroud)
查询显示排序
根据我的理解,应该避免排序成本,因为我们有所需的索引
CREATE NONCLUSTERED INDEX [IX_LogTable_DateSent] ON [dbo].[LogTable] ([DateSent] DESC) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
并且深入研究计划显示使用了相同的索引..
我的问题是: 1.
为什么排序成本仍然存在
2. 究竟是什么ordered property is true
意思。
我所做的观察/工作很少:
1.Ordered 属性设置为 false
所以我重写了如下查询
SELECT DI.LogID
FROM LogTable DI
INNER JOIN LogTable_Cross DP ON DP.LogID = DI.LogID
WHERE DP.UserID = 1 and di.datesent is not null
ORDER BY DateSent DESC
Run Code Online (Sandbox Code Playgroud)
像上面那样重写,使有序属性为真,但仍然存在排序
最近,我可以找到 Paul White 的这篇文章:两个索引提示的故事,在这篇文章中,下面的 Point 阐明了为什么会发生这种情况
对于非常大的表,优化器可能会计算出 IAM 驱动的扫描可能比额外排序所消耗的时间节省更多时间,并且将选择具有无序扫描 + 排序特征的计划。这是一种启发式优化:优化器对 inde 的实际碎片级别一无所知
但是这个查询需要排序,它不应该满足 IAM 扫描的条件
如果您需要更多详细信息,请告诉我
在查询计划中,ordered 属性设置为 true 意味着未完成 IAM 驱动的扫描。根据索引定义以逻辑顺序读取数据。
散列连接不保留顺序。您的第一个查询有一个散列连接,因此最后SORT
需要显式连接。避免查询中的排序的一种方法是使用LogTable
作为外部表的嵌套循环连接。在我的机器上,我能够通过各种提示完成此操作:
SELECT DI.LogID
FROM LogTable DI
INNER JOIN LogTable_Cross DP ON DP.LogID = DI.LogID
WHERE DP.UserID = 1
ORDER BY DateSent DESC
OPTION (MAXDOP 1, LOOP JOIN, FORCE ORDER, NO_PERFORMANCE_SPOOL);
Run Code Online (Sandbox Code Playgroud)
这是一个非常低效的查询计划,因为没有在LogTable_Cross
表上定义正确的索引。对该表进行了查找,但只有一个 UserId 列:
过滤LogID
是在连接本身中完成的。我可以创建一个更好地支持我正在寻找的查询计划的索引:
CREATE INDEX IX_LogTable_Cross ON LogTable_Cross (LogID, UserID);
Run Code Online (Sandbox Code Playgroud)
创建该索引并不能保证没有排序的查询计划。SQL Server 可能估计具有排序的计划的成本较低。但是,如果我消除了除 之外的所有提示,LOOP JOIN
那么我会得到一个没有排序的合理高效的查询计划:
归档时间: |
|
查看次数: |
3017 次 |
最近记录: |