【发布时间】:2018-02-27 01:48:10
【问题描述】:
我们正在将 MySQL 5.7 数据库迁移到 PostgreSQL 9.6。
一个真正的问题是 PostgreSQL 中缺少 bit_count 函数。即将发布的 10 版本中也没有此功能。
当前 MySQL 代码 sn-p(简化):
-- mysql specific, tested with 5.7.19
select code,phash,bit_count(phash ^ -9187530158960050433) as hd
from documents
where phash is not null and bit_count(phash ^ -9187530158960050433) < 7
order by hd;
我们尝试了一个简单的解决方案(将 BIGINT 转换为字符串并计算“1”),但与 MySQL 相比,它的性能非常糟糕。
Java uses a trick from Hacker's Delight,但 AFAIK 这在 PostgreSQL 中是不可能的,因为 >>> 运算符(也)不可用。
问题:是否有可用的解决方案/解决方法在性能方面可与 MySQL 相媲美?
更新 1
我能找到的最佳解决方案是基于this SO answer:
首先创建bit_count函数:
CREATE OR REPLACE FUNCTION bit_count(value bigint)
RETURNS numeric
AS $$ SELECT SUM((value >> bit) & 1) FROM generate_series(0, 63) bit $$
LANGUAGE SQL IMMUTABLE STRICT;
现在我们可以使用几乎与 MySQL 相同的 SQL:
-- postgresql specific, tested with 9.6.5
select code,phash,bit_count(phash # -9187530158960050433) as hd
from documents
where phash is not null and bit_count(phash # -9187530158960050433) < 7
order by hd;
更新 2
基于@a_horse_with_no_name 评论,我尝试了这个功能:
-- fastest implementation so far. 10 - 11 x faster than the naive solution (see UPDATE 1)
CREATE OR REPLACE FUNCTION bit_count(value bigint)
RETURNS integer
AS $$ SELECT length(replace(value::bit(64)::text,'0','')); $$
LANGUAGE SQL IMMUTABLE STRICT;
但是,这仍然比 MySQL 慢 5 - 6 倍(在相同硬件上使用完全相同的 200k phash 值的相同数据集进行测试)。
【问题讨论】:
-
请Edit您的问题并添加一些示例数据和基于该数据的预期输出。 Formatted text 请no screen shots。 edit 您的问题 - 请不要在 cmets 中提供邮政编码或其他信息。
-
您好。如果您找到了问题的解决方案,您可以将其添加为答案并稍等片刻,然后将其标记为已接受。只是为了确保没有人能提供更好的解决方案。
-
不知道是不是更快:
length(replace((phash # -9187530158960050433)::bit(64)::text,'0','')) -
如果您尝试计算感知散列或类似 LSH 位串的汉明距离,那么这个问题可能与此重复:stackoverflow.com/a/47487949/302521 Check my answer there
-
@PhilippeOmbredanne 这确实是这个问题的背景。但是,这个问题专门关于找到模拟 MySQL bit_count 函数的最快方法(它在 MySQL 环境中运行良好)。不过,感谢您的提示。
标签: postgresql hamming-distance