我有一个表 line_item { id: int, price: decimal, quantity: int, [other:...] }
。这张 table 很大,大约。 2800 万行。现在我想获取前 1000 行 order by f(price, quantity, [other...])
,f
是一个任意函数。最好的方法是什么?
我想到了 2 个解决方案:
- 使用
order by
和limit
。这种方式可能会很慢,因为我认为 MySQL 会为每一行计算f
的结果,然后对它们进行排序。 - 创建新列来存储函数
f
的结果。这种方式不利于可扩展性,因为我可能想在不同的上下文中使用多个函数f
(f1
、f2
...)。
我真的希望有比他们更好的第三种解决方案。
最佳答案
(抱歉,这是一个否定的答案,但这就是生活。)
如果您接受“最佳解决方案”的速度仅为您所经历的速度的两倍,那么请接受@Zsuzsa 的。
我在这里告诉你,如果不对 f(...) 做一些事情,它就无法优化。原因如下:
优化器看不到 WHERE 子句,但看到带有表达式的 ORDER BY。因此,它意识到评估查询的唯一方法是进行“表扫描”(即读取所有行),评估每一行的函数,将结果保存在 tmp 中表(2800 万行),对该 tmp 表进行排序,并交付 1000 行。
能否将该函数的任何复制到 WHERE 子句中以过滤掉某些行?如果是这样,tmp 表可能会更小。或者,如果幸运的话,也许可以设计一些 INDEX,这样它就不必进行全表扫描。
您要修改所有行吗?还是这种“只写”表?也就是说,一行一旦写入就永远不会改变吗?在此基础上,可以为所有“旧”行预先计算 f() 吗?如果是这样,将它存储在某个地方并添加一个索引——噗!即时结果。
f() 的公共(public)部分是对某个日期范围的测试吗? (大表通常有某种日期。大表上的查询通常会询问“最近”的项目。)如果是这样,是否可以将其从 f() 中提取出来。然后我们可以考虑按日期对表进行分区。这样,即使在 f 中没有其他东西可以优化,“分区修剪”也可以限制要处理的行数。
请显示 CREATE TABLE 并讨论这里的一些想法是否可行。
关于mysql - 在 MySQL 中通过复杂表达式获取 N 行顺序的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28682307/