如何在postgresql中获取整个表的哈希值?

Ben*_*Ben 18 sql postgresql hash

我想要一个相当有效的方法将整个表压缩为哈希值.

我有一些生成整个数据表的工具,然后可以用它们生成更多的表,依此类推.我正在尝试实现一个简单的构建系统来协调构建运行并避免重复工作.我希望能够记录输入表的哈希值,以便稍后检查它们是否已更改.建造一张桌子需要几分钟或几小时,所以花几秒钟建造哈希是可以接受的.

我使用的hack只是将pg_dump的输出传递给md5sum,但是这需要通过网络传输整个表转储以在本地盒上散列它.理想情况下,我想在数据库服务器上生成哈希.

在postgresql中查找行的哈希值给了我一种方法来计算一次一行的哈希值,然后可以以某种方式组合.

任何提示将非常感谢.

编辑发布我最终的结果: tinychen的答案对我不起作用,因为我显然不能使用'plpgsql'.当我在SQL中实现该函数时,它起作用,但对于大型表来说效率非常低.因此,我没有连接所有行哈希然后哈希,而是切换到使用"滚动哈希",其中前一个哈希与行的文本表示连接,然后进行哈希处理以产生下一个哈希.这要好得多; 显然在短字符串上运行md5数百万次额外时间比连接短字符串数百万次更好.

create function zz_concat(text, text) returns text as 
    'select md5($1 || $2);' language 'sql';

create aggregate zz_hashagg(text) (
    sfunc = zz_concat,
    stype = text,
    initcond = '');
Run Code Online (Sandbox Code Playgroud)

Tom*_*eif 23

我知道这是一个老问题,但这是我的解决方案:

SELECT        
    md5(CAST((array_agg(f.* order by id))AS text)) /* id is a primary key of table (to avoid random sorting) */
FROM
    foo f; 
Run Code Online (Sandbox Code Playgroud)


tin*_*hen 7

就像这样创建一个哈希表聚合函数.

create function pg_concat( text, text ) returns text as '
begin
    if $1 isnull then
        return $2;
    else
       return $1 || $2;
    end if;
end;' language 'plpgsql';

create function pg_concat_fin(text) returns text as '
begin
    return $1;
end;' language 'plpgsql';

create aggregate pg_concat (
    basetype = text,
    sfunc = pg_concat,
    stype = text,
    finalfunc = pg_concat_fin);
Run Code Online (Sandbox Code Playgroud)

然后你可以使用pg_concat函数来计算表的哈希值.

select md5(pg_concat(md5(CAST((f.*)AS text)))) from f order by id
Run Code Online (Sandbox Code Playgroud)


小智 7

SELECT md5(array_agg(md5((t.*)::varchar))::varchar)
  FROM (
        SELECT *
          FROM my_table
         ORDER BY 1
       ) AS t
Run Code Online (Sandbox Code Playgroud)


har*_*mic 5

我有一个类似的要求,在测试专门的表复制解决方案时使用。

@Ben 的滚动 MD5 解决方案(他将其附加到问题中)似乎非常有效,但是有几个陷阱让我绊倒了。

第一个(在其他一些答案中提到)是您需要确保在您正在检查的表上以已知顺序执行聚合。其语法是例如。

select zz_hashagg(CAST((example.*)AS text) order by id) from example;
Run Code Online (Sandbox Code Playgroud)

注意order by是在聚合内。

第二个是 usingCAST((example.*)AS text不会为具有相同列内容的两个表提供相同的结果,除非这些列是以相同的顺序创建的。在我的情况下,不能保证,所以为了获得真正的比较,我必须单独列出列,例如:

select zz_hashagg(CAST((example.id, example.a, example.c)AS text) order by id) from example;
Run Code Online (Sandbox Code Playgroud)

为了完整起见(以防后续编辑应将其删除)这里是@Ben 问题中 zz_hashagg 的定义:

create function zz_concat(text, text) returns text as 
    'select md5($1 || $2);' language 'sql';

create aggregate zz_hashagg(text) (
    sfunc = zz_concat,
    stype = text,
    initcond = '');
Run Code Online (Sandbox Code Playgroud)