【问题标题】:Multiple indexes or covering indexes and with includes?多个索引或覆盖索引和包含?
【发布时间】:2020-11-12 21:14:21
【问题描述】:

我有一个大型程序,它在包含大约 5000 万条记录的表上执行大量更新和选择,查询计划显示缺少索引会有所帮助:

缺失索引(影响 89.4367):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLA]) 包括 ([UserId],[Price])

缺失索引(影响 90.7279):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLB]) 包括 ([UserId],[Price])

缺失索引(影响 90.4069):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter][COLC]) 包括 ([UserId],[Price])

缺失索引(影响 90.6373):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLD]) 包括 ([UserId],[Price])

缺失索引(影响 88.774):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLE]) 包括 ([UserId],[Price])

缺失索引(影响 89.9133):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLF]) 包括 ([UserId],[Price])

缺失索引(影响 90.1297):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLF]) 包括 ([UserId],[Price])

缺失索引(影响 76.6554):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLG]) 包括 ([UserId],[Price])

缺失索引(影响 90.9105):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLH]) 包括 ([UserId],[Price])

缺失索引(Impact 84.1814):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLI]) 包括 ([UserId],[Price])

缺失索引(影响 89.3511):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLJ]) 包括 ([UserId],[Price])

缺失索引(影响 90.3087):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLK]) 包括 ([UserId],[Price])

缺失索引(影响 90.6367):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLL]) 包括 ([UserId],[Price])

缺失索引(影响 75.6598):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLM]) 包括 ([UserId],[Price])

缺失索引(影响 82.8915):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLN]) 包括 ([UserId],[Price])

缺少索引(影响 88.2316):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLO]) 包括 ([UserId],[Price])

缺失索引(影响 81.9138):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLP]) 包括 ([UserId],[Price])

缺失索引(Impact 80.1902):CREATE NONCLUSTERED INDEX [] ON [dbo].[myTable] ([Category],[Quarter],[COLP]) 包括 ([UserId],[Price])

我的问题是我应该:

  1. 创建它建议的所有索引

  2. 创建一个包含所有列的覆盖索引,例如

CREATE NONCLUSTERED INDEX indexA 
ON [dbo].[myTable] ([Category], [Quarter], [COLA], [COLB], [COLC], [COLD], [COLE], [COLF], 
                    [COLG], [COLH], [COLI], [COLJ], [COLK], [COLL], [COLM], [COLN], [COLO], [COLP])  
INCLUDE ([UserId],[Price])  
  1. 使用包含中的所有列创建索引,例如
CREATE NONCLUSTERED INDEX indexB 
ON [dbo].[myTable] ([Category], [Quarter])   
INCLUDE ([COLA], [COLB], [COLC], [COLD], [COLE], [COLF], [COLG], [COLH], [COLI],
         [COLJ], [COLK], [COLL], [COLM], [COLN], [COLO], [COLP], [UserId], [Price])
  1. 其他组合?

我知道对此可能没有确切的答案,但您会推荐哪个以及为什么?

【问题讨论】:

  • 如果没有关于您运行的实际查询的信息,一切都是假设。人们就这个主题写了整本书。
  • 我明白,但实际上有大约 250 个插入和相似数量的选择来寻找各种问题,我无法将它们全部包含在这里,所以只需要一个理论上的答案。

标签: sql-server indexing


【解决方案1】:

添加索引的主要问题是它们会减慢数据更新操作(插入、删除、更新),因为索引也需要更新。

虽然这个答案是基于意见的,但 imo 有一个主要考虑因素 - 表多久更新一次(例如,新的插入/更新/删除)?

  • 如果没有更新(或只有手动),则根据需要创建尽可能多的索引 - 这可以针对参考表等进行。但这不是 imo 参考表。
  • 或者,如果是数据仓库表,有数据加载,然后每天完成索引重建,也是可行的
  • 另一方面,如果它有很多更新,例如,一次加载一个事务或小批量加载,那么更多索引会降低这些更新的性能
    • 因此,我通常非常反对在事务表上使用许多非聚集索引(以及过宽的索引)

注意索引,主索引中只能有一定数量的字节(尽管包含字段可以更长)。因此,所有字段的索引可能不可行。此外,将所有这些字段作为索引的一部分可能无济于事——当它需要(比如)ColB 时,数据已经按 ColA 排序——因此无论如何它都需要再次读取整个索引。

就个人而言,我建议从[Category],[Quarter],[COLA] 的索引开始,然后包括所有其他字段。如果使用更频繁,您可以将 ColA 替换为任何其他列。它提供了

  • ColA 部分的一个很好的索引,因为它提供了所有需要的信息(覆盖索引)并且排序正确,并且
  • 其他部分的覆盖索引

它仍然需要进行索引扫描,但值得一试。看看这是否可以将您的查询速度提高到可接受的水平。

但请注意,如果您已经拥有

  • [Category],[Quarter] 上的聚集索引和
  • 其他字段中的少量数据(例如,表中没有 varchar(2000) 字段但未使用)

...那么非聚集索引可能没有多大帮助。

类似地,取决于您可以对表执行的其他操作,如果聚集索引在[Category],[Quarter] 上不是,那么您可能想要这样做。但请注意,如果有其他任何东西使用此表,您可能会迫使其表现不佳。

【讨论】:

  • 很好的答案,谢谢。该表是每天运行一次的一部分,因此它会执行大量插入和大量读取,然后在所有数据都进入并且查找问题的 select 语句运行后很少触及。
  • 哦 - 那是另一回事。创建索引需要CPU在创建时对数据进行排序。另一方面,如果您的查询只运行一次(寻找问题),那么可能根本不值得添加索引/es,因为总处理仍然是相似的。值得计算创建索引所需的时间与通过拥有它在查询上节省多少(另请注意,标准版 SQL Server 中的索引创建将高级锁定表; SELECT 可能只会放一个低级锁就可以了)。
  • 对不起,我的意思是每天只运行一次而不是只运行一次,我认为听起来至少有 1 个索引会有所帮助,但我认为我只需要在有无索引的情况下进行测试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-22
  • 2011-02-19
相关资源
最近更新 更多