PostgreSQL小技巧


PostgreSQL小技巧

按字段对某个表或者分区进行快速去重

下面这条SQL贼快,比min(id)或者加时间窗口函数:rank()等都很多很多:

DO $$
BEGIN
    -- 创建临时表,并设置其在事务提交后自动删除
    EXECUTE format('
        CREATE TEMP TABLE tmp_keep ON COMMIT DROP AS 
        SELECT DISTINCT ON (longitude, latitude) *
        FROM reverse_geocoding_caches
        ORDER BY longitude, latitude, id
    ');

    -- 清空原表数据
    EXECUTE 'TRUNCATE TABLE reverse_geocoding_caches';

    -- 将数据从临时表移回原表
    EXECUTE 'INSERT INTO reverse_geocoding_caches SELECT * FROM tmp_keep';
   
   EXECUTE 'DROP TABLE tmp_keep';
END $$;

如果是要对一个表下的所有分区都进行去重:

DO $$
DECLARE
    partition text;
BEGIN
    FOR partition IN
        SELECT inhrelid::regclass::text
        FROM pg_inherits
        WHERE inhparent = 'bingmap.reverse_geocoding_caches'::regclass
    LOOP
        -- 使用EXECUTE和format执行动态SQL,注意内部SQL要用单引号包裹,且内部的单引号需要双写
        EXECUTE format('CREATE TEMP TABLE tmp_keep ON COMMIT DROP AS SELECT DISTINCT ON (longitude, latitude) * FROM %I ORDER BY longitude, latitude, id', partition);
        
        EXECUTE format('TRUNCATE TABLE %I', partition);
        
        EXECUTE format('INSERT INTO %I SELECT * FROM tmp_keep', partition);
        
        EXECUTE 'DROP TABLE tmp_keep';
    END LOOP;
END $$;

对某个schema下的所有表执行truncate

DO $$
DECLARE
    rec record;
BEGIN
    FOR rec IN SELECT tablename FROM pg_tables WHERE schemaname = 'your_schema'
    LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident('your_schema') || '.' || quote_ident(rec.tablename) || ' CASCADE;';
    END LOOP;
END $$;

查看某个schema下的所有表的创建索引的语句

SELECT indexname AS index_name,
       tablename AS table_name,
       indexdef AS create_index_statement
FROM pg_indexes
WHERE schemaname = 'your_schema';

删除某个schema下所有表的索引

DO $$
DECLARE
    index_name RECORD;
BEGIN
    -- 遍历所有属于指定 schema 的索引
    FOR index_name IN 
        SELECT indexname, schemaname, tablename
        FROM pg_indexes
        WHERE schemaname = 'import'
    LOOP
        BEGIN
            -- 尝试直接删除索引
            EXECUTE format('DROP INDEX IF EXISTS %I.%I;', index_name.schemaname, index_name.indexname);
        EXCEPTION WHEN others THEN
            -- 如果直接删除索引失败,检查是否是主键或唯一约束
            IF EXISTS (SELECT 1 FROM pg_constraint 
                       WHERE conname = index_name.indexname 
                         AND conrelid = (quote_ident(index_name.schemaname) || '.' || quote_ident(index_name.tablename))::regclass) THEN
                -- 删除约束
                EXECUTE format('ALTER TABLE %I.%I DROP CONSTRAINT IF EXISTS %I;', index_name.schemaname, index_name.tablename, index_name.indexname);
                -- 删除索引
                EXECUTE format('DROP INDEX IF EXISTS %I.%I;', index_name.schemaname, index_name.indexname);
            ELSE
                RAISE NOTICE '无法删除索引:%', index_name.indexname;
            END IF;
        END;
    END LOOP;
END $$;

查看一个schema下所有表的行数

SELECT
    table_schema,
    table_name,
    n_live_tup AS row_count
FROM
    information_schema.tables AS t
JOIN
    pg_stat_user_tables AS st
ON
    t.table_schema = st.schemaname
AND
    t.table_name = st.relname
WHERE
    t.table_schema = 'import'  -- 替换为你的schema名称
ORDER BY
    row_count DESC;
undefined: wuliang142857