少量の行を挿入しようとするクライアント接続に関連付けられているpostmaster
子プロセスによるCPU使用率が高い(結果として行が挿入される25x遅い _COPY ... FROM STDIN
_(同じ行の場合)。
前述の不十分なINSERTパフォーマンスを軽減するためにシステム/データベース構成を特定しようとしています。データを処理し、結果をINSERTに戻すためにマルチスレッドRスクリプトを使用していますPostgreSQLデータベース。子Rによって開かれた接続に関連付けられたtop
子プロセスを監視するためにpostmaster
を使用しながら、DBI::dbBind()
呼び出しへのパフォーマンスボトルネックを分離するためにRスクリプトをプロファイルしましたスレッド(以下のcodeを参照)。 INSERTの間、Rの子プロセスはほとんどアイドル状態で実行されます(おそらくDBI::dbBind()
呼び出しの戻りを待機しています)が、postmaster
の子プロセスは、約100%実行されるコアでCPUを95-100%消費します。 2〜3分。
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
_
_/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
...
_
テスト中のデータベーステーブルは、RAID 10構成のSSDドライブのペアにあり、ログとWALは別々のドライブにあります(ベースライン_COPY ... FROM STDIN
_にはパフォーマンスの問題がないため、以下を参照してください タイミングにはbash sync
return time)および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
_
また、(一時的に)_/lib/systemd/system/postgresql.service.d/10-postgresql-unlimited.conf
_で次のことを試しても効果はありません(実際にはパフォーマンスのわずかな低下):[[〜#〜] warning [〜#〜]カジュアルな読者の場合、次の設定は[〜#〜]ではありません[〜#〜]の使用が推奨されています]
_# 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
_
各パーティションテーブルには180のパーティションがあり、42から81の列(_double precision
_タイプの)があります。
[〜#〜] nb [〜#〜]:これらは理想的なテーブルよりも幅が広く、推奨よりも多くのパーティションがありますが、列の数を12に、パーティションの数を30に設定すると、INSERTのパフォーマンスが低下する可能性があります。
現在PostgreSQLに基づいていますODBCドライバ(複数行の準備済みステートメントで作業できるのは1つだけです)
_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);
_
odbc
およびRPostgres
ドライバー)および(B)準備済みステートメントを使用せずに複数行のINSERT SQL文字列をアセンブルします。COPY ... FROM STDIN
_に基づく-次のコマンドを含む単純なbashスクリプト(28個のテーブルのそれぞれに1つ):_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
_
DBI::dbBind()
の結果であるINSERT中の_vmstat -wt 1
_のmax/avg/min値は、次のようになります。
_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
_
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
_
準備されたSQLステートメントの変更により、6倍の改善が得られました。
SQLの変更点:
INSERT INTO <table> (<col_1>,...,<col_n>) VALUES (?,...,?);
...
INSERT INTO <table> (<col_1>,...,<col_n>) VALUES (?,...,?);
に:
INSERT INTO <table> (<col_1>,...,<col_n>) VALUES
(?,...,?),
...
(?,...,?);
つまり、複数のINSERTステートメントを1つのステートメントにまとめたため、時間が390秒から66秒に、つまり56行/秒に短縮されました。まだ遅い側にありますが、残りのレイテンシがアプリケーションまたはデータベースに関連しているかどうかを確認するには、実行を再プロファイルする必要があります。