本番データなしで本番クエリプランを生成
PostgreSQL 18が導入した統計情報複製機能により、本番環境の大量データをコピーせずとも開発環境で本番同等のクエリ計画をシミュレーション可能となった。
キーポイント
PostgreSQL 18の新統計複製機能
`pg_restore_relation_stats()`と`pg_restore_attribute_stats()`により、本番環境の統計情報を開発環境へエクスポート・インポート可能になった。
クエリ計画の乖離解消とテスト効率化
統計情報の注入により、インデックススキャンかフルテーブルスキャンかといった実行計画を本番環境に近づけてテスト可能となり、環境間の性能差によるデバッグコストが削減される。
データ転送の軽量化とプライバシー保護
数百GBに及ぶ本番データのコピー不要で、統計ダンプは1MB未満のテキストファイルで完結するため、環境構築が高速化し機密データ漏洩リスクも回避できる。
SQLiteとの機能比較と業界標準化
SQLiteは既存の`sqlite_stat1`/`sqlite_stat4`テーブルで同様の統計注入機能を提供しており、オープンソースDB界隈ではクエリ計画制御の標準的な手法として定着しつつある。
影響分析・編集コメントを表示
影響分析
本機能は開発環境と本番環境のクエリ計画の乖離という長年の課題を解決し、データベースのパフォーマンステストやデバッグの効率を大幅に向上させる。特に大規模データ処理やML基盤を運用するチームにとって、環境構築コストを削減しつつ本番同等の負荷テストを可能にするため、インフラエンジニアリングのベストプラクティスに組み込まれることが期待される。
編集コメント
統計情報のみを軽量に転送するこのアプローチは、データプライバシーを維持しつつ本番同等のテスト環境を構築する現代的なインフラ設計に適合しており、MLパイプラインのCI/CDプロセスにも即座に応用できる実用的な改善である。
Radim Marek は、2025 年 9 月に PostgreSQL 18 で導入された新しい pg_restore_relation_stats() および pg_restore_attribute_stats() 関数 について説明しています。
PostgreSQL のクエリプランナーは、最適な実行方法を決定するために内部統計情報を利用します。これらの統計情報は、本番データと開発環境の間でしばしば異なるため、本番で使用されるクエリプランを開発環境で再現できない場合があります。
PostgreSQL の新機能により、これらの統計情報を開発環境にコピーできるようになりました。これにより、すべてのデータを事前にコピーする必要なく、本番ワークロードのプランをシミュレートすることが可能になります。
私はこの例が非常に参考になると感じました:
SELECT pg_restore_attribute_stats(
'schemaname', 'public',
'relname', 'test_orders',
'attname', 'status',
'inherited', false::boolean,
'null_frac', 0.0::real,
'avg_width', 9::integer,
'n_distinct', 5::real,
'most_common_vals', '{delivered,shipped,cancelled,pending,returned}'::text,
'most_common_freqs', '{0.95,0.015,0.015,0.015,0.005}'::real[]
);
これは、95% が配送済みであるステータス列の統計情報をシミュレートするものです。これらの統計情報に基づき、PostgreSQL は status = 'shipped' の場合にインデックスを使用することを決定できますが、status = 'delivered' の場合は代わりにフルテーブルスキャンを実行します。
これらの統計情報は非常に小さいサイズです。Radim 氏は次のように述べています:
統計情報のダンプは極めて小型です。数百のテーブルと数千の列を持つデータベースであっても、その統計情報ダンプは 1MB に満たないテキストファイルに収まります。一方、実際の生産データは数百 GB に及ぶ可能性があります。それを記述する統計情報はテキストファイルに収まるサイズなのです。
私は SQLite ユーザーフォーラムで、SQLite も同様の機能を提供できないかと質問しました。すると D. Richard Hipp 氏が即座に 既にあると回答 してくれました:
クエリプランナーが使用する SQLite のすべてのデータ統計情報は、sqlite_stat1 テーブル(または SQLITE_ENABLE_STAT4 を指定してコンパイルしている場合は sqlite_stat4 テーブル)で利用可能です。このテーブルは書き込み可能であり、好きな代替統計情報を注入することができます。
クエリプランナーを制御するためのこのアプローチについては、ドキュメントでも言及されています:
https://sqlite.org/optoverview.html#manual_control_of_query_plans_using_sqlite_stat_tables。
また、以下のページも参照してください:
https://sqlite.org/lang_analyze.html#fixed_results_of_analyze。
CLI の".fullschema"コマンドは、上記の理由により、スキーマと sqlite_statN テーブルの内容の両方を出力します。これにより、数テラバイトに及ぶデータベースファイルをロードする必要なく、テストのためにクエリの問題を再現することが可能になります。
Via Lobste.rs
Tags: databases, postgresql, sql, sqlite, d-richard-hipp
原文を表示
Production query plans without production data
Radim Marek describes the new pg_restore_relation_stats() and pg_restore_attribute_stats() functions that were introduced in PostgreSQL 18 in September 2025.
The PostgreSQL query planner makes use of internal statistics to help it decide how to best execute a query. These statistics often differ between production data and development environments, which means the query plans used in production may not be replicable in development.
PostgreSQL's new features now let you copy those statistics down to your development environment, allowing you to simulate the plans for production workloads without needing to copy in all of that data first.
I found this illustrative example useful:
SELECT pg_restore_attribute_stats(
'schemaname', 'public',
'relname', 'test_orders',
'attname', 'status',
'inherited', false::boolean,
'null_frac', 0.0::real,
'avg_width', 9::integer,
'n_distinct', 5::real,
'most_common_vals', '{delivered,shipped,cancelled,pending,returned}'::text,
'most_common_freqs', '{0.95,0.015,0.015,0.015,0.005}'::real[]
);
This simulates statistics for a status column that is 95% delivered. Based on these statistics PostgreSQL can decide to use an index for status = 'shipped' but to instead perform a full table scan for status = 'delivered'.
These statistics are pretty small. Radim says:
Statistics dumps are tiny. A database with hundreds of tables and thousands of columns produces a statistics dump under 1MB. The production data might be hundreds of GB. The statistics that describe it fit in a text file.
I posted on the SQLite user forum asking if SQLite could offer a similar feature and D. Richard Hipp promptly replied that it has one already:
All of the data statistics used by the query planner in SQLite are available in the sqlite_stat1 table (or also in the sqlite_stat4 table if you happen to have compiled with SQLITE_ENABLE_STAT4). That table is writable. You can inject whatever alternative statistics you like.
This approach to controlling the query planner is mentioned in the documentation:
https://sqlite.org/optoverview.html#manual_control_of_query_plans_using_sqlite_stat_tables.
See also https://sqlite.org/lang_analyze.html#fixed_results_of_analyze.
The ".fullschema" command in the CLI outputs both the schema and the content of the sqlite_statN tables, exactly for the reasons outlined above - so that we can reproduce query problems for testing without have to load multi-terabyte database files.
Via Lobste.rs
Tags: databases, postgresql, sql, sqlite, d-richard-hipp
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み