mysql:优化查询 w/混合升序 ORDER BY

Posted

技术标签:

【中文标题】mysql:优化查询 w/混合升序 ORDER BY【英文标题】:mysql: Optimizing query w/ mixed-ascendency ORDER BY 【发布时间】:2010-03-04 16:26:16 【问题描述】:

我有一个大表(现在~1M 行,很快~10M),它有两个排名列(除了常规数据):

avg_visited,一个浮点数 0-1,代表 %age 流行度;越高越好 alexa_rank,一个整数 1-N,给出一个先验排名

先验排名来自外部来源,因此无法更改。许多行还没有流行度(因为还没有用户点击它),所以先验排名是后备排序。然而,流行度确实会发生非常频繁的变化 - 无论是更新旧条目还是为以前只有先验排名的条目添加流行度,如果某些用户确实点击了它。

我经常运行SELECT id, url, alexa_rank, avg_visited FROMsitesORDER BY avg_visited desc, alexa_rank asc LIMIT 49500, 500(对于 49500 的各种值)。

但是,ORDER BY 不能使用按http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html 混合升序的索引

这是在 mysql 5.1,innodb 中。

我怎样才能最好地改变这种情况,给我一个理智的、完全索引的查询?

【问题讨论】:

【参考方案1】:

很遗憾,MySQL 不支持索引中的DESC 子句,也不支持派生表达式的索引。

您可以将负面人气与正面人气一起存储并在ORDER BY中使用:

CREATE INDEX ix_mytable_negpopularity_apriori ON (neg_popularity, a_priori);

INSERT
INTO    mytable (popularity, neg_popularity)
VALUES  (@popularity, -@popularity);

SELECT  *
FROM    mytable
ORDER BY
        neg_popularity, a_priori

【讨论】:

这也是我第一时间想到的。我想知道是否有更好的解决方案。 @Sai:这几乎不可能(MySQL)。在其他引擎中,您可以在(popularity DESC, a_priori) 上创建索引,但不能在MySQL 上创建索引。 另外,FWIW,我必须使用覆盖索引 - 即在 (neg_popularity, a_priori, common_data_1, common_data2) 上 - 因为如果选择中有其他字段,简单索引不适用于 order by。 :-/ @Sai:一个简单的索引适用于ORDER BY 好吧。出于某种原因可能不愿意使用它的优化器,但您可以通过FORCE INDEX 强制使用它。您的查询中有LIMIT 子句吗?能否请您发布完整的查询? 总是使用 LIMIT。已将完整查询添加到问题中。【参考方案2】:

只是一个简单的技巧:

因为流行度是 0 到 1 之间的浮点数。你可以将它乘以 -1,数字将在 -1 到 0 之间。

这样你可以将流行度的排序顺序颠倒为ORDER BY popularity ASC, a_priori ASC

不确定开销是否会影响收益。

这让我想起了反向存储电子邮件的技巧。

【讨论】:

这与 Quassnoi 的相同,所以我让他先检查(除非有人提出更好的解决方案)。以反向形式存储电子邮件有什么技巧?我不知道。

以上是关于mysql:优化查询 w/混合升序 ORDER BY的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 查询优化与 group by 和 order by rand

MySQL优化:order by和limit

MySQL ORDER BY 两个子句(降序和升序)

21《MySQL 教程》ORDER BY 排序

sql里的排序倒序的命令是order by啥

python:mysql之ORDER BY 语句