【发布时间】:2014-11-01 16:50:53
【问题描述】:
我已经阅读了很多关于索引和它们之间的差异的内容。现在我正在我的项目中进行查询优化。我创建了非聚集索引,应该在查询执行时使用,但事实并非如此。详情如下:
表:
索引:
CREATE NONCLUSTERED INDEX [_IXProcedure_Deleted_Date] ON [por].[DailyAsset]
(
[Deleted] ASC,
[Date] DESC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
实体框架生成的查询:
exec sp_executesql N'SELECT
[Project1].[C1] AS [C1],
[Project1].[AssetId] AS [AssetId],
[Project1].[Active] AS [Active],
[Project1].[Date] AS [Date]
FROM ( SELECT
[Extent1].[AssetId] AS [AssetId],
[Extent1].[Active] AS [Active],
[Extent1].[Date] AS [Date],
1 AS [C1]
FROM [por].[DailyAsset] AS [Extent1]
WHERE (0 = [Extent1].[Deleted]) AND ([Extent1].[Date] < @p__linq__0)
) AS [Project1]
ORDER BY [Project1].[Date] DESC',N'@p__linq__0 datetime2(7)',@p__linq__0='2014-05-01 00:00:00'
执行计划:
缺少索引详细信息:
The Query Processor estimates that implementing the following index could improve the query cost by 23.8027%.
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [por].[DailyAsset] ([Deleted],[Date])
INCLUDE ([AssetId],[Active])
我知道,如果将 AssetId 和 Active 列包含在索引中,将使用索引。
现在,为什么不包含列就无法工作?
这是另一个查询的简化示例,其中所有列都作为结果被提取。 (强制)使用索引查找的唯一解决方案是将所有列包含在索引中,这具有相同的估计子树成本(很明显)。
这里另一个烦人的问题是排序无知。日期列在索引中并设置为 DESCENDING。它被完全忽略了,当然,排序操作在执行计划中占据了昂贵的位置。
更新 1:
正如@Jayachandran 所指出的,IndexSeek + KeyLookUp 应该在上面的查询中使用,但是覆盖索引是有据可查的,它假设应该包括 AssetId 和 Active 列。我同意。
我正在创建 UPDATE 1 以在下面的查询中演示覆盖索引的有用性。同一张表,更大的结果集。据我所知,不应在索引中使用单个列,并且为 Date 和 Deleted 列创建索引。
exec sp_executesql N'SELECT
[Project1].[DailyAssetId] AS [DailyAssetId],
[Project1].[AssetId] AS [AssetId],
[Project1].[CreatedByUserId] AS [CreatedByUserId],
[Project1].[UpdatedByUserId] AS [UpdatedByUserId],
[Project1].[TimeCreated] AS [TimeCreated],
[Project1].[TimeUpdated] AS [TimeUpdated],
[Project1].[Deleted] AS [Deleted],
[Project1].[TimeDeleted] AS [TimeDeleted],
[Project1].[DeletedByUserId] AS [DeletedByUserId],
[Project1].[Active] AS [Active],
[Project1].[Date] AS [Date],
[Project1].[Quantity] AS [Quantity],
[Project1].[TotalBookValue] AS [TotalBookValue],
[Project1].[CostPrice] AS [CostPrice],
[Project1].[CostValue] AS [CostValue],
[Project1].[FairPrice] AS [FairPrice],
[Project1].[FairValue] AS [FairValue],
[Project1].[UnsettledQuantity] AS [UnsettledQuantity],
[Project1].[UnsettledValue] AS [UnsettledValue],
[Project1].[SettlementDate] AS [SettlementDate],
[Project1].[EffectiveDate] AS [EffectiveDate],
[Project1].[PortfolioId] AS [PortfolioId]
FROM ( SELECT
[Extent1].[DailyAssetId] AS [DailyAssetId],
[Extent1].[AssetId] AS [AssetId],
[Extent1].[CreatedByUserId] AS [CreatedByUserId],
[Extent1].[UpdatedByUserId] AS [UpdatedByUserId],
[Extent1].[TimeCreated] AS [TimeCreated],
[Extent1].[TimeUpdated] AS [TimeUpdated],
[Extent1].[Deleted] AS [Deleted],
[Extent1].[TimeDeleted] AS [TimeDeleted],
[Extent1].[DeletedByUserId] AS [DeletedByUserId],
[Extent1].[Active] AS [Active],
[Extent1].[Date] AS [Date],
[Extent1].[Quantity] AS [Quantity],
[Extent1].[TotalBookValue] AS [TotalBookValue],
[Extent1].[CostPrice] AS [CostPrice],
[Extent1].[CostValue] AS [CostValue],
[Extent1].[FairPrice] AS [FairPrice],
[Extent1].[FairValue] AS [FairValue],
[Extent1].[UnsettledQuantity] AS [UnsettledQuantity],
[Extent1].[UnsettledValue] AS [UnsettledValue],
[Extent1].[SettlementDate] AS [SettlementDate],
[Extent1].[EffectiveDate] AS [EffectiveDate],
[Extent1].[PortfolioId] AS [PortfolioId]
FROM [por].[DailyAsset] AS [Extent1]
WHERE (0 = [Extent1].[Deleted]) AND ([Extent1].[Date] < @p__linq__0)
) AS [Project1]
ORDER BY [Project1].[Date] DESC',N'@p__linq__0 datetime2(7)',@p__linq__0='2014-05-01 00:00:00'
【问题讨论】:
-
我猜是因为选择包括 AssetId 和 Active 列。所以使用索引不会得到所有需要的数据。因此它强制扫描。将这些列添加到索引将使选择仅通过索引搜索获取所有数据。一旦你强制索引搜索,排序问题就会自行解决。目前没有使用您的索引,因此索引中的排序日期没有相关性。
-
是的,但正如我在 and 中所写,假设我们正在选择所有列(这些查询确实存在于我的项目中,在同一张表上)而不仅仅是这三个。那么,我应该在索引中包含所有列吗?这既不实用也不有用..我认为。
-
它应该是一个没有覆盖索引的带有键查找的索引搜索。不确定为什么您的执行计划假设索引扫描比这便宜,但出于某种原因它确实如此;可能是不正确的统计数据或其他东西。但是是的,覆盖索引是一种有据可查的查询调优方法。
-
我会在索引中交换 Date 和 Deleted。
-
@Jayachandran:我已经用 UPDATE 1 编辑了我的问题。我对覆盖索引语句是否正确?
标签: sql sql-server non-clustered-index