一种更有效的方法来总结 postgres 中列之间的差异?
Posted
技术标签:
【中文标题】一种更有效的方法来总结 postgres 中列之间的差异?【英文标题】:A more efficient way to sum the difference between columns in postgres? 【发布时间】:2019-09-19 15:29:23 【问题描述】:对于我的应用程序,我有一个包含这三列的表:user, item, value
以下是一些示例数据:
user item value
---------------------
1 1 50
1 2 45
1 23 35
2 1 88
2 23 44
3 2 12
3 1 27
3 5 76
3 23 44
我需要做的是,对于给定的用户,针对其他所有人的值执行简单的算术运算。
假设我想将用户 1 与其他所有人进行比较。计算如下所示:
first_user second_user result
1 2 SUM(ABS(50-88) + ABS(35-44))
1 3 SUM(ABS(50-27) + ABS(45-12) + ABS(35-44))
这是目前我程序中的瓶颈。例如,我的许多查询开始需要 500 多毫秒,而这个算法大约需要 95% 的时间。
我的数据库中有很多行,它是 O(n^2)(它必须将所有用户 1 的值与其他所有人的匹配值进行比较)
对于如何提高效率,我相信只有两种选择。首先,我可以缓存结果。但是由于需要 NxN 空间,生成的表会很大,并且值需要相对新鲜。
第二种方法是使算法更快。我搜索了“postgres SIMD”,因为我认为 SIMD 听起来是优化它的完美解决方案。我找到了几个相关链接,例如 this 和 this,但我不确定它们是否适用于此。此外,它们似乎都有 5 年左右的历史并且相对无人维护。
Postgres 是否支持这种功能?您可以在哪里“矢量化”一列,或者可能导入或启用某些扩展或功能,以允许您对多行快速执行这些类型的基本算术运算?
【问题讨论】:
覆盖索引可以提高性能,如果你还没有的话。在您展示的简化示例中,这可能采用以下形式:create index ix1 on my_table (user, item, value)
。
@TheImpaler 在查找之前我从未听说过覆盖索引,谢谢。
现在,如果“需要比较新鲜的值”,您还可以使用将计算值存储在表上的策略,并定期刷新它们。如果一天有 24 小时,则每小时可以刷新 1/24 的用户;每个用户数据将最多 23 小时“陈旧”。一个 cron 工作就可以解决问题。
围绕矢量化执行进行了一些讨论,但到目前为止,还没有任何内容导致核心中的具体实现。您是否尝试为这些查询启用 JITting?
@a_horse_with_no_name 我以前也从未听说过。现在试一试,但不确定我是否做得正确。我跑了set JIT = true;
然后SET jit_above_cost = 10;
和SET jit_inline_above_cost = 10;
和SET jit_optimize_above_cost = 10;
但查询似乎仍然需要相同的时间。
【参考方案1】:
我不确定你从哪里得到 O(n^2)。您需要查找用户 1 的行,然后为其他所有人读取数据。假设项目少而用户多,这基本上是 O(n),其中“n”是表中的行数。
查询可以表述为:
select t1.user, t.user, sum(abs(t.value - t1.value))
from t left join
t t1
on t1.item = t.item and
t1.user <> t.user and
t1.user = 1
group by t1.user, t.user;
对于此查询,您需要在t(item, user, value)
上建立索引。
【讨论】:
嗯,有很多项目和很多用户。我已经在做类似的事情,这是我的瓶颈和性能问题的原因。我有大约 300 个项目和成千上万的用户。我想我需要 SIMD 或类似的东西才能在合理的时间内运行。 @RyanPeschel 。 . .你有指定的索引吗? 是的,我尝试使用 The Impaler 提到的覆盖索引,但它似乎根本没有提高查询速度。 @RyanPeschel 。 . .这不是我回答中的索引。 你是对的。好的,我也做了一个,但性能还是一样。以上是关于一种更有效的方法来总结 postgres 中列之间的差异?的主要内容,如果未能解决你的问题,请参考以下文章
有没有一种更有效的方法来枚举python或R中离散随机变量的每个可能结果的概率?