【问题标题】:How to optimize an ORDER BY for a computed column on a MASSIVE MySQL table如何为 MASSIVE MySQL 表上的计算列优化 ORDER BY
【发布时间】:2011-03-24 21:36:27
【问题描述】:

我有一个非常大(80+ 百万行)的非规范化 MySQL 表。简化的架构如下所示:

+------------+-------------+--------------+-------- ------+ |身份证 |参数1 |参数2 |参数3 | +------------+-------------+--------------+-------- ------+ | 1 | .04 | .87 | .78 | +------------+-------------+--------------+-------- ------+ | 2 | .12 | .02 | .76 | +------------+-------------+--------------+-------- ------+ | 3 | .24 | .92 | .23 | +------------+-------------+--------------+-------- ------+ | 4 | .65 | .12 | .01 | +------------+-------------+--------------+-------- ------+ | 5 | .98 | .45 | .65 | +------------+-------------+--------------+-------- ------+

我正在尝试查看是否有一种方法可以优化查询,其中我将权重应用于每个 PARAM 列(其中权重在 0 和 1 之间),然后对它们进行平均以得出计算值 SCORE。然后我想按该计算的 SCORE 列排序。

例如,假设 PARAM1 的权重为 0.5,PARAM2 的权重为 0.23,PARAM3 的权重为 0.76,您最终会得到类似于:

SELECT ID, ((PARAM1 * .5) + (PARAM2 * .23) + (PARAM3 * .76)) / 3 AS SCORE 

ORDER BY SCORE DESC LIMIT 10

通过一些适当的索引,这对于基本查询来说很快,但我想不出一个好方法来加快对如此大的表的上述查询。

详情:

  • 每个 PARAM 值都在 0 和 1 之间
  • 应用于 PARAMS 的每个权重在 0 到 1 s 之间

--编辑--

以下是问题的简化版本。

这会在合理的时间内运行:

SELECT value1, value2 
FROM sometable 
WHERE id = 1 
ORDER BY value2

不会在合理的时间内运行:

 SELECT value1, (value2 * an_arbitrary_float) as value3 
 FROM sometable 
 WHERE id = 1 
 ORDER BY value3

使用上面的示例,是否有任何解决方案可以让我在不提前计算 value3 的情况下执行 ORDER BY?

【问题讨论】:

  • 您可以使用“010001”按钮格式化代码。 <code> 标签无法识别。我已经为你做了。
  • 您目前有哪些索引? EXPLAIN对此有什么要说的?我知道您可能无法为您的精简版获得这些东西,但如果可能的话,它会有所帮助。
  • 我在这个表上有几个真正用于其他查询的索引。 ID 有一个索引,然后有 (ID, PARAM1) 和 (ID, PARAM2) 的索引,让我可以运行查询,在其中我可以获取给定 ID 的前 10 行,按 PARAM1 排序。从解释来看,问题是在动态计算的(未索引的)列上使用“ORDER BY”时发生的文件排序。我不确定是否有解决方案。
  • +1 好,写得很好的问题。欢迎来到 SO
  • 您希望这张桌子在未来变得更大吗?它是什么存储引擎?你能提供一些你的mysql服务器硬件的规格吗?

标签: mysql query-optimization sql-order-by


【解决方案1】:

我知道这个问题很老,但我最近遇到了这个问题,我想出的解决方案是使用派生表。在派生表中,创建计算列。在外部查询中,您可以按它排序。对于我的工作量(数量级),它似乎运行得更快。

SELECT value1, value3
FROM (
    SELECT value1, (value2 * an_arbitrary_float) as value3 
    FROM sometable 
    WHERE id = 1 
) AS calculated
ORDER BY value3

【讨论】:

    【解决方案2】:

    我发现 2 个(有点明显)有助于将此查询速度提高到令人满意的水平:

    1. 尽量减少需要排序的行数。通过使用“id”字段上的索引和子选择来首先修剪记录数,计算列上的文件排序并没有那么糟糕。即:

      SELECT t.value1, (t.value2 * an_arbitrary_float) as SCORE
      FROM (SELECT * FROM sometable WHERE id = 1) AS t 
      ORDER BY SCORE DESC
      
    2. 尝试在 my.conf 中增加 sort_buffer_size 以加快这些文件排序。

    【讨论】:

      【解决方案3】:

      MySQL 缺少许多可以帮助您解决此问题的性感功能。也许您可以添加一个包含计算排名的列,为其编制索引并编写几个触发器以保持更新。

      【讨论】:

      • 问题在于用于计算 SCORE 的权重是基于用户输入的——直到运行时才知道。因此,没有办法(容易)提前计算分数。一种可能的解决方案是将 PARAMS 的权重从浮点数更改为一组已知值(0、.2、.4、.6、.8),但这些计算值的存储需求会很大。
      猜你喜欢
      • 1970-01-01
      • 2017-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-08
      • 2022-01-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多