web-dev-qa-db-ja.com

PostgreSQL INSERTパフォーマンスの低下に対処するためのシステム構成

問題の症状

少量の行を挿入しようとするクライアント接続に関連付けられている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分。

システム/環境:

  • postgresqlバージョン10.3(Fedoraパッケージ10.3-5.fc27)
  • _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で待機しているようには見えません。ディスクのパフォーマンスが問題を引き起こしているとは考えていません)

Postgresの設定:

データベースプロファイル:

コード(R):

  • 現在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);
    _
    • [〜#〜] nb [〜#〜]同様のパフォーマンスで以下を使用しました:(A)INSERTが1つだけの準備されたステートメント(両方ともodbcおよびRPostgresドライバー)および(B)準備済みステートメントを使用せずに複数行のINSERT SQL文字列をアセンブルします。

パフォーマンスレポート:

ベースライン

  • _COPY ... FROM STDIN_に基づく-次のコマンドを含む単純なbashスクリプト(28個のテーブルのそれぞれに1つ):_cat <tablename>.out | psql -c 'COPY <tablename> FROM STDIN;'_
  • 28秒のパーティション分割されたテーブルそれぞれに11,117行を14秒で挿入=> 22,234 REC /秒(または4.5e-5秒/行)
  • _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
    _

現在

  • 単一のトランザクションブロック内で複数行の準備されたステートメントをバインドする場合(codeを参照)、28のそれぞれに同じ行を挿入するのに390秒かかります9行/秒の合計スループットのための分割テーブル(ベースラインの22,234行/秒と比較)
  • 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
    _

その他の注意事項:

  • 単一または複数のR子スレッド(つまり、1つまたは複数のデータベースクライアント接続)を実行するときにパフォーマンスに影響はありません。
  • RPostgresRPostgreSQL、およびodbc Rパッケージをデータベースドライバーとして使用しようとしました(ドライバー間にわずかなパフォーマンスの違いはありますが、実装固有のアーティファクトは、処理時間)。
  • SQLのEXPLAIN ANALYZEに取り組んでいますが、 潜在的なカーネル設定/データベース構成/ SystemD設定/などに関する事前の考えを歓迎します。

前もって感謝します。

アップデート(2018.11.28)

  • Rスクリプトによって生成されたINSERTステートメントを使用してSQLフラットファイルを作成し(ステートメントを_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
    _
2
Whee

準備された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行/秒に短縮されました。まだ遅い側にありますが、残りのレイテンシがアプリケーションまたはデータベースに関連しているかどうかを確認するには、実行を再プロファイルする必要があります。

1
Whee