You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何在PostgreSQL数据库中按内容查找所有完全相同的表?

我之前帮客户处理过类似的PostgreSQL大规模表去重排查需求,针对你说的这种表结构完全一致、但内容(含排序)重复的情况,给你几个实用的方案,一步步来:

第一步:先锁定结构完全一致的表(可选但推荐)

虽然你提到所有表结构都相同,但保险起见,可以先通过这个查询确认哪些表的列数、列名完全匹配,避免后续做无用功:

SELECT 
    array_agg(table_name ORDER BY table_name) AS tables_with_same_structure,
    column_count,
    column_list
FROM (
    SELECT 
        table_name,
        COUNT(*) AS column_count,
        array_agg(column_name ORDER BY column_name) AS column_list
    FROM information_schema.columns
    WHERE table_schema = 'public' -- 替换成你的表所在的schema
    GROUP BY table_name
) t
GROUP BY column_count, column_list
HAVING COUNT(*) > 1;

如果结果里所有600张表都在同一个分组里,就可以直接进入下一步了。

第二步:计算每张表的内容哈希(含排序)

核心思路是:给每张表的内容按固定列排序后生成唯一哈希值,内容完全一致的表哈希值必然相同。

首先创建一个临时表来存储每张表的哈希结果:

CREATE TEMP TABLE table_content_hashes (
    table_name text PRIMARY KEY,
    content_hash text NOT NULL
);

然后用PL/pgSQL脚本批量遍历所有表,计算哈希:

DO $$
DECLARE
    rec record;
    column_list text;
    hash_sql text;
BEGIN
    -- 获取目标表的列名列表(取第一张表的列,因为结构都一致)
    SELECT string_agg(column_name, ', ') INTO column_list
    FROM information_schema.columns
    WHERE table_schema = 'public' 
      AND table_name = (
          SELECT table_name FROM information_schema.columns WHERE table_schema = 'public' LIMIT 1
      )
    ORDER BY column_name;

    -- 遍历所有基础表
    FOR rec IN 
        SELECT table_name 
        FROM information_schema.tables 
        WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
    LOOP
        -- 构造计算哈希的SQL:按所有列排序后聚合,生成MD5哈希
        hash_sql := format(
            'INSERT INTO table_content_hashes (table_name, content_hash)
             SELECT %L, md5(cast(array_agg(t ORDER BY %s) as text))
             FROM %I.%I t',
            rec.table_name,
            column_list,
            'public',
            rec.table_name
        );
        EXECUTE hash_sql;
    END LOOP;
END $$;
第三步:找出内容重复的表

最后查询哈希值相同的表分组,就是你要找的内容完全一致的表:

SELECT content_hash, array_agg(table_name ORDER BY table_name) AS duplicate_tables
FROM table_content_hashes
GROUP BY content_hash
HAVING COUNT(*) > 1;
优化小技巧(针对大表)

如果你的表数据量很大,全表扫描计算哈希会比较慢,可以先通过行数快速排除不可能重复的表:

SELECT 
    reltuples,
    array_agg(relname ORDER BY relname) AS tables_with_same_row_count
FROM pg_stat_user_tables
WHERE schemaname = 'public'
GROUP BY reltuples
HAVING COUNT(*) > 1;

这里的reltuples是PostgreSQL统计的近似行数,能帮你快速缩小范围,只对行数相同的表计算哈希,节省时间。如果需要精确行数,可以替换成(SELECT count(*) FROM public.relname),但大表会比较耗时。

另外,如果你担心md5碰撞的概率(虽然极低),可以换成sha256函数,把md5(...)改成encode(sha256(cast(array_agg(t ORDER BY %s) as bytea)), 'hex')即可。

内容的提问来源于stack exchange,提问作者Dumbo

火山引擎 最新活动