KingbaseES数据库批量加载数据的最佳方法
前言
本文讨论在KingbaseES数据库服务器中批量加载数据的方法,以及空数据库中的初始数据加载和增量数据加载的最佳做法。
批量加载方法
以下数据加载方法按照从最耗时到最不耗时的顺序排列:
1.运行单记录 INSERT 命令。
2.在每次提交中分批成 100 到 1000 行。可以使用事务块在每次提交时包含多条记录。
3.运行INSERT命令,使用多个行的value值。
4.运行 COPY 命令。
将数据加载到数据库的首选方法是使用 COPY 命令。如果无法使用 COPY 命令,则使用分批提交处理 INSERT 是次优方法。
另外使用 COPY 命令进行多线程处理是批量加载数据的最佳方法。
初始数据加载的最佳做法
删除索引
在执行初始数据加载之前,建议删除表中的所有索引。在加载数据后创建索引,这样加载速度更快。
删除约束
下面描述了有关删除约束:
唯一键约束
建议在执行初始数据加载之前删除唯一键约束,并在数据加载完成后重新创建这些约束。但是删除唯一键约束会引发重复数据。
外键约束
建议执行初始数据加载之前删除外键约束,并在数据加载完成后重新创建这些约束。
将session_replication_role参数更改为replica也会禁用所有外键。注意,如果使用不当,进行更改可能会导致数据处于不一致状态。
无日志记录表
在初始数据加载中使用无日志记录表之前,考虑使用此类表的优点和缺点。
优点:
使用无日志记录表可以加快数据加载速度。写入无日志记录表的数据不会写入预写日志。
缺点:
数据库崩溃时不安全。发生崩溃或者执行不彻底的关机后,无日志记录表将被自动截断,无法恢复。
无日志记录表中的数据无法复制到备用服务器。
使用以下语法创建新的无日志记录表:
CREATE UNLOGGED TABLE <tablename>;
使用以下语法将现有日志记录表转换为无日志记录表:
ALTER TABLE <tablename> SET UNLOGGED;
服务器参数优化
autovacuum:在初始数据加载期间,最好关闭 autovacuum进程,初始加载完成后,建议对数据库中的所有表手动运行VACUUM ANALYZE,然后打开autovacuum进程。
备注:
请仅在内存和磁盘空间足够时遵循以下的建议。
maintenance_work_mem:建议在数据库服务器上设置为2GB。
maintenance_work_mem有助于加快autovacuum,索引和外键的创建。
checkpoint_timeout:在数据库服务器上,可将checkpoint_timeout值从默认设置5分钟增加到最大24小时。建议最初在灵活服务器上加载数据之前将该值增加到1小时。
最终生产上设置多大值需要结合业务上dml操作的频繁度,在安全和性能之间权衡。
checkpoint_completion_target:建议设置为值0.9。
max_wal_size:可设置为允许的最大值(执行初始数据加载时设置为64 GB)。
在业务高峰期,该参数通过以下方法得出一个合理值:
a. 运行以下查询获取当前的WAL日志序列号(LSN):
SELECT sys_current_wal_lsn ();
b. 等待checkpoint_timeout的秒数。运行以下查询获取当前的WAL LSN:
SELECT sys_current_wal_lsn ();
c. 使用这两个结果来检查差异(以 GB 为单位):
SELECT round (sys_wal_lsn_diff('LSN value when run second time','LSN value when run first time')/1024/1024/1024,2) WAL_CHANGE_GB;
wal_compression:可以打开。启用此参数可能会导致WAL日志记录期间的压缩和WAL日志重放期间的解压缩产生一些额外的CPU成本。
推荐
在数据库上开始初始数据加载之前建议:
在服务器上禁用高可主备流复制。在主库上完成初始加载后,再启用流复制。
在初始数据加载期间尽量减少日志记录量或完全禁用它(例如:禁用pgaudit、sys_stat_statements)。
加载数据后重新创建索引并添加约束
可以修改以下参数,在初始数据加载后更快地创建并行索引:
max_parallel_workers:可为并行查询提供的最大工作进程数。
max_parallel_maintenance_workers:控制可在CREATE INDEX中使用的最大工作进程数。
还可以通过在会话级别设置创建索引。 以下示例演示如何执行此操作:
SET maintenance_work_mem = '2GB';
SET max_parallel_workers = 16;
SET max_parallel_maintenance_workers = 8;
CREATE INDEX test_index ON test_table(test_column);
增量数据加载的最佳做法
将表分区
建议将大型表分区(尤其是千万行以上的大表)。 分区的一些优点(尤其是在增量加载期间)包括:
1.基于新增量数据创建新分区可以更高效地将新数据添加到表中。
2.为了表的维护更容易,可以在增量数据加载期间删除分区,以避免在大型表维护中进行耗时的删除。
3.仅增量加载期间更改或添加的分区上会触发Autovacuum,这使得可以更轻松地维护表中的统计信息。监视和维护表统计信息准确对于数据库的查询性能至关重要。
基于外键约束创建索引
以下情况下,在子表中基于外键创建索引可能有好处:
在父表中更新或删除数据。在父表中更新或删除数据时,将对子表执行查找,为加快查找速度,可以对子表的外键进行索引。
父表和子表的联接出现在键列上的查询。
识别未使用的索引
识别数据库中未使用的索引并删除。索引是数据加载的开销。表中的索引越少,数据加载期间的性能就越好。
索引使用情况
使用以下查询来识别未使用的索引:
SELECT
t.schemaname,
t.tablename,
c.reltuples::bigint AS num_rows,
sys_size_pretty(sys_relation_size(c.oid)) AS table_size,
ps.indexrelname AS index_name,
sys_size_pretty(sys_relation_size(i.indexrelid)) AS index_size,
CASE WHEN i.indisunique THEN 'Y' ELSE 'N' END AS "unique",
ps.idx_scan AS idx_number_of_scans,
ps.idx_tup_read AS idx_tuples_read,
ps.idx_tup_fetch AS idx_tuples_fetched
FROM
sys_tables t
LEFT JOIN sys_class c ON t.tablename = c.relname
LEFT JOIN sys_index i ON c.oid = i.indrelid
LEFT JOIN sys_stat_all_indexes ps ON i.indexrelid = ps.indexrelid
WHERE
t.schemaname NOT IN ('sys_catalog','pg_catalog','information_schema')
ORDER BY 1, 2;
idx_number_of_scans、idx_tuples_read 和 idx_tuples_fetched 列将指示索引使用情况。idx_number_of_scans 列值为零表示未使用的索引。