Whe*_*hee 5 postgresql performance configuration r postgresql-10 postgresql-performance
postmaster
与尝试插入低容量行的客户端连接相关的子进程的 CPU 使用率较高(导致插入的行比使用相同行慢 25 倍)。COPY ... FROM STDIN
尝试识别系统/数据库配置以缓解上述较差的插入性能。我正在使用多线程 R 脚本来处理数据并将结果插入到 PostgreSQL 数据库中。我对 R 脚本进行了分析,以隔离调用的性能瓶颈DBI::dbBind()
,同时用于top
监视postmaster
与子 R 线程打开的连接关联的子进程(请参阅下面的代码)。在 INSERT 期间,R 子进程大部分时间处于空闲状态(大概是在等待调用返回DBI::dbBind()
),而postmaster
子进程在其运行大约 2-3 分钟的时间内消耗了 95-100% 的 CPU。
uname -a
:Linux localhost 4.16.6-202.fc27.x86-64 #1 SMP Wed May 2 00:09:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
/proc/cpuinfo
: 16 个处理器 ( Intel(R) Xeon(R) CPU D-1541 @ 2.10GHz
)ulimit -a
:
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 515220
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 515220
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
Run Code Online (Sandbox Code Playgroud)/proc/meminfo
(在postmaster
处理 INSERT 时的任意时间):
MemTotal: 131923484 kB
MemFree: 112894260 kB
MemAvailable: 123181440 kB
Buffers: 201220 kB
Cached: 14932288 kB
SwapCached: 0 kB
...
Mlocked: 0 kB
SwapTotal: 201326588 kB
SwapFree: 201326588 kB
Dirty: 3260 kB
...
Shmem: 4251184 kB
Slab: 1024344 kB
SReclaimable: 658476 kB
SUnreclaim: 365868 kB
...
PageTables: 38436 kB
...
CommitLimit: 267288328 kB
Committed_AS: 35678744 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
...
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
...
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
Hugetlb: 0 kB
...
Run Code Online (Sandbox Code Playgroud)测试中的数据库表驻留在 RAID 10 配置中的一对 SSD 驱动器上,日志记录和 WAL 位于单独的驱动器上(因为基线COPY ... FROM STDIN
没有写入性能问题——见下文——(计时还包括 bashsync
返回时间)并且 CPU 通常不会出现等待 IO,不相信磁盘性能存在瓶颈)
其中一些在尝试识别配置更改时可能显得有点高(请随意注意给定我的系统的任何“疯狂”设置 - 假设服务器主要作为数据库服务器运行)
max_connections = 20 # (change requires restart)
shared_buffers = 32GB # min 128kB
temp_buffers = 128MB # min 800kB
max_prepared_transactions = 20 # Allow 'max_connections'
work_mem = 16MB # min 64kB
max_stack_depth = 6MB # min 100kB
dynamic_shared_memory_type = posix # the default is the first option
max_wal_size = 5GB
checkpoint_flush_after = 1MB # measured in pages, 0 disables
deadlock_timeout = 15s
max_locks_per_transaction = 2096 # min 10
Run Code Online (Sandbox Code Playgroud)还(暂时)尝试了以下设置,/lib/systemd/system/postgresql.service.d/10-postgresql-unlimited.conf
但没有效果(实际上性能略有下降):[警告对于临时读者,不建议使用以下设置]
# DO NOT USE THIS IN PRODUCTION (or elsewise)
[Service]
LimitDATA=infinity
LimitFSIZE=infinity
LimitLOCKS=infinity
LimitMEMLOCK=infinity
LimitMSGQUEUE=infinity
LimitNPROC=infinity
LimitNOFILE=infinity
LimitSIGPENDING=infinity
Run Code Online (Sandbox Code Playgroud)每个分区表有 180 个分区和 42 到 81 个列(类型double precision
)。
注意:虽然这些表比理想情况更宽,并且分区比推荐的要多,但我尝试将列数减少到 12,将分区数减少到 30,但 INSERT 性能相当差。
目前基于 PostgreSQL ODBC 驱动程序(只有一个我可以使用多行准备好的语句)
library(odbc);
cdb <- DBI::dbConnect(drv=odbc::odbc(),driver="PostgreSQL",...);
on.exit({DBI::dbDisconnect(cdb);}, add=TRUE);
DBI::dbBegin(cdb);
sth <- DBI::dbSendStatement(cdb,paste(rep("INSERT INTO <table> (<col_1>,...,<col_n>) VALUES (?,...,?);",100),collapse="")); # Bind up to 8,000 placeholders at a time (ref in source?) -- use 100 multi-line statements in this example
DBI::dbBind(sth,bvallist); # Here, 'bvallist' is a list of values to bind in the multi-line prepared statement -- have tested and checked values in database are correct after INSERT
num_recs <- DBI::dbGetRowsAffected(sth);
DBI::dbClearResult(sth);
DBI::dbCommit(cdb);
Run Code Online (Sandbox Code Playgroud)
odbc
以及RPostgres
(B) 在不使用预准备语句的情况下组装多行 INSERT SQL 字符串。COPY ... FROM STDIN
-- 一个简单的 bash 脚本,包含以下命令(28 个表中的每个表一个):cat <tablename>.out | psql -c 'COPY <tablename> FROM STDIN;'
vmstat -wt 1
信息COPY ... FROM STDIN
(基于 16 个处理器的 CPU 信息):
procs -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu-------- -----timestamp-----
r b swpd free buff cache si so bi bo in cs us sy id wa st EST
2 0 0 113563384 200600 15965816 0 0 0 696 4178 1518 14 1 85 0 0 2018-11-27 14:29:19
2 0 0 113562280 200600 15967184 0 0 0 1483 4781 1727 14 1 84 0 0 2018-11-27 14:29:20
3 0 0 113564520 200604 15962952 0 0 0 1123 4847 1790 15 2 83 0 0 2018-11-27 14:29:21
3 0 0 113565664 200604 15962020 0 0 0 800 4512 1646 15 2 84 0 0 2018-11-27 14:29:22
>>>>>>>> START: COPY ... FROM STDIN bash script (Tue Nov 27 14:29:23 EST 2018)
3 0 0 113566992 200604 15960036 0 0 0 760 4730 1655 14 2 84 0 0 2018-11-27 14:29:23
3 1 0 113551160 200604 15961608 0 0 0 9704 5271 5025 15 3 82 1 0 2018-11-27 14:29:24
3 0 0 113548176 200604 15966864 0 0 0 8764 6269 6335 19 3 77 1 0 2018-11-27 14:29:25
3 0 0 113552104 200604 15969684 0 0 0 7744 6331 5648 19 3 77 1 0 2018-11-27 14:29:26
1 0 0 113521248 200604 15975508 0 0 0 8624 3717 5478 9 2 89 0 0 2018-11-27 14:29:27
2 0 0 113535536 200604 15976840 0 0 0 12563 4982 8784 11 3 86 1 0 2018-11-27 14:29:28
3 0 0 113535640 200604 15978772 0 0 0 11223 5473 6182 12 3 84 1 0 2018-11-27 14:29:29
2 0 0 113533576 200604 15977312 0 0 0 11180 5032 6443 12 3 85 0 0 2018-11-27 14:29:30
2 0 0 113534384 200604 15978180 0 0 0 11169 4961 6511 12 3 86 0 0 2018-11-27 14:29:31
2 0 0 113504656 200604 16004428 0 0 0 32691 4551 13584 10 3 84 2 0 2018-11-27 14:29:32
2 0 0 113486672 200604 16023572 0 0 0 26133 4387 8803 10 3 86 2 0 2018-11-27 14:29:33
4 0 0 113459744 200604 16033296 0 0 0 12535 5709 8188 17 3 80 1 0 2018-11-27 14:29:34
1 0 0 113444128 200604 16057612 0 0 0 78953 8980 10186 12 4 82 2 0 2018-11-27 14:29:35
1 1 0 113415520 200604 16087380 0 0 0 23640 5576 8781 15 3 80 1 0 2018-11-27 14:29:36
3 0 0 113400864 200604 16108080 0 0 0 14733 3348 10182 6 2 90 1 0 2018-11-27 14:29:37
<<<<<<<< END : COPY ... FROM STDIN bash script (Tue Nov 27 14:29:37 EST 2018)
1 0 0 113393552 200632 16127372 0 0 0 56640 4456 4481 4 3 93 1 0 2018-11-27 14:29:38
0 1 0 113392368 200632 16127680 0 0 0 1688 2446 1406 2 1 96 0 0 2018-11-27 14:29:39
1 0 0 113391032 200632 16128472 0 0 0 1616 2372 1396 2 1 97 0 0 2018-11-27 14:29:40
0 0 0 113389376 200632 16128440 0 0 0 1896 2474 1402 2 1 96 0 0 2018-11-27 14:29:41
Run Code Online (Sandbox Code Playgroud)vmstat -wt 1
INSERT 期间产生的最大/平均/最小值DBI::dbBind()
如下所示:
procs -----------------------memory---------------------- ---swap-- -----io---- --system-- --------cpu--------
r b swpd free buff cache si so bi bo in cs us sy id wa st
6 1 0 112348416 200092 15661572 0 0 0 10090 12259 37796 32 3 81 4 0 # MAX
3 0 0 111860781 199437 15608955 0 0 0 1708 5658 6371 21 1 78 0 0 # AVG
3 0 0 111353344 199372 15572860 0 0 0 184 4115 1602 17 0 67 0 0 # MIN
Run Code Online (Sandbox Code Playgroud)RPostgres
、RPostgreSQL
和odbc
R 包作为数据库驱动程序(虽然驱动程序之间存在轻微的性能差异,但没有特定于实现的工件似乎对处理时间有显着贡献)。先感谢您。
BEGIN ... COMMIT
事务块内)并使用加载psql -f <file>.sql
- 没有性能改进。在单个 INSERT 上运行EXPLAIN ANALYZE VERBOSE
,输出如下:
Insert on <tablename> (cost=0.00..0.26 rows=1 width=1952) (actual time=0.074..0.074 rows=0 loops=1)
-> Result (cost=0.00..0.26 rows=1 width=1952) (actual time=0.006..0.007 rows=1 loops=1)
Output: <row data>
Planning time: 0.303 ms
Trigger RI_ConstraintTrigger_c_274329 for constraint <foreign_key_constraint_name> on <child_tablename>: time=0.071 calls=1
Execution time: 13.345 ms
Run Code Online (Sandbox Code Playgroud)对准备好的 SQL 语句进行更改后,性能提高了六倍。
SQL 更改为:
INSERT INTO <table> (<col_1>,...,<col_n>) VALUES (?,...,?);
...
INSERT INTO <table> (<col_1>,...,<col_n>) VALUES (?,...,?);
Run Code Online (Sandbox Code Playgroud)
到:
INSERT INTO <table> (<col_1>,...,<col_n>) VALUES
(?,...,?),
...
(?,...,?);
Run Code Online (Sandbox Code Playgroud)
换句话说,我将多个 INSERT 语句折叠为单个语句,这将时间从 390 秒减少到 66 秒,即 56 行/秒。虽然速度仍然较慢,但需要重新分析执行情况,看看剩余的延迟是否与应用程序或数据库相关。