提问人:Bylaw 提问时间:3/29/2023 最后编辑:Bylaw 更新时间:3/29/2023 访问量:162
使用 plpgsql 脚本批量插入/删除行
Insert/delete rows in batches with plpgsql script
问:
我需要对具有 ~400M 条记录的表进行分区。由于数据库资源、WAL 大小等原因,它有几个陷阱和挫折。经过不同的方法,解决方案似乎是这样的:
- 为作用域中的每个月创建子表,表示将来的分区
- 在同一事务中将相关数据从父级插入到子级,并从父级中删除
- 停止继承,将以前的子表作为分区附加到默认分区的新表
这样一来,停机时间几乎为零,因为查询原始(父)表将返回数据,即使它已经在子表中。插入/删除部分是通过脚本完成的,该脚本批量循环访问表。所有这些都在本地工作(数据要少得多),但实际表存在问题。
不知何故,在某些批处理中,删除的行要少得多,即使我用于收集批处理的公共表表达式对于两个命令都是相同的。由于这个原因,以及我出于某些原因多次运行脚本的事实,子项中存在重复的行(不幸的是,其中没有约束,因此可能会发生这种情况)。
现在,我需要对其进行重复数据删除,然后从父行中删除已迁移的行。即使在那之后,我也必须解决删除问题,这是我的实际问题:可能是什么问题?这两个命令是否以某种方式相互干扰?这是一个问题吗
起初,我认为只有日志具有欺骗性,但看到所有重复的数据表明,删除的行确实较少。
提前致谢!
脚本:(稍微简化一点,实际脚本也会循环几个月,但包括基本要素)
DO $$
DECLARE
batch_size INTEGER := 10000;
off_set INTEGER := 0;
rows_inserted INTEGER;
rows_deleted INTEGER;
BEGIN
SELECT MIN(id) INTO off_set FROM ONLY parent_table WHERE inserttime >= ('2023-01-01') AND inserttime < ('2023-02-01');
LOOP
WITH parent_table_cte AS (
SELECT * FROM parent_table
WHERE inserttime >= ('2023-01-01')
AND inserttime < ('2023-02-12')
AND id >= off_set
ORDER BY id ASC
LIMIT batch_size
)
INSERT INTO child_table SELECT * FROM parent_table_cte;
GET DIAGNOSTICS rows_inserted = row_count;
RAISE info 'Inserted [%] rows into [child_table]!', rows_inserted;
WITH parent_table_cte AS (
SELECT * FROM pod.parent_table
WHERE inserttime >= ('2023-01-01')
AND inserttime < ('2023-02-12')
AND id >= off_set
ORDER BY id ASC
LIMIT batch_size
)
DELETE FROM ONLY pod.parent_table USING parent_table_cte
WHERE parent_table.id = parent_table_cte.id;
GET DIAGNOSTICS rows_deleted = row_count;
RAISE info 'Deleted [%] rows from [parent_table] in the range of (2023-01-01) - (2023-02-01)!', rows_deleted;
IF rows_inserted = 0 THEN
RAISE info e'No more rows to insert from range (2023-01-01) - (2023-02-01) into table: [child_table]\n';
EXIT;
END IF;
RAISE info e'[%] rows were inserted and [%] were deleted in the batch ending at offset [%]\n', rows_inserted, rows_deleted, off_set + rows_inserted;
COMMIT;
off_set := off_set + batch_size;
-- PERFORM pg_sleep(5);
END LOOP;
END;
$$;
更新
现在,当我浏览我的问题时,我注意到 CTE 不仅从父项中进行选择,这意味着子项也在查询中。这可能是问题所在,我会尽快检查。
答:
0赞
Bylaw
3/29/2023
#1
当我再次浏览我的问题时,我发现了问题: CTE 使用父级的 SELECT 命令,而不使用 ONLY 关键字。这样,子表也会被查询。虽然删除只发生在父表中,但批处理也将包含来自父表和子表的数据,因此删除量正在减少,脚本变得越来越慢,因为子表一直在增长。
评论