【问题标题】:MySQL ORDER BY DESC is fast but ASC is very slowMySQL ORDER BY DESC 很快但 ASC 很慢
【发布时间】:2011-02-22 14:45:40
【问题描述】:

由于某种原因,当我按 DESC 对该查询进行排序时,它的速度非常快,但如果按 ASC 排序,则速度极慢。

这大约需要 150 毫秒:

SELECT posts.id
FROM posts USE INDEX (published)
WHERE posts.feed_id IN ( 4953,622,1,1852,4952,76,623,624,10 )
ORDER BY posts.published DESC
LIMIT 0, 50;

这大约需要 32 秒:

SELECT posts.id
FROM posts USE INDEX (published)
WHERE posts.feed_id IN ( 4953,622,1,1852,4952,76,623,624,10 )
ORDER BY posts.published ASC
LIMIT 0, 50;

两个查询的 EXPLAIN 相同。

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  posts   index   NULL    published   5   NULL    50  Using where

我已将其追踪到“使用索引(已发布)”。如果我把它拿出来,这两种方式的表现都是一样的。但 EXPLAIN 显示查询整体效率较低。

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  posts   range   feed_id feed_id 4   \N  759 Using where; Using filesort

这是桌子。

CREATE TABLE `posts` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `feed_id` int(11) NOT NULL,
  `post_url` varchar(255) NOT NULL,
  `title` varchar(255) NOT NULL,
  `content` blob,
  `author` varchar(255) DEFAULT NULL,
  `published` int(12) DEFAULT NULL,
  `updated` datetime NOT NULL,
  `created` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `post_url` (`post_url`,`feed_id`),
  KEY `feed_id` (`feed_id`),
  KEY `published` (`published`)
) ENGINE=InnoDB AUTO_INCREMENT=196530 DEFAULT CHARSET=latin1;

有解决办法吗?

【问题讨论】:

    标签: mysql performance


    【解决方案1】:

    您的索引是按降序排序的,因此当您要求升序时,它需要做更多的工作才能按该顺序恢复

    【讨论】:

    • 感谢您的解释。有解决办法吗?我正在考虑使用 2 个不同的查询,一个用于 DESC,另一个用于 ASC。
    • 如果你使用 mysql 5+ 你应该能够定义多个索引。
    • 来自dev.mysql.com/doc/refman/5.5/en/create-index.html : index_col_name 规范可以以 ASC 或 DESC 结尾。这些关键字被允许用于未来的扩展,以指定升序或降序索引值存储。目前,它们被解析但被忽略;索引值始终按升序存储。那么,我怎样才能创建一个按 desc 排序的索引呢?
    • @SQLMenace 为什么 desc 索引不能简单地“颠倒”返回结果。我不明白为什么 desc 索引和 asc 索引不相同,你能解释一下为什么吗?
    • 我看不出接受的答案实际上是如何回答问题的。 Pepper 指出,他的 ORDER BY DESC SELECT 比 ORDER BY ASC,但索引始终按 ASC 顺序排序。那么,为什么ORDER BY DESC 不慢呢?
    【解决方案2】:

    翻转 WHERE 条件怎么样?

    SELECT posts.id
    FROM posts USE INDEX (published)
    WHERE posts.feed_id IN ( 10,624,623,76,4952,1852,622,4953 )
    ORDER BY posts.published DESC;
    

    【讨论】:

    • 我不明白,你能澄清一下或提供一个例子吗?
    • SELECT posts.id FROM posts USE INDEX (published) WHERE posts.feed_id IN (10,624,623,76,4952,1852,622,4953) ORDER BY posts.published DESC;好吧... post.created 应该具有完全相同的排序
    【解决方案3】:

    您想跨 (feed_id, published) 添加索引:

    ALTER TABLE posts ADD INDEX (feed_id, published)
    

    这将使该查询运行得最好,并且您无需使用 USE INDEX 强制执行特定索引。

    【讨论】:

    • 这是我以前的,但在一个包含 500000 多个条目的表上,它的执行速度很慢。按 DESC 排序时,强制上面发布的索引大约快 3 倍,按 ASC 排序时慢 10 倍
    • 你试过这个精确的索引吗?以该顺序?定义“慢慢地”。 500,000+ 行对 MySQL 来说真的没什么大不了的(除非你的服务器很古老),并且在这两个字段之间有一个索引,无论排序方向如何,这个查询都应该是全索引的。在你的一个解释计划中“使用文件排序”应该会提示你 - 在优化像这样的简单单表查询时没有理由发生这种情况。另外,什么是“发布”?它是 int(12) 有充分的理由吗?
    • 我猜“慢”是指比 DESC 排序慢。它正在做一个类型:范围,达到 4000 行而不是 50 行,并且正在使用文件排序。
    • 嗯,是的,我自己试过了,看到了你的报告。显然我对此无能为力。就在你认为你了解 MySQL 查询优化的时候... :\
    • 嘿,没关系 :) 你的答案是我开始的,应该是最好的方法......遗憾的是结果并不像预期的那样。
    【解决方案4】:

    我不建议您在表上创建另一个索引;每次插入或删除一行时,表上的每个索引都需要更新,从而减慢INSERT 查询。

    索引绝对是它放慢速度的原因。也许你可以试试IGNORE-ing 它:

    SELECT posts.id
    FROM posts IGNORE INDEX (published)
    WHERE posts.feed_id IN ( 4953,622,1,1852,4952,76,623,624,10 )
    ORDER BY posts.published ASC
    LIMIT 0, 50;
    

    或者,由于该字段已经是KEYed,您可以尝试以下操作:

    SELECT posts.id
    FROM posts USE KEY (published)
    WHERE posts.feed_id IN ( 4953,622,1,1852,4952,76,623,624,10 )
    ORDER BY posts.published ASC
    LIMIT 0, 50;
    

    【讨论】:

    • 谢谢,USE KEY 和 USE INDEX 似乎有相同的结果。并且不使用 USE INDEX 与 IGNORE INDEX 的结果相同。
    【解决方案5】:

    您可以先获取数据集,然后再订购。

    类似

    SELECT posts.id FROM (
    SELECT posts.id
    FROM posts USE INDEX (published)
    WHERE posts.feed_id IN ( 4953,622,1,1852,4952,76,623,624,10 )
    LIMIT 0, 50
    )
    order by postS.id ASC;
    

    它应该首先使用索引找到所有满足你的“where”语句的记录,然后对它们进行排序。但订单将在较小的集合中执行。试一试,然后告诉我们。

    最好的问候。

    【讨论】:

    • 它实际上对我有用。感谢您的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2019-06-09
    • 1970-01-01
    • 1970-01-01
    • 2023-02-01
    • 2020-02-19
    • 1970-01-01
    • 2014-08-02
    • 2020-03-09
    相关资源
    最近更新 更多