【问题标题】:bit_count function in PostgreSQLPostgreSQL 中的 bit_count 函数
【发布时间】: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 中是不可能的,因为 &gt;&gt;&gt; 运算符(也)不可用。

问题:是否有可用的解决方案/解决方法在性能方面可与 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 textno screen shotsedit 您的问题 - 请不要在 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


【解决方案1】:

如果您正在尝试计算感知哈希或类似 LSH 位串的汉明距离,那么这个问题可能与这个 answer 密切相关

如果您正在寻找一种预先构建的方法来在 PostgreSQL 数据库上进行汉明距离查询,那么这可能是解决方法:hamming distance search 的扩展

【讨论】:

    【解决方案2】:

    问题:是否有可用的解决方案/解决方法与 MySQL 性能如何?

    要获得可比较的速度,应使用已编译的 C 函数。 如果您可以编译 C 代码,请参见例如 https://github.com/dverite/postgresql-functions/tree/master/hamming_weight

    代码本身很简单。

    根据将bit(64) 字符串中的0 字符计数为文本,结果似乎比bit_count 函数快10 倍。

    例子:

    plpgsql函数:

    test=> select sum(bit_count(x)) from generate_series(1,1000000) x;
       sum   
    ---------
     9884999
    (1 row)
    
    Time: 2442,340 ms
    

    C 函数:

    test=> select sum(hamming_weight(x::int8)) from generate_series(1,1000000) x;
       sum   
    ---------
     9884999
    (1 row)
    
    Time: 239,749 ms
    

    【讨论】:

    • 是的,它的性能与 MySQL 相当。这种解决方案的缺点是“自己动手”的特点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-28
    • 2012-08-18
    • 2013-05-04
    • 1970-01-01
    • 1970-01-01
    • 2020-11-18
    • 2013-12-24
    相关资源
    最近更新 更多