假设我有一个包含a,b和c列的大型数据库。假设我希望根据多列上的某些排序选择第x到第(x + 100)行。我可以使用ORDER BY
和LIMIT
构造完成此操作:
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
操作,但不幸的是,似乎无法创建包含混合升序和降序的指标。
有优化方法可以优化吗?这似乎是一个相当常见的用例。
答案 0 :(得分:1)
这是一个可能适用于数字列的想法(这是一个黑客攻击)。
对于要按其排序的每个列,添加一个具有值MAX_TYPE - column_value
的相同类型的新列,其中MAX_TYPE
是此列所需的最大值。现在为此列添加一个索引,然后按它而不是原始列进行排序。
抬头:
DECIMAL
代替DOUBLE
,因为双倍可能会出现舍入错误。MySQL
在使用ORDER BY
时根本不使用任何索引(即使只有一列)。MAX_TYPE
更好。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 |
我知道这是一个非常不优雅的解决方案,但对于无法牺牲速度的大型数据库 - 这可能会有效。
答案 1 :(得分:1)
可能唯一的优化是将数字b
存储为-b
,或者在其中有一个冗余的-b
列。然后
ORDER BY b ASC, c DESC LIMIT...
将被
取代ORDER BY minusb DESC, c DESC LIMIT...
并且
INDEX(minusb, c)
只要你确定
ORDER BY
项都是同一个表中的列名INDEX
,其列出的所有顺序与ORDER BY
列表的顺序相同(可选 end 上的额外列),然后优化器可以(但可以选择不)非常有效地使用INDEX
- 包括使用LIMIT
。
无论是ASC
还是全部DESC
,都无关紧要。 (ASC
可能稍好一些。)
请注意,LIMIT m, n
必须阅读m+n
行。 (OFFSET
是一个很好的功能,但它没有得到很好的优化。)如果您使用OFFSET
和LIMIT
通过长列表“分页”,最好“记住你在哪里停止“以避免扫描OFFSET
行。 (如果适用,我可以提供更多详细信息。)