外部テーブルに対する一括挿入の高速化 – PostgreSQL 14でコミットされた機能の先行紹介:技術者Blog
PostgreSQLインサイド

綱川 貴之

富士通株式会社
ソフトウェアプロダクト事業本部 データマネジメント事業部
シニアプロエンジニア

はじめに

富士通のシニアディレクターであるAmit Kapilaが率いる"グローバルPostgreSQL開発チーム"は、当社のPostgreSQLに対する取り組みの一環として、コミュニティーへ継続的な貢献を行っています。私はこのチームの一員として、世界中の才能ある情熱的なコミュニティーメンバーとともに、PostgreSQLの発展に積極的に取り組んでいます。
私たちのチームは、メンバーが取り組んだ機能やパッチに焦点を当て、ブログ記事を発信していきます。この記事では、PostgreSQL 14にコミットされた「外部テーブルに対する一括挿入の高速化」について、それに取り組んだ理由と、エキサイティングな性能向上の成果をご紹介します。

なぜこの開発に取り組んだか?

綱川
私たちのチームは、PostgreSQLのスケーラビリティーや性能の向上に注力しています。大きな目標の1つは、書き込みスケールアウトを実現することです。これにより、PostgreSQLを適用できるワークロードをさらに広げたいと考えています。
スケールアウトのための複数サーバー間のやりとりには、外部データラッパー(以降、FDWと略します)機構に基づくpostgres_fdwを用いるアイデアが、コミュニティーでは有望であり現実的だと考えられています。なぜなら、postgres_fdwは長年にわたり、数多くの開発者による改善を積み重ねてきているからです。
そのようなときに私たちは、PostgreSQLコミッターであるTomas Vondra氏がpostgres_fdwによる一括挿入を速くしようとしているのを見ました。彼が言うには、FDWを使ってシャード化したデータベースへの挿入が遅いという問題を、顧客からよく報告されるそうです。
あるユーザーもPostgreSQLのバグ報告用メーリングリストに、同様の問題を報告しました。その報告では、Google Cloud上でpostgres_fdwを使ってシャード化したデータベースに対し、INSERT SELECT文で2,000万行を挿入するのに、1時間50分もかかったといいます。シャード化しない場合は8分で完了したのに比べると、14倍も遅いということです。
遅い原因は、ネットワークのレイテンシーと通信回数です。現在のFDW機構では、FDWが1行ずつ外部テーブルに行を挿入します。そのたびに、遠隔のサーバーとの往復通信が生じるのです。
Tomas Vondra氏たちはpostgres_fdwのみを変更し、まとめて複数の行を外部サーバーに送る方法を試行していました。しかし、エグゼキュータを変更せずに済ませる方法を模索している間に、開発が3か月ほど止まっていたのです。

どのような機能を開発したか?

綱川
そこで私は、次のような提案をしました。外部サーバーに複数行を一括して送るというアイデアは、Tomas Vondra氏のものと同じです。

  • FDWインターフェイスに、一括行挿入のための以下の関数を新たに追加する。
    • BeginForeignBatchInsert
    • ExecForeignBatchInsert
    • EndForeignBatchInsert
    • GetForeignBatchSize
  • ExecForeignBatchInsert()は行の配列と行数を受け取り、それらの行を一括して外部サーバーに送る。
  • executorは複数の行を蓄積し、まとめてFDWに渡す。蓄積する行数は、GetForeignBatchSize()でFDWから取得する。
  • postgres_fdwは、渡された行配列を使って「INSERT ... VALUES (row 1), (row 2), ..., (row n)」文を組み立てて、外部サーバーでそれを実行する。
  • postgres_fdwの外部サーバーと外部テーブルの設定に、batch_sizeオプションを新たに追加し、利用者が外部テーブルごとに一括して挿入する行数を指定できるようにする。

これは、実に素直でシンプルなつくりです。
これにより、INSERT SELECT文だけでなく、複数行を指定したINSERT VALUES文も速くなります。アプリケーションを変更する必要はありません。
上記のインターフェイスは、oracle_fdwやmysql_fdwといった、他のデータベース用のFDWでも素直に実装できるはずです。

どれだけ速くなったか?

綱川
まず、単純なテーブルに対するデータ挿入を測定してみました。対象テーブルは1つのint型のプライマリキー列と、1つのtext型の列を持ちます。
別のテーブルからそのテーブルに、INSERT SELECT文で100万件の行を挿入するのにかかった時間は次のとおりです。このとき、postgres_fdwのbatch_sizeパラメーターの設定値は100です。つまり、一度に最大で100行を外部サーバーに送ります。

処理条件 処理時間
FDWなしのローカルテーブル 6.1秒
FDWを使ったリモートテーブル(PostgreSQL 13の場合) 125.3秒
FDWを使ったリモートテーブル(PostgreSQL 14の場合) 11.1秒

すばらしい!11倍も速くなりました。
次に、同じ列からなる対象テーブルを8つのハッシュパーティションに分割しました。同様に、INSERT SELECT文で100万行を挿入するのにかかった時間は次のとおりです。

処理条件 処理時間
FDWなしのローカルテーブル 8.6秒
FDWを使ったリモートテーブル(PostgreSQL 13の場合) 113.7秒
FDWを使ったリモートテーブル(PostgreSQL 14の場合) 12.5秒

これも良いですね!9倍の速度向上です。
なお、この測定では、外部サーバーを同じホストに配置しました。「ping localhost」で測定されるネットワーク・レイテンシーは34マイクロ秒です。これほど小さなレイテンシーでも大きな性能向上が見られたということは、クラウドなどのより大きなネットワーク・レイテンシーを伴う環境では、この機能の効果はさらに大きいでしょう。

さらなる高速化への期待

綱川
この機能により、1つの外部テーブルへのデータ追加が劇的に速くなりました。ただ、これは単一のCPUを使った逐次処理の高速化です。
一方、私の同僚のGreg Nancarrowは、複数のCPUを使ってINSERT SELECT文を並列に処理できるようにする開発に取り組んでいます。また別の開発者たちは、CREATE TABLE AS SELECT(CTAS)文を並列化しようとしています。
これらを組み合わせることで、シャード化されたOLTPデータベースへのデータ移行や、データウェアハウスへのETL処理がさらに高速化する可能性に期待します。今後、また良いお知らせができることを楽しみにしています。

謝辞

綱川
この機能が比較的早くコミットされたことについて、Tomas Vondra氏やAmit Langote氏をはじめとする開発者の方々に深く感謝いたします。彼らの素早く熱心なフィードバックのおかげで、この機能を実現できたと考えています。

2021年3月26日公開

オンデマンド(動画)セミナー

    • PostgreSQLに関連するセミナー動画を公開中。いつでもセミナーをご覧いただけます。
      • 【事例解説】運送業務改革をもたらす次世代の運送業界向けDXプラットフォームの構築
      • ハイブリッドクラウドに最適なOSSベースのデータベースご紹介

本コンテンツに関するお問い合わせ

お電話でのお問い合わせ

Webでのお問い合わせ

当社はセキュリティ保護の観点からSSL技術を使用しております。

ページの先頭へ