【问题标题】:MySql doesn't use index with ORDER BYMySql 不使用带有 ORDER BY 的索引
【发布时间】:2012-04-15 13:30:14
【问题描述】:

我有一个具有这种结构的表(有 50k 个字段):

CREATE TABLE IF NOT EXISTS `comments` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `imageid` int(10) unsigned NOT NULL DEFAULT '0',
  `uid` bigint(20) unsigned NOT NULL DEFAULT '0',
  `content` text CHARACTER SET utf8,
  `adate` datetime DEFAULT NULL,
  `ip` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `ids` (`imageid`,`adate`) USING BTREE
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=52236 ;

我想通过 imageid 选择数据并使用 adate 对其进行排序,所以我添加了 (imageid,adate) 键。

但是这个查询的解释结果说 MuSQL 仍然使用表扫描。为什么?!

EXPLAIN SELECT   comments.*
FROM comments
WHERE comments.imageid=50
ORDER BY
comments.adate DESC LIMIT 10

结果:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  comments    ref     ids     ids     4   const   203     Using where

并使用此索引:

KEY `ids` (`imageid`,`adate`,`id`) USING BTREE

这个查询的结果:

EXPLAIN SELECT   comments.id
FROM comments
WHERE comments.imageid=50
ORDER BY
comments.adate DESC LIMIT 10

是:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  comments    ref     ids     ids     4   const   203     Using where; Using index

【问题讨论】:

  • 你有关于 imageid 的索引吗?
  • 是的,你可以看到我添加了一个密钥 KEY ids (imageid,adate) USING BTREE
  • 如果您在第一个示例中仅选择 cmets.id 有什么不同吗?根据我的经验,我可以说:检查这一点的最简单方法是通过速度。将您的 50k 条目增加三倍,并搜索在特定字段上使用和不使用索引来衡量速度的东西。

标签: mysql indexing sql-order-by


【解决方案1】:

您没有正确阅读解释的结果。

using index 表示查询是索引覆盖的——数据只从索​​引中读取,不使用实际行。这不是因为索引不同,而是因为在第二个查询中您只选择了 id。

如果 MySQL 不使用索引来解析 ORDER BY,则解释中将有 using filesort。在这两个查询中,都使用了 ids 键并且 MySQL 不执行表扫描

【讨论】:

  • “在哪里使用”呢?它显示在两个查询中...!
  • 很可能是因为 adate 允许空值
【解决方案2】:

Straight out of the manual:

在某些情况下,MySQL 不能使用索引来解析 ORDER BY,尽管它仍然使用索引来查找与 WHERE 子句匹配的行。这些情况包括: ––– 您对键的非连续部分使用 ORDER BY: SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2;

也许这适用于您的查询,因为您有一个复合 KEY ids (imageid,adate) 并且您没有在 ORDER BY 中使用 imageid。您可以尝试只为adate 添加一个密钥,看看是否有帮助。

【讨论】:

    【解决方案3】:

    为 InnoDB 创建一个像这样的键 (imageid,adate,id);索引中列的顺序很重要。

    那就试试这个-

    EXPLAIN SELECT   comments.id
    FROM comments
    WHERE comments.imageid=50
    ORDER BY
    comments.adate DESC LIMIT 10
    

    让我知道输出是什么。

    感谢您的输出。 在下面添加以下部分。

    如果您需要的不仅仅是 id,请尝试类似的方法

    EXPLAIN 
    SELECT c1.* from comments as c1
    JOIN
    (
       SELECT comments.id
       FROM comments
       WHERE comments.imageid=50
       ORDER BY
       comments.adate DESC LIMIT 10
    ) as c2 ON (c1.id=c2.id)
    

    但这一次不要依赖解释。无论如何,解释仍然会显示一行带有索引。而是在 phpmyadmin 或 mysql 查询浏览器中检查执行时间。

    【讨论】:

    • 谢谢,我将结果添加到原始问题中
    猜你喜欢
    • 2011-09-29
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 2014-11-13
    • 1970-01-01
    • 2013-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多