【问题标题】:How to create Index for this scenario in SQL Server?如何在 SQL Server 中为这种情况创建索引?
【发布时间】:2017-06-06 22:53:13
【问题描述】:

对于以下查询,此Item table 的最佳索引是什么

select 
    tt.itemlookupcode,
    tt.TotalQuantity,
    tt.ExtendedPrice,
    tt.ExtendedCost,
    items.ExtendedDescription,
    items.SubDescription1,
    dept.Name,
    categories.Name,
    sup.Code,
    sup.SupplierName

from 
    #temp_tt tt

left join HQMatajer.dbo.Item items
on items.ItemLookupCode=tt.itemlookupcode

left join HQMatajer.dbo.Department dept
ON dept.ID=items.DepartmentID

left join HQMatajer.dbo.Category categories
on categories.ID=items.CategoryID

left join HQMatajer.dbo.Supplier sup
ON sup.ID=items.SupplierID

drop table #temp_tt

我创建了类似的索引

CREATE NONCLUSTERED INDEX [JFC_ItemLookupCode_DepartmentID_CategoryID_SupplierID_INC_Description_SubDescriptions] ON [dbo].[Item]
(
    [DBTimeStamp] ASC,
    [ItemLookupCode] ASC,
    [DepartmentID] ASC,
    [CategoryID] ASC,
    [SupplierID] ASC
)
INCLUDE (   
    [Description],
    [SubDescription1]
)

但是在执行计划中,当我检查选择另一个索引的索引时。该索引只有TimeStamp column。

在这种情况下,该特定表的最佳索引是什么。

【问题讨论】:

  • @Hadi 不幸的是,这个问题太宽泛了,答案因不合格而狭窄的适用性而受到影响。关于索引调优的主题已经写了整本书,如果认为特定的问答作为替代品是很危险的。 (这个问题要具体得多,但仍然过于宽泛。)

标签: sql sql-server stored-procedures indexing


【解决方案1】:

索引中的第一列应该是过滤的一部分,否则索引将不会被使用。在您的索引中,第一列是DBTimeStamp,并且在您的查询中没有被过滤。这就是不使用您的索引的原因。

同样在覆盖索引中您使用了[Description],[SubDescription1],但在查询中您选择了ExtendedDescription,items.SubDescription1,这将产生key/Rid lookup 的额外开销

尝试像这样提醒您的索引

CREATE NONCLUSTERED INDEX [JFC_ItemLookupCode_DepartmentID_CategoryID_SupplierID_INC_Description_SubDescriptions] ON [dbo].[Item]
(
    [ItemLookupCode] ASC,
    [DepartmentID] ASC,
    [CategoryID] ASC,
    [SupplierID] ASC
)
INCLUDE (   
    [ExtendedDescription],
    [SubDescription1]
)

话虽如此,所有仍然优化器都会进行扫描或根据从 Item 表中检索到的数据选择其他索引

【讨论】:

    【解决方案2】:

    没有使用您的索引我并不感到惊讶。 DBTimeStamp 可能具有高度选择性,并且根本不会在您的查询中引用。

    您可能忘记在查询中包含 ORDER BY 子句,该子句旨在引用 DBTimeStamp。但即便如此,您的查询也可能需要扫描整个索引。所以它还不如扫描实际的表。

    使该索引“看起来很诱人”的唯一方法是确保它包含 所有 已使用/返回的列。 IE。您需要添加ExtendedDescription。 这可以提供帮助的原因是索引通常需要比完整表更少的存储空间。所以从磁盘读取速度更快。但是,如果您缺少列(在您的情况下为 ExtendedDescription),那么引擎无论如何都需要对完整表执行额外的查找。

    我无法评论为什么首选 DBTimeStamp 列 - 您没有提供足够的详细信息。但也许是CLUSTERED 索引?

    如果定义如下,您的索引几乎肯定会被使用:

    (
        [ItemLookupCode] ASC --The only thing you're actually filtering by
    )
    INCLUDE (
        /* Moving the rest to include is most efficient for the index tree.
           And by including ALL used columns, there's no need to perform
           extra lookups to the full table.
        */
        [DepartmentID],
        [CategoryID],
        [SupplierID],
        [ExtendedDescription],
        [SubDescription1]
    )
    

    但是请注意,这种“为使用的每个查询找到最佳”的索引策略是不可持续的。

    • 您最好找到适合多个查询的“更窄”索引。
    • 每个索引都会减慢 INSERT 和 UPDATE 查询。
    • 与首选的“较窄”索引相比,此类索引受到更多列的影响。

    索引选择应该关注列的选择性。 IE。给定一个特定值或小范围的值,可能会根据您的查询选择多少百分比的数据?

    在您的情况下,我希望ItemLookupCode 在Items 表中每个项目都是唯一的。换句话说,没有任何包含的索引 应该足够了。但是,由于您要加入一个理论上可能包含所有项目代码的临时表:在某些情况下,无论如何最好扫描CLUSTERED INDEX。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-16
      相关资源
      最近更新 更多