【问题标题】:Do I need to add an Index on ORDER BY field?我需要在 ORDER BY 字段上添加索引吗?
【发布时间】:2013-05-23 10:40:02
【问题描述】:

我有一个类似的查询

$query = "SELECT * FROM tbl_comments WHERE id=222 ORDER BY comment_time";

我需要在comment_time 字段上添加索引吗?

另外,如果我想获取两个日期之间的数据,那么我应该如何构建索引?

【问题讨论】:

  • 奇怪的是,名为 'id' 的列不会是 PK,但除了您是否索引 comment_time 不会影响结果之外,这样做可能会提高性能。见dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
  • 嗯。不确定..但您可能会尝试在查询前添加 EXPLAIN 并查看 INDEX 的影响。此外,获取 2 个值之间的数据称为范围搜索,请查看dev.mysql.com/doc/refman/5.0/en/range-optimization.html 上的 mysql 文档
  • 不幸的是,对此没有是/否的答案——这实际上取决于几个因素,例如表的大小、表中的列数、其他索引数、读取的成本效益/writes 等。最好的办法是尝试查看您的执行计划。关于日期,只需搜索即可 - 但我建议在使用日期时使用 >= 和

标签: php mysql sql database-indexes


【解决方案1】:

从技术上讲,您不需要在每个字段上都使用索引,因为它也可以工作,但是出于性能原因,您可能需要一个或多个。

编辑

这个问题从软件设计之初就知道了。通常,如果您增加程序使用的内存量,则会降低其速度(假设程序编写得很好)。为字段分配索引会增加数据库使用的数据,但会加快搜索速度。如果您不想通过此字段搜索任何内容(您实际上在问题中进行了搜索),则没有必要。

在现代,与磁盘数据大小相比,索引并没有那么大,添加一个或多个应该不是一个坏主意。

通常很难确定“我是否需要索引”。 EXPLAIN 语句 (refer to the manual) 提供了一些帮助。

【讨论】:

  • 但是如果我在comment_time 字段上添加索引会提高性能吗?
  • 我编辑了我的评论,但您将在其他答案中获得更多信息
【解决方案2】:

如果您的 where id 不同,则不必将索引放在 comment_time 上。

【讨论】:

    【解决方案3】:

    关于您的第一个问题,您不必在comment_time 创建索引。如果记录的数量非常大,您将需要索引来加快检索速度。但是对于您的操作,您不需要索引。 对于您的第二个问题,使用这样的 WHERE 子句将对您有所帮助。

    WHERE(comment_time BETWEEN 'startDate' AND 'endDate');
    

    【讨论】:

    • @Strawberry “反逗号”是指单引号吗?的确,它们与倒勾不一样,但是您在哪里看到对倒勾的需求?
    【解决方案4】:

    是的,在使用 ORDER BY 时,索引会为您提供帮助。因为INDEX是一个有序的数据结构,所以请求会执行得更快。

    看这个例子:表 test2 有 3 行。我在 order by 之后使用了 LIMIT 来显示执行的差异。

    DROP TABLE IF EXISTS `test2`;
    CREATE TABLE `test2` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `value` varchar(10) CHARACTER SET utf8 COLLATE utf8_swedish_ci NOT NULL,
      PRIMARY KEY (`id`),
      KEY `ix_value` (`value`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of test2
    -- ----------------------------
    INSERT INTO `test2` VALUES ('1', '10');
    INSERT INTO `test2` VALUES ('2', '11');
    INSERT INTO `test2` VALUES ('2', '9');
    
    -- ----------------------------
    -- Without INDEX
    -- ----------------------------
    
    mysql> EXPLAIN SELECT * FROM test2 ORDER BY value LIMIT 1\G
    *************************** 1. row *************************
               id: 1
      select_type: SIMPLE
            table: test2
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 3
            Extra: Using filesort
    1 row in set (0.00 sec)
    

    MySQL 检查了 3 行以输出结果。 在 CREATE INDEX 之后,我们得到:

    mysql> CREATE INDEX ix_value ON test2 (value) USING BTREE;
    Query OK, 0 rows affected (0.14 sec)
    
    -- ----------------------------
    -- With INDEX
    -- ----------------------------
    
    mysql> EXPLAIN SELECT * FROM test2 ORDER BY value LIMIT 1\G
    *************************** 1. row ***************************
               id: 1
      select_type: SIMPLE
            table: test2
             type: index
    possible_keys: NULL
              key: ix_value
          key_len: 32
              ref: NULL
             rows: 1
            Extra: Using index
    1 row in set (0.00 sec)
    

    现在 MySQL 只使用了 1 行。

    回答收到的 cmets,我尝试了没有 LIMIT 的相同查询:

    -- ----------------------------
    -- Without INDEX
    -- ----------------------------
    
    mysql> EXPLAIN SELECT * FROM test2 ORDER BY value\G
    *************************** 1. row ******************
               id: 1
      select_type: SIMPLE
            table: test2
             type: ALL
    possible_keys: NULL
              key: NULL
          key_len: NULL
              ref: NULL
             rows: 3
            Extra: Using filesort
    
    -- ----------------------------
    -- With INDEX
    -- ----------------------------
    
    mysql> EXPLAIN SELECT * FROM test2 ORDER BY value\G
    *************************** 1. row *****************
               id: 1
      select_type: SIMPLE
            table: test2
             type: index
    possible_keys: NULL
              key: ix_value
          key_len: 32
              ref: NULL
             rows: 3
            Extra: Using index
    

    正如我们所见,它使用索引来表示第二个ORDER BY

    要在您的字段上建立索引,请使用:

    CREATE INDEX ix_comment_time ON tbl_comments (comment_time) USING BTREE;
    

    http://dev.mysql.com/doc/refman/5.0/en/create-index.html

    【讨论】:

    • 这是否构成“证明”?
    • @Strawberry 解释一下,你是什么意思。
    • 你的解释是否证明'index will help you, when using ORDER BY'?
    • @Strawberry 是的,因为如果您在创建索引之前查看说明,它会显示:“额外:使用文件排序”。之后 - “使用索引”。当 MySQL 不能使用索引来产生排序结果时,它必须自己对行进行排序。它可以在内存或磁盘上执行此操作,但它始终将此过程称为文件排序(取自高性能 MySQL)。所以,第二种情况它不会对记录进行排序,请求必须执行得更快。
    • @NiklasModess 这是正确的,但对于具有LIMIT 的查询。如果要订购整个表,则可能不使用索引。 MySQL 可能会(明智地)选择检索整个表并进行排序。
    【解决方案5】:

    为了提高检索数据的速度,您需要索引。这也适用于 out 索引。对于第二个问题,您可以使用 WHEREBETWEEN 子句。

    参考:http://www.w3schools.com/sql/sql_between.asp

    【讨论】:

      【解决方案6】:

      EXPLAIN 语句在这种情况下非常有用。对于您的查询,您可以按如下方式使用它:

      EXPLAIN SELECT * FROM tbl_comments WHERE id=222 ORDER BY comment_time
      

      这将输出正在使用哪些索引来执行查询,并允许您使用不同的索引进行实验以找到最佳配置。为了加快排序,您将需要一个 BTREE 索引,因为它以排序方式存储数据。为了加快查找具有特定 id 的项目,HASH 索引是更好的选择,因为它提供了相等谓词的快速查找。请注意,MySQL 可能无法使用这两个索引的组合来执行您的查询,而是只使用其中一个。

      更多信息:http://dev.mysql.com/doc/refman/5.7/en/using-explain.html

      对于范围谓词,例如日期范围内的日期,BTREE 索引将比 HASH 索引执行得更好。

      更多信息:http://dev.mysql.com/doc/refman/5.7/en/create-index.html

      【讨论】:

        【解决方案7】:

        comment_time 字段上的索引对于这样的查询可能根本没有帮助:

        SELECT *
        FROM tbl_comments
        WHERE id=222
        ORDER BY comment_time;
        

        查询需要扫描表以找到匹配的id 值。它可以通过扫描索引、查找行和进行测试来做到这一点。如果有一行匹配,并且它有highext comment_time,那么这需要扫描索引并读取表。

        没有索引,它会扫描表,找到行,然后非常快速地对 1 行进行排序。表的顺序扫描通常比索引扫描后的页面查找更快(并且在大于可用内存的表上肯定会更快)。

        另一方面,id, comment_time 上的索引会很有帮助。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-02-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-13
          • 1970-01-01
          • 2012-03-12
          • 2016-03-06
          相关资源
          最近更新 更多