从索引开始还是何时出现性能问题?


15

我的问题是关于索引的使用。

  1. 我应该从头开始还是在出现性能问题时立即开始索引编制?

  2. 我们还可以在执行查询时创建临时索引。这种技术的优缺点是什么?

Answers:


17

我应该从头开始还是在出现性能问题时立即开始索引编制?

随着使用模式的出现,索引策略趋向于发展。也就是说,还有一些策略和设计准则可以预先应用。

  • 选择一个好的群集密钥。通常,您可以在设计时根据对表的插入的预期模式来确定适当的聚簇索引。如果有令人信服的理由要求将来做出改变,那就这样吧。

  • 创建您的主要约束和其他独特约束。这些将由唯一索引强制执行。

  • 创建您的外键和关联的非聚集索引。外键是您最常引用的联接列,因此从一开始就对其进行索引。

  • 为任何显然高度选择性的查询创建索引。对于查询模式,您已经知道它将具有很高的选择性,并且很可能使用查找而不是扫描。

除上述之外,请采用渐进的整体方法来实施新索引。整体而言,我的意思是在评估添加项时评估对所有查询和现有索引的潜在收益和影响。

由于缺少索引DMV和SSMS提示的指导,SQL Server圈中的一个常见问题是过度索引。这些工具都不会对现有索引进行评估,并且会建议您创建一个新的6列索引,而不是向现有的5列索引添加单个列。

-- If you have this
CREATE NONCLUSTERED INDEX [IX_MyTable_MyIndex] ON [dbo].[MyTable] 
(
    [col1] ASC
    , [col2] ASC
    , [col3] ASC
    , [col4] ASC
    , [col5] ASC
)

-- But your query would benefit from the addition of a column
CREATE NONCLUSTERED INDEX [IX_MyTable_MyIndex] ON [dbo].[MyTable] 
(
    [col1] ASC
    , [col2] ASC
    , [col3] ASC
    , [col4] ASC
    , [col5] ASC
    , [col6] ASC
)

-- SSMS will suggest you create this instead
CREATE NONCLUSTERED INDEX [IX_MyTable_AnotherIndexWithTheSameColumnsAsTheExistingIndexPlusCol6] ON [dbo].[MyTable] 
(
    [col1] ASC
    , [col2] ASC
    , [col3] ASC
    , [col4] ASC
    , [col5] ASC
    , [col6] ASC
)

金伯利·特里普(Kimberly Tripp)拥有一些出色的索引策略材料,而SQL侧重于索引策略也适用于其他平台。对于SQL Server专家来说,有一些方便的工具可用于识别重复项,例如上面的示例。

我们还可以在执行查询时创建临时索引。这种技术的优缺点是什么?

这通常仅适用于很少运行的查询,通常是ETL。您需要评估:

  1. 创建索引所花费的时间是否减少了查询的执行时间。
  2. 将索引保留在原处的维护开销是否超过了在需要时创建/删除索引所花费的时间。

3
+1群集键,外键,唯一/主键,并且不信任以面值计的缺失索引DMV ...所有这些都是不错的建议。使用sys.dm_db_index_usage_stats DMV,在SQL Server中处理现有索引非常容易。在一段时间内,您可以列出尚未扫描或查找的索引,同时还可以看到这些相同的索引已被更新多次。这表明过度索引。
Matt M

1
+1,但是“为任何显然高度选择性的查询创建索引”。不涵盖所有其他情况。索引可以帮助对结果进行排序,即使您的查询不是高度选择性的。如果它们覆盖所有选定的列,它们还可以加快查询速度。
不合理

1
同意,但问题是要寻找起点而不是终点。没有使用模式,很难确定要覆盖的查询,因为您几乎无法全部覆盖它们。
Mark Storey-Smith

8

这两种方法确实存在风险:

选项a)从一开始就建立索引,但没有意识到您已经创建了许多从未使用过的索引。这些增加了一些开销(最显着的是修改数据的查询,但同时还通过优化SELECT语句来尝试确定最佳索引)。

您将需要训练自己以识别不再使用的索引并尝试将其删除(PostgreSQL可以做到这一点;不幸的是,相比之下,MySQL的功能非常弱。)

选项b)在人们开始抱怨之前,否则不要添加索引,否则您的诊断工具会触发某些查询速度很慢并且可以改进的查询。

引入的风险是,从发现需要索引到必须添加索引之间的时间窗口不够长。

PostgreSQL确实支持构建索引CONCURRENTLY,这确实减轻了这种突然添加索引的压力,但是手册中有一些注意事项


选项(b)通常是我的偏爱,但我认为将这两种选项混合使用可能是最好的解决方案。这与您是否认为实际使用索引有关的置信度有关。

使得该讨论特别复杂的是,更改索引通常很容易,但是更改架构则更困难。我不想提倡b 的延迟反应是鲁re的借口。


4

除了马克的答案

您可以通过获得预期数量的真实测试数据来体会。我已经看到很多(很多)查询可以运行1000行但没有生产百万行的情况。

如果可以的话,以后再制作副本,

当然,我在生产中看到了奇怪的问题,因为在其他所有方面相同的情况下使用模式

临时索引?在ETL加载模式之外,如果一次需要它们,则将再次需要它们。不要忘记:索引的创建/删除是一次写入并被记录=更多负载


3

只是添加一些东西。

  • 临时索引是一个糟糕的主意。除非索引位于临时表上。
  • 索引占用的数据空间(以及其他开销)比人们意识到的要多得多。因此,请保守地创建它们。

这是我的方法。

  1. 与Mark类似,在有意义的地方创建索引,但不要过期。
  2. 您不必等到性能变慢才能创建新索引。每当您编写新的SQL时,都应运行查询计划(最好针对prod数据库)。您应该能够查看是否需要新索引。
  3. 不要害怕在未使用的列中放置> 0或放置> ""在where子句中。

    1. 即,假设您在A,B,C和D上有一个索引。但是,您只有信息A,B,D。没有理由您不能-
    select * from blah 
    where A="one" 
    and B="two" 
    and C>=""     --to match index
    and D="four"
    
    --This will use your existing index. No need to create a redundant one.

另一件事,这是在“ dba”论坛中,但是创建索引实际上应该是开发人员的责任,而不是dba的责任。(对于它们完全分开的情况。)
user606723,2011年

2
您关于索引占用的空间的声明有些误导,非聚集索引的开销很小。如果您可以在这一点上提出问题,则值得进一步探讨。其次,我不同意索引创建是开发人员的职责。这是开发人员与DBA之间的协作可以产生最佳结果的很多领域之一。
Mark Storey-Smith,

1
我将举一个我们表的例子。表格大小:21052404 KB。该表上一个非聚集索引的大小:6637470 KB。开销很少?我觉得不是。此外,我并不是说不应该与DBA合作,而是要确定是否需要创建新索引是开发人员的责任。他们不应该编写SQL并期望dbas自己解决这个问题。
user606723 2011年

1
没有上下文,您不能引用这样的数字。如果不指定NC索引列和聚簇键,就无法计算开销与数据的比例。
Mark Storey-Smith

感动。键为[数字(24),字符,日期],NC列为[日期,数字(24)]。(在此特定索引中只有两列)。
2011年

2

我将尝试仅回答第一个问题。如果您可以从一开始就大致估计出一定时间后表中将有多少条记录,那比从头开始设计一些索引要好。尝试使用一些测试工具或测试脚本,这些工具或测试脚本将自动执行您认为最常使用的应用程序调用的尽可能多的调用,并且您将从一开始就可以避免使用哪些表扫描。

一开始这将是一个猜测,但是随着时间的流逝,有了正确的使用统计,您的形象就会更加清晰。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.