在MySQL中通过复杂表达式获得N行排序的有效方法

时间:2015-02-23 19:58:29

标签: mysql performance sorting sql-order-by limit

我有一张桌子line_item { id: int, price: decimal, quantity: int, [other:...] }。这张桌子很大,约。 2800万行。现在我想获得前1000行order by f(price, quantity, [other...])f是一个任意函数。最好的方法是什么?

我想到了2个解决方案:

  1. 使用order bylimit。这种方式可能很慢,因为我认为MySQL计算每行f的结果然后对它们进行排序。
  2. 创建新列以存储函数f的结果。这种方式不利于可伸缩性,因为我可能想在不同的上下文中使用多个函数ff1f2 ...)。
  3. 我真的希望有第三种解决方案比他们更好。

2 个答案:

答案 0 :(得分:0)

我正考虑另一种选择:

创建一个只包含id和f列的临时表。

创建第二个临时表(temp_table2)并在其中插入以下结果:

SELECT TOP 1000 id, f
FROM temp_table
ORDER BY f

这应该比你提到的其他2个选项运行得更快,因为在这里你只需要使用2列。

最后,您可以通过将此seoncd临时表连接到原始表来选择最终结果。

SELECT line_item.* --or just the columns you need
FROM temp_table2
INNER JOIN line_item
ON temp_table2.id = line_item.id

您还可以尝试执行您提到的第一个选项,如果使用我建议的临时表,请查看是否有任何显着的性能改进。 在许多情况下使用临时表可以缩短执行时间,但不是所有时间都是如此 - 所以最好是尝试两者并查看哪些更好。

答案 1 :(得分:0)

(对不起,这是一个否定的答案,但这就是生活。)

如果您接受“最佳解决方案”的速度只是您所经历的速度的两倍,那么请接受@ Zsuzsa's。

我在这里告诉你,如果不对f(...)做些什么就无法进行优化。原因如下:

优化器没有看到WHERE子句,但看到带有表达式的ORDER BY。因此,它意识到评估查询的唯一方法是执行“表扫描”(即,读取所有行),评估每行的函数,将结果保存在tmp中table(有28M行),对tmp表进行排序,并提供1000行。

可以将该函数的任何复制到WHERE子句中以过滤掉某些行吗?如果是这样,tmp表可能会更小。或者,如果你幸运的话,也许可以设计一些INDEX,这样就不必进行全表扫描。

您要修改所有行吗?或者这是一种“只写”表?也就是说,一旦写入,一行是否永远不会改变?在此基础上,可以为所有“旧”行预先计算f()吗?如果是这样,将它存储在某处并添加索引 - 噗!即时结果。

f()的常见部分是某个日期范围的测试吗? (大表通常有某种日期。大表上的查询经常询问“最近”的项目。)如果是这样,可以从f()中取出。然后我们可以考虑按日期对表进行PARAGETION。这样,即使f中没有其他任何东西可以优化,“分区修剪”也可以限制要处理的行数。

请显示创建表并讨论这里的一些想法是否可行。