如何优化重复 MySQL 排序的选择

How to optimize repeat MySQL sorted selects

假设我有一个包含 a、b 和 c 列的大型数据库。假设我随后希望根据多列上的某种排序 select 第 x 行到第 (x+100) 行。我可以使用 ORDER BYLIMIT 构造来完成此操作:

SELECT * FROM table_name ORDER BY b ASC, c DESC, a DESC LIMIT x, 100

如果我随后希望使用相同的顺序(在 b 上升序,在 c 上降序,然后在 a 上降序)但具有不同的范围限制来执行许多类似的查询怎么办?直觉上,不需要为每个这样的查询重复昂贵的排序操作。

我正在研究使用索引 (http://dev.mysql.com/doc/refman/5.6/en/order-by-optimization.html) 优化 ORDER BY 操作,但不幸的是,似乎无法创建包含混合升序和降序的索引。

有什么好的优化方法吗?这似乎是一个相当常见的用例。

这里有一个可能适用于数字列的想法(更像是一种 hack)。 对于要作为排序依据的每一列,添加一个具有值 MAX_TYPE - column_value 的相同类型的新列,其中 MAX_TYPE 是该列的预期最大值。现在向该列添加索引并按它而不是原始列进行排序。

注意:

  • 我使用 DECIMAL 而不是 DOUBLE,因为双精度可能有舍入误差。
  • 也许我遗漏了一些东西,因为 MySQL 在使用 ORDER BY 时根本不使用任何索引(即使是单个列)。
  • @Rick James 建议的解决方案绝对比使用 MAX_TYPE 更好。

SQL fiddle:

MySQL 5.6 架构设置:

CREATE TABLE `bogus` (
  `income` DECIMAL(7,2),
  `expense` DECIMAL(7,2),
  `expense_inverted` DECIMAL(7,2)
);

ALTER TABLE `bogus` ADD INDEX `income_idx` (`income`);
ALTER TABLE `bogus` ADD INDEX `expense_idx` (`expense`);
ALTER TABLE `bogus` ADD INDEX `expense_inverted_idx` (`expense_inverted`);

INSERT INTO `bogus` (`income`, `expense`)
  VALUES
  (250.35, 200.90),
  (250.35, 100.35),
  (300.50, 210.75);

UPDATE `bogus` SET `expense_inverted` = 99999.99 - `expense`;

查询 1:

SELECT income, expense
FROM `bogus`
ORDER BY
  `income` ASC,
  `expense_inverted` ASC; # equivalent of `expense` DESC

Results:

| income | expense |
|--------|---------|
| 250.35 |   200.9 |
| 250.35 |  100.35 |
|  300.5 |  210.75 |

我知道这是一个非常不优雅的解决方案,但对于不能牺牲速度的大型数据库,这可能会奏效。

可能唯一的优化是将数字 b 存储为 -b 或者有一个额外的列,其中冗余地包含 -b。然后

ORDER BY b ASC, c DESC LIMIT...

将被替换为

ORDER BY minusb DESC, c DESC LIMIT...

并且有

INDEX(minusb, c)

只要你确定

  • 所有 ORDER BY 项都是同一 table、
  • 中的列名
  • 方向相同,
  • 和一个 INDEX 存在,它以与 ORDER BY 列表相同的顺序列出所有这些(可选地在 结束 的额外列),

然后优化器可以(但可能选择不)非常有效地使用 INDEX——包括消耗 LIMIT.

无论你是全部制作ASC还是全部制作DESC都没有关系。 (ASC可能稍微好一点。)

请记住 LIMIT m, n 必须读取 m+n 行。 (OFFSET 是一个不错的功能,但它没有得到很好的优化。)如果您 "paginating" 通过使用 OFFSETLIMIT 的长列表,最好 "remember where you left off" 以避免扫描 OFFSET 行。 (如果适用,我可以为您提供更多详细信息。)