【问题标题】:What columns generally make good indexes?哪些列通常可以制作好的索引?
【发布时间】:2010-09-11 13:13:01
【问题描述】:

作为我尝试了解索引的“What are indexes and how can I use them to optimise queries in my database?”的后续行动,哪些列是好的索引候选?专门针对 MS SQL 数据库?

经过一番谷歌搜索,我所读到的所有内容都表明,通常会增加且唯一的列是一个很好的索引(例如 MySQL 的 auto_increment 之类的东西),我理解这一点,但我使用的是 MS SQL,并且我正在使用 GUID 作为主键,所以看起来索引不会有利于 GUID 列......

【问题讨论】:

标签: sql-server database optimization database-design indexing


【解决方案1】:

索引可以在查询优化和从表中快速搜索结果中发挥重要作用。所以选择要索引的列是最重要的一步。有两个主要的地方我们可以考虑索引:WHERE 子句中引用的列和 JOIN 子句中使用的列。简而言之,应该为这些列建立索引,您需要根据这些列搜索特定记录。假设我们有一个名为 Buyer 的表,其中 SELECT 查询使用如下索引:

SELECT
 buyer_id /* no need to index */
FROM buyers
WHERE first_name='Tariq' /* consider to use index */
AND last_name='Iqbal'   /* consider to use index */

由于在 SELECT 部分引用了“buyer_id”,MySQL 不会使用它来限制所选行。因此,没有必要对其进行索引。下面是另一个与上面略有不同的示例:

SELECT
 buyers.buyer_id, /* no need to index */
 country.name    /* no need to index */
FROM buyers LEFT JOIN country
ON buyers.country_id=country.country_id /* consider to use index */
WHERE
 first_name='Tariq' /* consider to use index */
AND
 last_name='Iqbal' /* consider to use index */

根据上面的查询 first_name,last_name 列可以被索引,因为它们位于 WHERE 子句中。还可以考虑将来自国家/地区表的附加字段 country_id 用于索引,因为它位于 JOIN 子句中。因此可以考虑对 WHERE 子句或 JOIN 子句中的每个字段进行索引。

以下列表还提供了一些提示,当您打算在表中创建索引时应始终牢记:

  • 仅索引 WHERE 和 ORDER BY 子句中需要的那些列。大量索引列会导致一些缺点。
  • 尝试利用 MySQL 的“索引前缀”或“多列索引”功能。如果您创建索引,例如 INDEX(first_name, last_name),请不要创建 INDEX(first_name)。但是,并非所有搜索情况都建议使用“索引前缀”或“多列索引”。
  • 对您考虑建立索引的列使用 NOT NULL 属性,这样就永远不会存储 NULL 值。
  • 使用 --log-long-format 选项记录不使用索引的查询。通过这种方式,您可以检查此日志文件并相应地调整您的查询。
  • EXPLAIN 语句可帮助您揭示 MySQL 将如何执行查询。它显示了表的连接方式和顺序。这对于确定如何编写优化查询以及是否需要对列进行索引非常有用。

更新(2015 年 2 月 23 日):

任何索引(好/坏)都会增加插入和更新时间。

根据您的索引(索引数量和类型),搜索结果。如果您的搜索时间会因为索引而增加,那么这就是糟糕的索引。

在任何一本书中,“索引页”都可能有章节起始页、主题页码起始页以及子主题页起始页。索引页面中的一些说明会有所帮助,但更详细的索引可能会使您感到困惑或吓到您。索引也有记忆。

索引选择应该是明智的。请记住,并非所有列都需要索引。

【讨论】:

  • 感谢 Somnath,这是否意味着只应为我们计划使用 WHEREJOINSHAVING 的列创建索引?
  • 是的,对您计划使用 WHERE、JOINS 或 HAVING 的列使用索引。但也要记住,所有条件列都不需要索引。有时 where 条件列只使用一次,因此它可能不需要索引,而其他条件列在许多查询中使用,因此更喜欢为该列建立索引。
  • 答案将受益于将“WHERE 子句中引用的列和 JOIN 子句中使用的列”放在 TL;DR 部分中。
  • 所以你的意思是,如果在我的WHERE 子句中我正在检查一个字段的值,而该字段的列只能取两个值,那么我应该索引那个二进制列吗?这似乎是错误的。
  • @AjaxLeung:记住 Knuth 的格言“过早优化是万恶之源。”。您可以在二进制列上创建索引,但它应该取决于成本(如插入、更新时间)。如果您的业务逻辑通常依赖于该二进制开关,则可能需要二进制列具有索引。
【解决方案2】:

有些人在这里回答了类似的问题:How do you know what a good index is?

基本上,这实际上取决于您将如何查询数据。您需要一个能够快速识别与查询相关的一小部分数据集的索引。如果您从不按日期戳查询,则不需要索引,即使它大多是唯一的。如果您所做的只是获取某个日期范围内发生的事件,那么您肯定想要一个。在大多数情况下,性别索引是没有意义的——但如果你所做的只是获取所有男性的统计数据,并且单独获取所有女性的统计数据,那么创建一个索引可能是值得的。弄清楚您的查询模式将是什么,以及访问哪个参数最能缩小搜索空间,这就是您的最佳索引。

还要考虑您创建的索引类型——B 树适用于大多数事情并允许范围查询,但哈希索引可以让您直截了当(但不允许范围)。其他类型的索引各有利弊。

祝你好运!

【讨论】:

    【解决方案3】:

    这完全取决于您希望询问的有关表的查询。如果您要求 X 列具有特定值的所有行,则如果无法使用索引,则必须进行全表扫描。

    如果满足以下条件,索引将很有用:

    • 一个或多个列具有高度的唯一性
    • 您经常需要查找某个值或值范围 列。

    如果出现以下情况,它们将不会有用:

    • 您正在选择表中较大的 % (>10-20%) 行
    • 额外的空间使用是个问题
    • 您希望最大限度地提高插入性能。表上的每个索引都会降低插入和更新性能,因为每次数据更改时都必须更新它们。

    主键列通常非常适合索引,因为它们是唯一的并且经常用于查找行。

    【讨论】:

    • 字符串搜索值可以在字符串内的任何位置可能会使其不使用这些索引。
    【解决方案4】:

    任何将经常用于从表中提取数据的列都应该被索引。

    这包括: 外键 -

    select * from tblOrder where status_id=:v_outstanding
    

    描述性字段 -

    select * from tblCust where Surname like "O'Brian%"
    

    列不需要是唯一的。事实上,在搜索异常时,您可以从二进制索引中获得非常好的性能。

    select * from tblOrder where paidYN='N'
    

    【讨论】:

    • 你明确提到外键确实让我在考虑加入时解决了问题。
    【解决方案5】:

    一般来说(我不使用 mssql,所以不能具体评论),主键是很好的索引。它们是唯一的,并且必须具有指定的值。 (此外,主键可以创建很好的索引,以至于它们通常会自动创建一个索引。)

    索引实际上是已排序的列的副本以允许二进制搜索(这比线性搜索快得多)。数据库系统可能会使用各种技巧来进一步加快搜索速度,尤其是在数据比简单数字更复杂的情况下。

    我的建议是最初不要使用任何索引并分析您的查询。如果某个特定查询(例如按姓氏搜索人员)运行频率很高,请尝试再次在相关属性和配置文件上创建索引。如果查询的速度明显加快,而插入和更新的速度可以忽略不计,请保留索引。

    (抱歉,如果我重复您在另一个问题中提到的内容,我之前没有遇到过。)

    【讨论】:

      【解决方案6】:

      这真的取决于您的查询。例如,如果您几乎只写入表,那么最好不要有任何索引,它们只会减慢写入速度并且永远不会被使用。您用于与另一个表连接的任何列都是索引的理想候选者。

      另外,请阅读缺失索引功能。它监控对您的数据库使用的实际查询,并可以告诉您哪些索引可以提高性能。

      【讨论】:

        【解决方案7】:

        GUID 列不是索引的最佳候选者。索引最适合数据类型的列,该数据类型可以被赋予某种有意义的顺序,即排序(整数、日期等)。

        列中的数据是否普遍增加并不重要。如果您在列上创建索引,索引将创建它自己的数据结构,该结构将简单地引用表中的实际项目,而不考虑存储顺序(非聚集索引)。然后,例如可以对您的索引数据结构执行二进制搜索以提供快速检索。

        还可以创建一个“聚集索引”,对您的数据进行物理重新排序。但是,每个表只能有一个,而您可以有多个非聚集索引。

        【讨论】:

        • 嗯,那并不完全准确。您可以轻松地在 GUID 列上创建常规的非聚集索引 - 为什么不呢?如果您将 GUID 用作集群键(例如,用于 CLUSTERED INDEX),则 GUID 有一个很大的缺点 - 使用起来会很糟糕。
        • 可以Guid上创建索引,但索引将被排序以优化Seek操作。当插入的数据是顺序的(如 IDENTITY 列)时,可以简单地附加索引,碎片风险相对较低,但是Guid 值通常是随机值,这意味着每次新插入都会导致索引碎片化,需要重新排序索引。对于大型数据库,这可能会导致需要主动管理的严重性能或维护问题。使用顺序键而不是 Guid 可以简化长期管理。
        【解决方案8】:

        您的主键应始终是索引。 (事实上​​,如果它没有被 MS SQL 自动索引,我会感到惊讶。)您还应该经常索引您 SELECTORDER 的列;它们的目的是快速查找单个值和更快的排序。

        索引too 许多列的唯一真正危险是减慢对大表中行的更改,因为索引也都需要更新。如果您真的不确定要索引什么,只需对最慢的查询进行计时,查看最常使用哪些列,然后对它们进行索引。然后看看它们的速度有多快。

        【讨论】:

          【解决方案9】:

          按升序或降序排序的数字数据类型是很好的索引,原因有很多。首先,数字通常比字符串(varchar、char、nvarchar 等)计算得更快。其次,如果您的值未排序,则可能需要对行和/或页面进行洗牌以更新您的索引。这是额外的开销。

          如果您使用 SQL Server 2005 并设置使用 uniqueidentifiers (guid),并且不需要它们是随机的,请查看顺序 uniqueidentifier 类型。

          最后,如果您谈论的是聚集索引,那么您谈论的是物理数据的种类。如果你有一个字符串作为你的聚集索引,那可能会很难看。

          【讨论】:

            【解决方案10】:

            ol' 的经验法则是在 WHERE、ORDER BY 和 GROUP BY 子句中经常使用的列,或者在连接中似乎经常使用的任何列。请记住,我指的是索引,而不是主键

            不要给出“普通”的答案,但这确实取决于您访问数据的方式

            【讨论】:

              【解决方案11】:

              如果您使用 GUID,它应该会更快。 假设你有记录

              1. 100
              2. 200
              3. 3000
              4. ....

              如果你有一个索引(二分查找,你可以在 O(lg n) 时间内找到你要查找的记录的物理位置,而不是按顺序查找 O(n) 时间。这是因为你不知道什么表中的记录。

              【讨论】:

                【解决方案12】:

                最佳索引取决于表格的内容以及您要完成的任务。

                举个例子 一个会员数据库,其主键是会员社会保险号。我们选择 S.S. 是因为应用程序主要以这种方式引用个人,但您还想创建一个搜索功能,该功能将利用成员的名字和姓氏。然后我建议在这两个字段上创建一个索引。

                您应该首先找出您将要查询的数据,然后确定您需要索引哪些数据。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2013-03-08
                  • 1970-01-01
                  • 2012-02-29
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-07-28
                  • 1970-01-01
                  • 2011-09-16
                  相关资源
                  最近更新 更多