【问题标题】:What is the ideal indexing strategy for SQL Server?SQL Server 的理想索引策略是什么?
【发布时间】:2011-03-01 08:57:18
【问题描述】:

我和一个朋友正在开发一个使用 SQL Server 的新项目。在我过去做过的项目中,我总是在 JOIN 或 WHERE 中使用的任何字段上放置索引。

我的朋友仅在需要它们的性能时才添加它们。这个想法是维护索引是有成本的,并且您希望确保支付该成本是值得的。公平地说,有些查询不会经常使用,而且有些表会比其他表更积极地添加。

因此,我正在寻找关于什么是数据库索引的“最佳实践”的建议。什么适合你?

【问题讨论】:

  • 这个问题非常广泛。不要指望简单的答案。如果您了解以下内容,您可以做出更好的有根据的决策:索引结构如何工作、INSERT/UPDATES 如何影响索引、LOCKS 和锁升级的影响、选择性原则、数据访问模式. 但一切都归结为:在任何显着规模的系统中,索引调整都是一个持续的过程,涉及监控、分析、基准测试和实验测试。
  • 附带说明:我想知道你是否真的学到了什么?看起来您只是接受了最接近并支持您个人观点的答案。所以看起来你真的只是在寻找支持你的人。

标签: sql sql-server


【解决方案1】:

我会尽量遵循以下准则:

  • 始终有一个良好的主键/集群键 - 通常是 INT IDENTITY - 避免 GUID 或大型复合 PK/CK。精心选择的 PK/CK 将大大有助于提高整体性能。要彻底了解原因,请阅读 Kimberly Tripp 的所有 blog posts on clustering key 选项。

  • 始终索引所有外键列 - 单独或与其他有意义的列一起;这有助于提高 JOIN 性能

  • 除此之外:少即是多!仅在绝对必须时添加索引 - 观察您的系统,分析您的数据负载,查看性能,微调,再次测量。如果索引有帮助 - 保留它;如果一个索引没有被使用 - 扔掉它

  • 使用手头的 DMV(missing index DMV, and the unused indices DMV)了解哪些索引可能有帮助,哪些索引根本没有被使用...

【讨论】:

    【解决方案2】:

    我个人偏好积极主动的方法:根据您的查询,在需要的地方添加索引。正如您所说,在 JOIN 或 WHERE 中涉及的字段上。每个索引都会加速读取查询,但会减慢写入速度(因为每次写入都需要更新索引)。因此,对于写入密集型表,可能需要其他解决方案(数据仓库、复制...)。

    另一种方法,只在性能需要的地方添加索引,只有在您进行主动监控时才有效,但即便如此也有一些缺点

    • 您将不得不向遇到性能问题的表添加索引。在添加索引时,您的表被锁定 - 这是一个使用率很高的表!
    • 通常在测试时,测试数据比应用程序中的真实数据小几个数量级。瓶颈可能被忽视。

    【讨论】:

    • 如果您使用的表太大以至于担心创建新索引会影响性能(假设是一个没有维护窗口的 24/7 系统?!) i>:那么明显更重要该表不会被多余的索引(甚至可能导致锁定问题)所困。
    【解决方案3】:

    您只想将它​​们放在对它们有大量查询的那些列或列组上。您可以从 SQL Server 获取大量统计信息,以查看正在对您的表运行哪些查询,SQL Server 甚至会建议您没有索引的位置。

    这是一个很好的链接,其中包含一些有用的信息和其他有用信息的链接。 SQL Server Index Checklist and tips

    【讨论】:

      【解决方案4】:

      您的问题没有简单的答案。这一切都归结为桌子的使用。监控表的使用情况会告诉你该怎么做。

      【讨论】:

        【解决方案5】:

        索引最好放置在尽可能唯一的值上。例如,在列的 50% 的值为“A”且该列的另外 50% 的值为“B”的列上放置索引是无用

        这样,表格将在选择正确的值之前扫描至少 50% 的记录

        所以最佳实践是在最独特的列上放置一个索引,并且只在那些用于选择查询的列上放置一个索引。

        示例:如果您要为典型的“登录”创建一个选择,您将在“用户名”列上放置一个索引,以确保用户名是唯一的。

        【讨论】:

        • 我在您撰写评论之前编辑了我的解决方案。我正在阅读它,并确切地看到了您刚才提到的内容。
        • Thumb 规则可能会受到打击 - 索引也可用于检索数据 - 因此,即使您有 50-50 个数据,某些查询也可以从索引中受益 - 例如 COUNT(*) ... WHERE ... = 'A' 必须只读取索引。所以它不一定是无用的。
        【解决方案6】:

        在设计索引时,请遵循以下准则:

        • 对具有大量行的表、在 查询或表中的 WHERE 子句 连接,以及在 ORDER BY 中使用的列 和 GROUP BY 查询。
        • 避免在频繁更新的列上使用不经常使用的索引。在 另外,避免有很多索引 经常更新的表。 否则,你会不必要地增加 您的插入和更新时间 查询。为了提高性能, 最小化的总宽度 索引列。
        • 适当地使用聚集索引和非聚集索引。了解 每个目的并选择正确的 为您的方案键入内容。
        • 使用覆盖索引来减少频繁的查询执行时间 使用的语句。覆盖指数是 具有所有 WHERE 子句中的列 并在查询列选择中。

        根据

        http://msdn.microsoft.com/en-us/library/ff650692.aspx

        【讨论】:

          【解决方案7】:
          select * from sys.dm_db_missing_index_details
          

          了解您的动态管理视图

          然后从这个 URL 去使用这个 sproc http://www.sqlservercentral.com/scripts/Index+Management/63937/

          另外.. homedude 关于“覆盖索引”的说法确保您了解覆盖索引(SQL 2000)和带有 INCLUDE 子句的索引(SQL 2005 和更新版本)之间的区别

          【讨论】:

          • 我找到了这张表,但它是空的。是否需要启用一个选项来填充它?
          • 我从未见过带有空 DMW 的生产服务器。你在开发中这样做吗?另一种方法是使用 SQL 分析器(针对生产)来捕获跟踪,然后使用数据库优化顾问测试此工作负载的性能。我通常确保不会在它运行时将其保存到文件/表中,但是当 SQL 探查器跟踪完成时(当您点击停止时),您可以将跟踪结果保存到表中。我只是认为在跟踪的末尾而不是在跟踪的开头执行此操作要好得多。
          猜你喜欢
          • 1970-01-01
          • 2018-04-11
          • 2021-07-29
          • 2010-10-25
          • 2015-07-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-27
          相关资源
          最近更新 更多