このページでは PostgreSQL 9.6 (2016年9月29日リリース)に関する技術情報をお届けします。
本ドキュメントは PostgreSQL のリリースノートを元に弊社で解説を加えたものです。
バージョン9.6の主な拡張点
バージョン9.6での主な拡張箇所は以下の通りです。
- シーケンシャルスキャン、結合、集約のパラレル実行に対応しました。
- 自動VACUUMは古いデータを繰り返しスキャンしなくなります。
- 同期レプリケーションで複数スタンバイサーバが可能になりました。
- 全文検索でフレーズ(隣接した複数語)の検索に対応しました。
- postgres_fdw がリモートでの結合、ソート、UPDATE、DELETE に対応しました。
- 特に複数CPUソケットサーバでのスケーラビリティにおいて性能改善しました。
バージョン9.6への移行/互換性のない変更点
- pg_stat_activityビューのプロセスロック待ちの列が拡張されました。 (Amit Kapila, Ildus Kurbangaliev) (9.6)
- to_char() 関数で日付時間のテンプレートパターンについて、マイナス記号をフィールド幅の一部として数えなくなりました。 (Bruce Momjian) (9.6)
重量ロック(SQLレベルでのロック)を待機しているかを示すboolean型の waiting列が無くなり、それに代わってロックの種類を示す wait_event_type列と wait_event列が追加されました。待機していなければ、新たな2つの列は共にNULLになります。
これからは重量ロック(wait_event_type が'Lock'になります)のみならず、軽量ロック(同じく'LWLockNamed'または'LWLockTranche')やバッファピン('BufferPin')の待機も表示されるようになります。
pg_stat_activityビューの waiting列を参照していたプログラムは修正が必要です。
期待される出力結果が変わることになります。以下例は、従来は「-04」でなく「-4」が返りました。
db1=# SELECT to_char('-4 years'::interval, 'YY'); to_char --------- -04 (1 row)
単調増加する要素(YEAR、EPOCH)については infinity、-infinity が返り、それ以外の要素(DAY、HOUR、等)については NULL が返るようになりました。これまでは入力のタイムスタンプが 'infinity' または '-infinity' であるなら、フィールド指定が何であるかにかかわらず 0 が返っていました。
(9.6 での動作例) db1=# SELECT EXTRACT(MONTH FROM 'infinity'::timestamp); date_part ----------- *NULL* (1 row) db1=# SELECT EXTRACT(YEAR FROM '-infinity'::timestamp); date_part ----------- -Infinity (1 row)
以下のように実行したとき、これまでは「CONTEXT:」の行が出力されませんでした。
db1=# CREATE OR REPLACE FUNCTION f_raisetest() RETURNS void LANGUAGE plpgsql AS $$ BEGIN RAISE EXCEPTION 'test' ; RETURN; END; $$; CREATE FUNCTION db1=# SELECT f_raisetest(); ERROR: test CONTEXT: PL/pgSQL function f_raisetest() line 1 at RAISE
to_tsvector() や to_tsquery() の動作が変わり、僅かながら検索結果が変わります。メールアドレスを切り出すには新たな動作の方が適しています。
(9.5以前の動作例) db1=# SELECT to_tsvector('simple', 'foo@123_mail.sraoss.co.jp'); to_tsvector --------------------------------------- '123':2 'foo':1 'mail.sraoss.co.jp':3 (1 row) (9.6の動作例) db1=# SELECT to_tsvector('simple', 'foo@123_mail.sraoss.co.jp'); to_tsvector ------------------------------- 'foo@123_mail.sraoss.co.jp':1 (1 row)
従来のバージョンはいくつかの一般的でない発音区別符号付き文字に対応していませんでした。 また、これからは合字がばらばらの文字に展開されます。
このルールファイルを使う(アップグレードした)インストール先では、tsvector列とインデックスの再構築が必要です。
CREATEUSER は古い後方互換性のためにあり、実際には SUPERUSER を意味しました。これは CREATEROLE と同じ意味かと間違えやすく、常に混乱のもととなってきました。
今後は pg_ で始まるロール名は作成できません。
(9.6 でエラーになる例) $ initdb -U pg_admin /data/pgdata initdb: superuser name "pg_admin" is disallowed; role names cannot begin with "pg_" $ psql -q db1 db1=# CREATE ROLE pg_nobody; ERROR: role name "pg_nobody" is reserved DETAIL: Role names starting with "pg_" are reserved.
SQL:2011 標準では長い方の名前(..._character_...)を指定していますが、まわりの列名は他のinformation_schemaビューと同様に短い形式(..._char_...)を使っているので、これは誤りのように見えます。
旧来の振る舞いにするには明示的に --no-psqlrc (-X) を指定します。この方法で修正したスクリプトは旧バージョンの psql でも動作します。
通常のテーブルだけでなく、ビュー、外部テーブル、マテリアライズドビュー、シーケンスを指定できるようになりました。
XIDエポック(XIDの周回毎に1増える)とXID値のペアを : で区切る形式になりました。以前の形式は LSN の表示形式と似ていて紛らわしいものでした。
(以前の表示形式) $ pg_controldata | grep NextXID Latest checkpoint's NextXID: 0/31699 (9.6 の表示形式) $ pg_controldata | grep NextXID Latest checkpoint's NextXID: 0:31699
標準拡張モジュールの多くが並列実行できるように更新されました。この変更は旧バージョンからの pg_upgrade では適用されません。バージョンアップ後に ALTER EXTENSION UPDATE を各拡張モジュールについてデータベース毎に実行する必要があります。
バージョン 9.6 の変更点
サーバの変更
パラレルクエリ
- パラレルクエリ (Robert Haas, Amit Kapila, David Rowley, many others) (9.6)
- 関数がパラレル処理で安全かを示す機構が提供されます。 (Robert Haas, Amit Kapila) (9.6)
PostgreSQL 9.6 では、大きなクエリをパラレル実行するための初期サポートが導入されました。シーケンシャルスキャンを使ってテーブル参照する、厳密に読み込みだけのクエリは並列化することが可能になります。ハッシュ結合とネストループは並列に実行することができます。集約関数も可能です(サポートされた集約なら)。やるべき事は多数残っていますが、これはすでに便利な機能セットです。
パラレルクエリ実行は(まだ)デフォルトで有効にされていません。有効にするには新しい設定パラメータ(max_parallel_workers_per_gather)を0より大きな値にします。追加の並列処理の実行制御は、新しい設定パラメータforce_paralle_mode, parallel_setup_cost, parallel_tuple_cost,min_parallel_relation_size を通じて行なえます。
プランナが、クエリをパラレル実行しても安全か判断するのに使われます。
インデックス
- GIN インデックス作成が、1GB 以上の maintenance_work_mem 設定を有効に使えるようになりました。 (Robert Abraham, Teodor Sigaev) (9.6)
- GIN インデックスの保留リストから削除されたページは、すぐにフリースペースマップに追加されるようになりました。 (Jeff Janes, Teodor Sigaev) (9.6)
- gin_clean_pending_list 関数が追加され、GIN インデックスの保留リストの掃除を手動で起動できるようになりました。 (Jeff Janes) (9.6)
- GiSTインデックスでのデッドインデックスの扱いが改善されました。 (Anastasia Lubennikova) (9.6)
- box型に対する SP-GiST 演算子クラスが追加されました。 (Alexander Lebedev) (9.6)
これまでは内部処理の都合で 1GB で制限されていました。
テーブルが頻繁に VACUUM されない場合の膨張を軽減します。これまでは VACUUM が実行されるまで FSM に移動しませんでした。これは挿入のみで VACUUM されないテーブルで問題になることがありました。
以前は、この様な掃除は親テーブルの vacuum や analyze の副作用でしか実行されていませんでした。
インデックススキャンで、対応するヒープタプルが死んでいる事に気付くと、デッドインデックスタプルとしてマークされるようになります。タプルを挿入する際に、ページに空き領域を作る必要があれば、デッドとマークされたタプルは削除されるようになりました。
GiST インデックスページ内のマイクロ VACUUM 処理です。
ソート
- 外部ソートを実行する時は、置換選択ソート(replacement-selection)ではなく、クイックソートを使うことで性能を向上します。(Peter Geoghegan) (9.6)
- テキストのソートで同じ文字列が何度も現れる場合が速くなりました。 (Peter Geoghegan) (9.6)
- uuid, bytea, char(n) フィールドのソートは、短縮キーを使うことで速くなりました。 (Peter Geoghegan) (9.6)
- TID を64ビット整数としてソートすることで CREATE INDEX CONCURRENTLY がスピードアップされました。 (Peter Geoghegan) (9.6)
新しい方式では、典型的なキャッシュサイズやデータ量で、CPU キャッシュをより有効に使います。必要な時は、新しい設定パラメータ replacement_sort_tuples で振る舞いを調整することができます。
短縮キー(abbreviated keys)のサポートが、デフォルトではない演算子クラスtext_pattern_ops, varchar_pattern_ops, bpchar_pattern_ops にも追加されました。順序付き集約の処理でも、短縮キーの利用が可能になっています。
ロック
- ProcArrayLock の競合を減らしました。 (Amit Kapila, Robert Haas) (9.6)
- バッファコンテンツロックを、バッファディスクリプタに移動することで性能が向上されました。 (Andres Freund, Simon Riggs) (9.6)
- 共有バッファヘッダの spinlock をアトミック操作に交換したことで、スケーラビリティを向上しました。 (Alexander Korotkov, Andres Freund) (9.6)
- LWLock の待ちキュー保護に、spinlock ではなく、アトミック操作を使うようになりました。 (Andres Freund) (9.6)
- マルチ CPU ソケットサーバでの競合を軽減するため、共有ハッシュテーブルのフリーリストが分割されました。 (Aleksander Alekseev) (9.6)
- スタンバイサーバで B-Tree インデックスの vacuum 操作を再生する時の内部ロックを軽減しました。 (Simon Riggs) (9.6)
XID をクリアする処理で、複数の書き込みトランザクションが同時に行なわれている時は、ロックを獲得しているプロセスが、他のプロセスの分も処理します。
これによりロックと pin がひとつのキャッシュラインで処理されることになります。
pin/unpin バッファ操作が頻繁に行なわれるのはボトルネックになります。フラグ, usage_count, buf_hdr_lock, refcount をひとつの 32bit アトミック変数として扱うことで、同時に操作することができるようになります。
spinlock してから状態フィールドを操作するのではなく、単純に、状態フラグをアトミック操作することにしました。
フリーリストを分割しない場合、巨大なサーバでは深刻な問題になっていました。
この変更により、その様な再生処理中の、レプリケーション遅延の発生を回避します。
最適化統計
- NULL をたくさん含むカラムでの ANALYZE の見積りを向上しました。 (Tomas Vondra, Alex Shulgin) (9.6)
- クエリ結果に含まれる固有値の数のプランナの推定が改善されました。 (Tomas Vondra) (9.6)
- 結合述部の選択率の推論に、外部キーの関係を利用します。 (Tomas Vondra, David Rowley) (9.6)
これまでの ANALYZE は、多くの NULL を含むカラムでは、NULL でない値の固有値を過小評価していました。また頻出値の計算も不正確になっていました。
アルゴリズムのバグで、NULLの個数を含めたカラム数と、含めないカラム数での計算が混在していて、不正確な結果になっていました。
テーブル t が外部キー制約を持ち (a,b) が r (x,y) を参照しているとすると、WHERE 条件で t.a = r.x AND t.b = r.y は、t の行に対し 1より多くの r 行が選択されることはありません。これまでプランナは AND 条件は独立していると考えて、結果の選択率を大幅に間違えていました。今は WHERE 条件と適用できる外部キー制約を比較し、より良い推定値を算出します。
VACUUM
- 凍結されたタプルだけを含むページを、再 VACUUM しなくなりました。 (Masahiko Sawada, Robert Haas, Andres Freund) (9.6)
- VACUUM 中の無駄なヒープ切り詰めが抑止されました。 (Jeff Janes, Tom Lane) (9.6)
これまでは、XID 周回を避けるための VACUUM は何もすることがないページでも、全て参照していました。今は、既に凍結されているタプルしか含まないページは、ビジビリティマップで判別され、トランザクション周回対策の vacuum を実行する場合でもスキップされます。これは、ほとんど変更されることのないデータを含む巨大なテーブルをメンテナンスするコストを大幅に削減します。
必要ならば VACUUM の DISABLE_PAGE_SKIPPING オプションで、すべて凍結されているページも処理するように強制することができます。通常ならば、これを必要とすることはありませんが、ビジビリティマップの破損を回復させる助けになるかも知れません。
この変更により、いくつかのケースで切り詰めができないときに、排他的テーブルロックを取らなくなります。主な利点は、スタンバイサーバでの不要なクエリキャンセルを避けることからきています。
パフォーマンス一般
- 古いMVCCスナップショットを指定のタイムアウト後に無効にできるようになりました。 (Kevin Grittner) (9.6)
通常、削除されたタプルは、それを参照できる最後のトランザクションが居なくならないない限り、VACUUM処理で削除されません。そのため、長時間のトランザクションが領域再利用を妨げてテーブル膨張をひき起こす可能性がありました。
本変更では、MVCCスナップショットの有効性を保証する時間を指定する新たな設定パラメータ old_snapshot_threshold による時間に基づく限度を導入します。デッドタプル(削除済みタプル、不要領域)は、指定時間を超えれば VACUUM処理が可能になります。本機能を使用する場合、古いスナップショットを使うトランザクションはデータを参照する際に以下のエラーを受ける可能性があります。
ERROR: snapshot too old
GROUP BY 句が遅延無しのプライマリキーの全ての列を含むなら、その他の列はいずれも冗長であり、グルーピングから除外することができます。これは多くのよくある場合に計算を節約します。
(9.6 での結果: 主キーの id 以外が無視されている) db1=# explain SELECT id FROM t24 GROUP BY k1, k2, k3, id, k4, k5; QUERY PLAN ------------------------------------------------------------ HashAggregate (cost=4.50..6.50 rows=200 width=24) Group Key: id -> Seq Scan on t24 (cost=0.00..4.00 rows=200 width=24) (3 rows)
以下に例を示します。SELECT 文の条件に WHERE a > 0 が含まれていて、選択リストが b だけなので index-only スキャンが選択されています。
db1=# CREATE INDEX tidx_partial ON t25 (b) WHERE a > 0; db1=# explain SELECT b FROM t25 WHERE a > 0 AND b > 200; QUERY PLAN ------------------------------------------------------------------------------ Index Only Scan using tidx_partial on t25 (cost=0.29..4.47 rows=10 width=4) Index Cond: (b > 200) (2 rows)
以前はこのような場合にインデックス列に a が含まれないため、index-only スキャンは利用できないと判断されていました。
これまではチェックポイントで共有バッファにあらわれた順にダーティページを書き出していました。通常はランダム同然の順番となります。これは特に回転体メディア(主としてハードディスク装置)では性能に劣ります。本変更でファイル・ブロック番号の順に書き出すようになり、また、各テーブルスペースにバランスよくアクセスするようになりました。
PostgreSQLはデータを、やがて物理ストレージにフラッシュされることから、カーネルディスクバッファに書き出します。多くの OS は必ずしもこのバッファ管理が賢くなく、大量のダーティデータをこれらを一度に書き出すと判断するまでの間に溜めこんで、新たな I/O 要求が大きく遅れてしまいます。この変更は設定された時間の後に明示的にデータのフラッシュを要求することで、本問題を緩和します。
以下の新たな設定パラメータでこの動作を制御します。
backend_flush_after = 0 # 0 disables, default is 0 bgwriter_flush_after = 0 # 0 disables, # default is 512kB on linux, 0 otherwise checkpoint_flush_after = 0 # 0 disables, # default is 256kB on linux, 0 otherwise wal_writer_flush_after = 1MB # 0 disables
例えば「SELECT avg(x), variance(x) FROM tab」は二つの集約に対して 1行につき1回の計算で済みます。
二相コミットの情報は、PREPARE TRANSACTION のときに WAL にのみ書かれ、直ぐ後に生じるなら COMMIT PREPARED のとき WAL からのみ読み返されます。分離状態ファイルは保留しているトランザクションが次のチェックポイントまでコミットもアボートもされない場合にのみ作られるようになります。
Resource Owners は問い合わせに係わるリソースを管理するための内部モジュールです。
ライブラリ関数を手書きコードに置き換えて高速化しています。
これは競合を減らすことでスケーラビリティを改善します。
上記の ParamListInfo は内部的なデータ構造です。
Windows 2012 からデフォルト値が増やされたため、従来の値を増やす為のコードが逆に値を減らす結果になっていました。
他のプラットフォームと比べて Windows ではプロセスタイトルを更新するオーバーヘッドが非常に大きく、また、大部分の Windowsユーザはプロセスタイトルを参照するツールを持っておらず実用性も低いため、このように変更されました。
モニタリング
- VACUUM処理の進行を報告するシステムビューpg_stat_progress_vacuum が追加されました。 (Amit Langote, Robert Haas, Vinayak Pokale, Rahila Syed) (9.6)
- 関数 pg_control_system()、pg_control_checkpoint()、pg_control_recovery()、pg_control_init() が追加されました。 (Joe Conway, Michael Paquier) (9.6)
- pg_configシステムビューが追加されました。 (Joe Conway) (9.6)
- pg_replication_slotsシステムビューに confirmed_flush_lsn 列が追加されました。 (Marko Tiikkaja) (9.6)
- ホットスタンバイサーバの WALレシーバプロセスの状態に関する情報を持つpg_stat_wal_receiverシステムビューが追加されました。 (Michael Paquier) (9.6)
- どのセッションがどのセッションをブロックしているかを識別するpg_blocking_pids() 関数が追加されました。 (Tom Lane) (9.6)
これにより(pg_control コマンドで参照できる)pg_controlファイルのフィールドをSQL から参照することができます。
pg_configコマンドと同様の PostgreSQLコンパイル時の設定情報を取得することができます。
引数にセッション (のバックエンドプロセスの) PID を与えると、そのセッションを待たせているセッションの PID が配列で返ります。これまでは pg_locksビューの出力を加工して同様の情報を得る必要がありましたが、無駄に手間がかかり、また、パラレル問い合わせに対応するのは困難でした。
(使用例) db1=# SELECT pid, pg_blocking_pids(pid), state, wait_event_type, wait_event FROM pg_stat_activity ; pid | pg_blocking_pids | state | wait_event_type | wait_event -------+------------------+---------------------+-----------------+------------ 10926 | {} | idle in transaction | | 10934 | {10926} | active | Lock | relation 10937 | {} | active | | 10952 | {10926,10934} | active | Lock | relation (4 rows)
メモリ不足エラーになるとエラーメッセージとしてメモリコンテキスト統計ダンプも出力されます。これが多数のメモリコンテキスト(固定で 100個以上)がある場合には、要約した短い出力とするようになりました。また、どちらの場合でも合計サイズの報告が加わります。
認証
- PostgreSQLクライアント認証にBSD認証サービスを利用するbsd認証方式が追加されました。 (Marisa Emerson) (9.6)
- pam認証を使う際に PAM_RHOST項目を通してクライアントIPアドレスやホスト名をPAMモジュールに提供するようになりました。 (Grzegorz Sampolski) (9.6)
- マスタプロセスのログにパスワード認証失敗の詳細が出力されるようになりました。 (Tom Lane) (9.6)
- RADIUSパスワードが128文字までサポートされました。これまでは16文字まででした。 (Marko Tiikkaja) (9.6)
- 新たなSSPI認証のパラメータ compat_realm、upn_username が追加されました。 (Christian Ullrich) (9.6)
bsd認証はいまのところ OpenBSDでのみ利用可能です。
このために設定オプション pam_use_hostname が追加されました。
「password authentication failure」になるすべての場合のログ出力にDETAIL欄が加わり、パスワード不一致であるほか、指定ロールが存在しない場合や、ロールにパスワードが設定されていない場合を区別できるようになります。
これらは SSPI認証で使われる NetBIOS か Kerberos のレルム名とユーザ名を制御します。
サーバ設定
- idle in transaction 状態が長く続くセッションを自動的に停止できるようになりました。 (Vik Fearing) (9.6)
- checkpoint_timeout の許される最大値が 24 hours に増やされました。 (Simon Riggs) (9.6)
- effective_io_concurrency がテーブルスペース毎に設定できるようになりました。 (Julien Rouhaud) (9.6)
この動作は 新たな設定パラメータ idle_in_transaction_session_timeout で制御されます。忘れられたトランザクションが長時間にわたりロックを保持していたり、VACUUMを妨げていたりするのを防ぐのに役立ちます。
以前の最大値は 1 hour でした。
それぞれ異なるI/O特性を持つテーブルスペースがあるときに役立ちます。
(設定例) db1=# ALTER TABLESPACE my_tblspc1 SET ( EFFECTIVE_IO_CONCURRENCY = 5 );
ミリ秒を伴い「1474886432.585」のような出力となります。
syslog にログ出力するときにメッセージに連番を付けるか、メッセージを分割するかを指定できます。デフォルト設定はいずれも on で従来通りの動作となります。
これらの設定を区別することに価値が無いと判断されました。旧来の名称も引き続き受け付けられ、内部的に replica に置き換えられます。
これにより、systemd 下での PostgreSQL の管理をとても簡単にできるnotifyタイプの systemdサービスユニットを使用できるようになります。
これまでは鍵ファイルは PostgreSQLサーバ実行ユーザが所有者でなければなりませんでした。Debian など証明書を集中管理する一部のシステムでは、これは不便でした。グループに信頼できないユーザが含まれないようにするのはOS管理者の責任となります。
信頼性
- マスタプロセスが終了したならバックエンドプロセスも強制終了するようになりました。 (Rajeev Rastogi, Robert Haas) (9.6)
- 制約違反エラーを報告する前に直列化の衝突を検査するようになりました。 (Thomas Munro) (9.6)
- たとえ XID 割り当ての無いトランザクションから出されたときでも、無効化メッセージ(新たな XLOGメッセージタイプ XLOG_INVALIDATIONS)が確実にWAL記録されるようになりました。 (Andres Freund) (9.6)
- 複数プロセスが GINインデックスのペンディングリストを同時に掃除しようとするのを防ぐようになりました。 (Teodor Sigaev, Jeff Janes) (9.6)
通常の状況ではマスタプロセスは子プロセスよりも長く生き続けます。何らかの理由でマスタプロセスが死ぬと、バックエンドセッションがエラーを出して終了するようになりました。これまでは、残ったバックエンドプロセスはクライアントから切断されるまで実行を続けていましたが、これは危険で非効率的でした。この変更は、旧バックエンドプロセスが残っているのに新たな PostgreSQL を起動してしまうことも防ぎます。バックエンドプロセスはクライアントI/Oを待つ間にマスタプロセスダウンを検知した場合には、即座には終了しませんが、現在の問い合わせが終了した時点よりも遅くなることはありません。
トランザクション隔離レベルにシリアライザブルを使っている場合、現在トランザクションが原因のあらゆるエラーは直列化失敗として表明すべきことが望まれます。これによってリトライで成功を見込めるアプリケーションに指示を出しています。残念ながら、これまでは同時挿入によりキー重複エラーが生じた場合、直列化失敗エラーは確実には発生しませんでした。
本変更でこのような場合には直列化失敗エラーとして報告されるようになります。
この変更は、スタンバイサーバのトランザクションが、インデックス同時作成や可視性マップ等の更新に気づくのに失敗するという場合について修正します。
これまでは故意に許されていましたが、このことは結果として VACUUM が削除すべきインデックスエントリを見落とす競合状態をひき起こします。
レプリケーション/リカバリ
- 同期レプリケーションで同時に動作する複数の同期スタンバイサーバをサポートするようになりました。 (Masahiko Sawada, Beena Emerson, Michael Paquier, Fujii Masao, Kyotaro Horiguchi) (9.6)
コミット応答の前に同期完了を確認しなければいけないスタンバイサーバの数を、synchronous_standby_names パラメータの中で指定できるようになります。
以下は、s1、s2、s3 の 3つスタンバイのうち 2つを同期スタンバイサーバとするという意味になります。
synchronous_standby_names = '2 (s1,s2,s3)'
このモードでは、プライマリはトランザクションがスタンバイサーバ上で、ディスクに書かれるだけでなく、適用されるのを待ちます。このことは、マスタにてコミット済みとこれまで応答を受けた全ての内容をスタンバイ上で参照できると期待できることを意味します。
これによりレプリケーションスロット作成によってベースバックアップに必要な全ての WAL が入手可能であることを保証できるようになります。
これは pg_basebackup にWALストリーミングのレプリケーションスロットを使わせます。ベースバックアップ完了後、通常のストリーミングレプリケーション用に同スロットを選択することで、スムーズに新たなスタンバイサーバを開始できます。
これにより同時に2系統のベースバックアップが実行可能になります。両関数に排他モードであるかを指定するオプションパラメータが追加されました。
問い合わせ
- 行の集合を返す関数が NULL の行を返せるようになりました。 (Andrew Gierth, Tom Lane) (9.6)
SELECT ... FROM function(...) という文脈では、複合値の集合を返す関数は、これまで単なる NULL値を集合の一部として返すことができませんでした。これからは可能となり、行の各要素が NULL の行と解釈されます。
以下に例を示します。
db1=# CREATE TABLE t71 (id int, v text, ts timestamp(0)); db1=# CREATE OR REPLACE FUNCTION f_srf() RETURNS SETOF t71 LANGUAGE sql AS $$ VALUES ( NULL::t71 ), ((1, 'a', '2015-01-01')::t71); $$; (9.6 の実行結果) db1=# pset null *null* db1=# SELECT * FROM f_srf(); id | v | ts --------+--------+--------------------- *null* | *null* | *null* 1 | a | 2015-01-01 00:00:00 (2 rows) (9.5.x の実行結果) db1=# SELECT * FROM f_srf(); ERROR: function returning set of rows cannot return null value
これまでは以下のように同じ対象列が複数回現れる場合にエラーが出ていました。
(9.5.x の結果) db1=# INSERT INTO t72 (id, arr[1], arr[2], arr[3]) VALUES (1, 101, 102, 103), (2, 201, 202, 203); ERROR: multiple assignments to same column "arr"
この変更は出力リストにある揮発性の関数、高負荷な関数が、ORDER BY で指示される順序で実行されることを、また、LIMIT句があるときに必要な回数以上に評価されないことを保証します。
インデックススキャンやマージ結合前のソートでは従来からこのような動作をしていましたが、トップレベルソートでは実施されませんでした。
(実行例/ここでの t73 テーブルの行はデタラメな順で物理格納されている) db1=# SELECT id FROM t73; id ---- 5 7 49 76 25 : (後略) (9.5 の結果) db1=# CREATE SEQUENCE sq73; db1=# SELECT nextval('sq73'), id FROM t73 ORDER BY id ; nextval | id ---------+---- 31 | 1 63 | 2 44 | 3 77 | 4 1 | 5 (5 rows) db1=# SELECT currval('sq73'); currval --------- 100 (1 row) (9.6 の結果) db1=# CREATE SEQUENCE sq73; db1=# SELECT nextval('sq73'), id FROM t73 ORDER BY id ; nextval | id ---------+---- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 (5 rows) db1=# SELECT currval('sq73'); currval --------- 5 (1 row)
この変更により SELECT 等のコマンドタグが 40億件以上のタプル数を正しく報告できるようになります。これは PL/pgSQL の GET DIAGNOSTICS ... ROW_COUNTコマンドにも適用されます。
これまでキリル文字と中央ヨーロッパのシングルバイト文字エンコーディングに対する多くの変換では、MULE_INTERNAL を通して変換していました。これは非効率であり、また、変換不能である場合のエラーメッセージがMULE_INTERNAL との間で変換できないという混乱を招く内容になってしまっていました。
これまでは外部テーブル結合のプッシュダウン基盤は、各外部データラッパ次第のセキュリティ上の問題を残していました。このことは、外部データラッパ実装で不注意によりセキュリティホールを作ってしまい易くしていました。
そのため、本体コード側でどのロールID で各テーブルにアクセスするかを判定して、各結合するテーブルにアクセスするロールが同じでない限り結合のプッシュダウンを試みないようにしました。
ユーティリティコマンド
- COPY が INSERT、UPDATE、DELETE に RETURNING を付けた場合の出力をコピーできるようになりました。 (Marko Tiikkaja) (9.6)
- ALTER ... DEPENDS ON EXTENSION ... 構文が追加されました。 (Abhijit Menon-Sen) (9.6)
これまでは CTE を経由してこれらを出力する SQL を記述する必要がありました。
ALTER FUNCTION、ALTER INDEX、MATERIALIZED VIEW、ALTER TRIGGER の各コマンドに新たな DEPENDS ON EXTENSION オプションが加わりました。
これらはオブジェクトに拡張モジュールに依存しているという印をつけます。そうすると、その拡張モジュールを削除すると(CASCADE指定無しでも)自動的にオブジェクトも削除されます。しかしながら、そのオブジェクトは拡張モジュールの一部というわけではないので、pg_dump では別個にダンプされます。
(動作例) db1=# CREATE EXTENSION hstore; db1=# CREATE FUNCTION f(text) RETURNS text LANGUAGE sql AS $$ SELECT ($1::hstore)::text $$; db1=# ALTER FUNCTION f(text) DEPENDS ON EXTENSION hstore; db1=# SELECT f('a=>b'); f ---------- "a"=>"b" (1 row) db1=# DROP EXTENSION hstore; db1=# SELECT f('a=>b'); ERROR: function f(unknown) does not exist
このケースは、これまでほとんどの種類のオブジェクトでエラーになっていました。
CREATE OPERATOR では以前から指定可能でした。
これからは AccessExclusiveLock ではなく ShareUpdateExclusiveLock で済みます。
作成時点ではテーブルには行がありませんので、これは安全です。FOREIGN KEY 制約を NOT VALID 指定で作った場合には、従来からこのような振る舞いとなっていました。
これまではこれらリンクはそのまま残されていて、あまりないことですが、削除された演算子の OID が他の演算子で再利用されることで問題をひき起こすおそれがありました。
ある種の、典型的にはインデックス条件の SubPlanノードを伴う場合に、EXPLAIN は同じサブプランを 2回出力することがありました。
このようなインデックスはサポートされていると考えられておらず、タプルのシステムカラム列はインデックスを更新することなく変更されることがあるため、おそらく極めて不適切な動作をしていました。それでいて、これまでインデックス作成を防ぐエラーチェックがありませんでした。
アクセス権限の制御
- 機微な関数へのアクセス管理に権限システムを使うようになりました。 (Stephen Frost) (9.6)
これまでは、多くのセキュリティ的に機微な関数には、非スーパーユーザから呼び出されたらエラーを投げるという固定的なチェックが組み込まれていました。このことは関連する通常のタスクにもスーパーユーザロールを使わざるをえなくしていました。
今後は、これらの固定的なチェックは無くして、むしろ initdb でこれら関数上のデフォルトの public EXECUTE 権限を無効にするようにします。これにより、これら関数の使用を(スーパーユーザでない)信頼されたロールに許可する使い方ができるようになります。
以下の関数でそのように変更されました。
pg_start_backup(text, boolean, boolean) pg_stop_backup() pg_stop_backup(boolean) pg_create_restore_point(text) pg_switch_xlog() pg_xlog_replay_pause() pg_xlog_replay_resume() pg_rotate_logfile() pg_reload_conf() pg_stat_reset() pg_stat_reset_shared(text) pg_stat_reset_single_table_counters(oid) pg_stat_reset_single_function_counters(oid)
pg_read_file() など、依然として固定的にスーパーユーザでないと実行できないように実装されている関数も残っています。
いまのところ、サーバシグナル送信関数を実行できる pg_signal_backend ロールのみ用意されています。
データ型
- フレーズ検索ができるように全文検索が改良されました。 (Teodor Sigaev, Oleg Bartunov, Dmitry Ivanov) (9.6)
フレーズとは指定の順序で隣接あるいは指定の距離を空けて現れる語彙素の並びです。
フレーズ検索問い合わせは tsquery 入力の中でで <-> 演算子、<N> 演算子にて指定できます。前者は、前後の語彙素が隣接してその順に現れなければいけないことを意味します。後者は、前後の語彙素がちょうど N 語彙素だけ離れていなければいけないことを意味します。
以下に使用例を示します。
db1=# CREATE TABLE t_ps (id serial, txt text, tsv tsvector); db1=# INSERT INTO t_ps (txt) VALUES ( 'PostgreSQL is the most advanced open source database in the world'); db1=# UPDATE t_ps SET tsv = to_tsvector('english', txt); db1=# SELECT phraseto_tsquery('english', 'open source database'); phraseto_tsquery ---------------------------------- 'open' <-> 'sourc' <-> 'databas' (1 row) db1=# SELECT phraseto_tsquery('english', 'open source database') @@ tsv FROM t_ps; ?column? ---------- t (1 row) db1=# SELECT phraseto_tsquery('english', 'database in the world'); phraseto_tsquery ----------------------- 'databas' <3> 'world' (1 row) db1=# SELECT phraseto_tsquery('english', 'database in the world') @@ tsv FROM t_ps; ?column? ---------- t (1 row)
以下のように使用できます。
db1=# SELECT '{aa,bb,cc,dd,ee,ff}'::text[]; text --------------------- {aa,bb,cc,dd,ee,ff} (1 row) db1=# SELECT ('{aa,bb,cc,dd,ee,ff}'::text[])[:3]; text ------------ {aa,bb,cc} (1 row) db1=# SELECT ('{aa,bb,cc,dd,ee,ff}'::text[])[:]; text --------------------- {aa,bb,cc,dd,ee,ff} (1 row)
この変更は timestamp with time zone 型の最大値、最小値に極めて近い値に対して、想定外の out-of-range エラーが生じるのを防ぎます。これまでは、タイムゾーン設定によって同じ値が受け入れられたり、受け入れられなかったりしました。このことはダンプ後のリロードで、既に受け入れられた値について失敗するおそれがあることを意味します。これからは、値の上限下限は timezone設定と無関係にローカル時刻でなくUTC時刻に従って制限されます。
また、date + integer などの演算で生じた新たな date や timestamp 値のオーバーフロー判定をより注意深く行うようになりました。
これらの結果として、仕様上範囲外とされている値において 9.5.x よりも扱えない値の範囲が増えています。バージョンアップ時の注意事項となります。
今後これらの値は常に単純な float8 (double precision) 型の列と同様に出力されるようになります。また、入力においても同様に扱われます。これまでは振る舞いがプラットフォーム依存となっていました。
後方検索制約は、既存の先行検索制約(先読み制約、lookahead constraint) と同様に、テキストを消費しませんが、文字列の現在位置を末尾としてマッチするかチェックします。同様の仕様は既存の他の多くの正規表現エンジンに存在します。
以下のように使用できます。
(例1: abc に続く 3文字) db1=# SELECT regexp_matches('abcdefgh', '(?<=abc)...'); regexp_matches ---------------- {def} (1 row) (例2: abc に続かない 3文字を複数切り出し) db1=# SELECT regexp_matches('abcdefgh', '(?<!abc)...', 'g'); regexp_matches ---------------- {abc} {efg} (2 rows)
nn が 377 (10進数で 255、1バイト) を超えることがあり、これを 2桁の8進エスケープと見なすようになりました。 (Tom Lane) (9.6)
以下例の 467 は 2桁8進数エスケープで解釈すれば '&' と文字 '7' で、3桁8進数で解釈すると1バイトを超える不正な値になります。
(9.5.x での結果) db1=# SELECT 'a&7bbbbb' ~ '^a467'; ?column? ---------- f (1 row) (9.6 での結果 - 正規表現パターンが '^a&7' と解釈されています) db1=# SELECT 'a&7bbbbb' ~ '^a467'; ?column? ---------- t (1 row)
関数
- jsonb配列に新たな要素を挿入したり、jsonbオブジェクトに新たなキーを挿入する jsonb_insert()関数が追加されました。 (Dmitry Dolgov) (9.6)
以下のようにパスを指定して jsonbデータ構造の内部に要素を挿入できます。
db1=# SELECT jsonb_insert('{"x":[10,20,30],"y":[4,5]}', ARRAY['x','2']::text[], '100'); jsonb_insert --------------------------------------- {"x": [10, 20, 100, 30], "y": [4, 5]} (1 row)
(例) db1=# SELECT scale(12345.678::numeric); scale ------- 3 (1 row)
末尾に d が付いた度単位版の三角関数 acosd()、asind()、atan2d()、cosd()、cotd()、sind()、tand() が追加されました。
(例) db1=# SELECT sind(30); sind ------ 0.5 (1 row)
POSIX標準では、これら関数は NaN 入力には NaN を返すべきであり、infinity を含む範囲外入力にはエラーを出すべきとされています。これまでは、各プラットフォームでばらばらの振る舞いをしていました。
従来は「ERROR: timestamp out of range」となっていました。
以下が追加されています。
ts_delete() tsvector から要素を削除 ts_filter() tsvector から重み指定条件で要素を削除 unnest() tsvector を行集合に展開 tsvector_to_array() tsvector を配列に変換 array_to_tsvector() 配列を tsvector に変換 setweight() の別引数版 指定の要素だけ重み付け設定
CHECK制約に CHECK(num_nonnulls(a, b, c) = 1) と記述することで、3つの列のうち 1つだけが非NULL であるということを表明できます。これらの関数は、一つの配列に対して要素の NULL または非NULLを数える使い方も可能です。
"APP"スキーマの t_log テーブルの col1 カラムが「"APP".T_LOG.Col1」と表現されていたとして、これを以下例のように分解できます。クォートされていない大文字の小文字への正規化も行われます。
db1=# SELECT parse_ident('"APP".T_LOG.Col1'); parse_ident ------------------ {APP,t_log,col1} (1 row)
これにより、to_char の逆関数として動作するようになります。
(9.6 での動作例: V の後 9 が 2個並んでいるので 10^2 で割った値が返ります) db1=# SELECT to_number('12400', '999V99'); to_number ---------------------- 124.0000000000000000 (1 row) (9.6 および 9.5.x の動作例: 10^2 を乗じた値が返ります) db1=# SELECT to_char(124.000, '999V99'); to_char --------- 12400 (1 row)
引数が単純なリテラル定数でない箇所でも、ほとんどの場合に明示的なキャストを加える必要がなくなります。
これまでは以下のように明示的なキャストが必要なケースがありました。
(9.5.x の動作例 - public.t1 の """"""OID番号を調べる問い合わせ) db1"""""" =# SELECT to_regclass('public.t1')::oid; to_regclass ------------- 17757 (1 row) db1=# SELECT to_regclass('public.' || 't1')::oid; ERROR: function to_regclass(text) does not exist db1=# SELECT to_regclass(('public.' || 't1')::cstring)::oid; to_regclass ------------- 17757 (1 row)
本関数は、pg_size_pretty()関数が出力するような文字列をバイト単位の数値に変換します。
例えば以下のように使用します。
db1=# SELECT oid::regclass FROM pg_class WHERE pg_total_relation_size(oid) > pg_size_bytes('10 GB');
これまではマイナス値は必ずバイト単位で出力されていました。
(9.5.x の動作) db1=# SELECT pg_size_pretty(-100000000::int8); pg_size_pretty ------------------ -100000000 bytes (1 row) db1=# SELECT pg_size_pretty(-100000000::int8); pg_size_pretty ---------------- -95 MB (1 row)
これにより認識できないパラメータ名についてエラーを回避して、代わりにNULL が返るようにできます。
今後は、pg_get_viewdef() は無効なビューのOIDに対して NULL を返します。また、類似のいくつかの関数も無効な入力に NULL を返すようになります。
これまではエラーを示す文字列(例:「Not a view」)が返ったり、「ERROR: cache lookup failed ...」というエラーが生じたりして、不規則な応答となっていました。
ドキュメントには引数を持たないと記されており、C コードも引数無しの想定となっていますが、SQL関数定義上は 2引数を取るようになっていました。
サーバサイド言語
- PL/pgSQL で実行時でなく関数コンパイル時に CONTINUE文と EXIT文の不一致を検出するようになりました。 (Jim Nasby) (9.6)
- PL/Python のエラー報告関数とメッセージ報告関数が、主エラーメッセージの他に追加メッセージ欄を指定できるように拡張されました。 (Pavel Stehule) (9.6)
- PL/Python 関数が自分自身を SPI を通して再帰的に呼び出しできるようになりました。また、集合を返す PL/Python 関数が一つの問い合わせの中で複数呼び出されたときの振る舞いが修正されました。 (Alexey Grishchenko, Tom Lane) (9.6)
- PL/Python におけるセッション単位でのメモリリークが修正されました。 (Heikki Linnakangas, Haribabu Kommi, Tom Lane) (9.6)
- PL/Tcl を単純な文字列でなく Tcl のオブジェクトAPI を使うように現代化しました。 (Jim Nasby, Karl Lehenbauer) (9.6)
- PL/Tcl で、Tcl の errorCode グローバル変数にて、データベースエラーに追加情報が返るようになりました。 (Jim Nasby, Tom Lane) (9.6)
これにより一部ケースでかなり性能が改善されます。なお、PL/Tcl は Tcl 8.4 以降が必要となります。
この仕様は Tcl のエラーに関する補助データを返すときの慣習に従っています。
クライアントインターフェース
- エラーおよび警告メッセージにおける深刻度フィールドの非ローカライズ版が加わりました。 (Tom Lane) (9.6)
- libpq でメッセージの CONTEXT 出力の抑制を調整できるようになりました。常に抑制するか、非エラーのメッセージのみ抑制するかを指定できます。 (Pavel Stehule) (9.6)
- libpq で別の冗長レベルでのエラーメッセージ再生成に対応しました。 (Alex Shulgin) (9.6)
- libpq の PQhost()関数がデフォルトの Unixソケット接続について有用なデータを返すように改良されました。 (Tom Lane) (9.6)
- ecpg の字句解析器がプリプロセッサ命令の行においてコメント文字列内の改行を受け付けるように修正されました。 (Michael Meskes) (9.6)
「ERROR」「WARNING」「NOTICE」などの深刻度を示す語が NLS を有効にしている場合、ローカライズされている可能性がありました。本修正で、クライアントプログラムがこのような懸念なく深刻度を判定できるようになります。
PQresultErrorField() 関数で fieldcode に PG_DIAG_SEVERITY の他PG_DIAG_SEVERITY_NONLOCALIZED を指定できるようになります。
また、PostgreSQLプロトコルにおける ErrorResponse および NoticeResponseメッセージ内で現れるフィールドの種類をあらわすコードに 'S' の非ローカライズ版である 'V' が加わっています。
PQerrorMessage() デフォルトの現在のデフォルト動作は後者の動作で、エラー時のみ CONTEXT を出力します。この調整のために新たな関数 PQsetErrorContextVisibility() を使用できます。
これは新たな関数 PQresultVerboseErrorMessage() で実行されます。psql の 新機能 errverbose の実現に使われています。
これまでは明示的にホスト指定が無い場合には NULL が返っていました。これからはデフォルトのソケットディレクトリパスを返します。
クライアントアプリケーション
pg_dump
- pg_dump、pg_restore に --strict-names オプションが追加されました。 (Pavel Stehule) (9.6)
本オプションは -t、-n オプションに対して指定したオブジェクトが存在していないときにエラーを出して失敗させます。--strict-names 指定が無い場合(すなわち従来の動作)は、該当するオブジェクトが無い -t や -n の指定が含まれていても警告なしに実行されます。
(t1テーブルは存在し、t2テーブルは存在しない場合) $ pg_dump --strict-names -d db1 -t t1 -t t2 > t12.dump pg_dump: no matching tables were found for pattern "t2"
スーパーユーザはビルトインオブジェクトや拡張モジュールによるオブジェクトの権限割り当てを常に変更できる一方、これまでこれらの変更はダンプ・リロードで失われていました。これからは pg_dump がこれらの変更を認識し、ダンプするようになります。
なお、これはバージョン 9.6 以降のサーバに対してのみ機能します。
これまではこのようなオブジェクトは拡張モジュールに属すると判断されて無視されていました。
以下のように Name: が「テーブル名 オブジェクト名」になっています。
(ダンプ出力の一部) -- -- Name: t1 t1_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres -- ALTER TABLE ONLY t1 ADD CONSTRAINT t1_pkey PRIMARY KEY (id);
psql
- psql が複数の -c、-f オプションに対応しました。 (Pavel Stehule, Catalin Iacob) (9.6)
複数のコマンドやスクリプトファイルを指定すると、一つの接続の中でオプションが与えられた順(左から順)に実行されます。
(実行例) $ echo 'SELECT $$script$$' > script.sql $ psql -c 'BEGIN' -f script.sql -c 'COMMIT' db1 BEGIN ?column? ---------- script (1 row) COMMIT $
以下のように使用することができます。
db1=# SELECT cat1, cat2, to_char(sum(sales),'9,999,999') FROM tsales GROUP BY cat1, cat2; cat1 | cat2 | to_char ------+------------+------------ 支店 | 通常期間 | 2,168,062 本店 | セール期間 | 563,499 本店 | 通常期間 | 906,981 支店 | セール期間 | 1,344,994 (4 rows) db1=# crosstabview cat1 | 通常期間 | セール期間 ------+------------+------------ 支店 | 2,168,062 | 1,344,994 本店 | 906,981 | 563,499 (2 rows)
本コマンドで予期せぬエラーを受けた後から VERBOSITY変数を verbose 設定したのと同様のエラーメッセージを取得できます。以下のように動作します。
db1=# SELECT * FROM t1; ERROR: relation "t1" does not exist LINE 1: SELECT * FROM t1; ^ db1=# errverbose ERROR: 42P01: relation "t1" does not exist LINE 1: SELECT * FROM t1; ^ LOCATION: parserOpenTable, parse_relation.c:1159
関数における ef コマンド、sf コマンドとの相似になっています。
前回の問い合わせ結果を新たな問い合わせとして実行します。以下のように使用することができます。
db1=# SELECT format('DROP TABLE %I', table_name) FROM information_schema.tables WHERE table_schema = 'public'; format ----------------------------- DROP TABLE pgbench_history DROP TABLE pgbench_tellers DROP TABLE pgbench_branches DROP TABLE pgbench_accounts (4 rows) db1=# gexec DROP TABLE DROP TABLE DROP TABLE DROP TABLE
設定されていたなら pset title の文字列を含むようになります。タイムスタンプになるヘッダの前段部分が短くなりました。また、タイムスペースフォーマットが psql のロケール環境に従うようになりました。
(出力例) $ LANG=ja_JP.UTF-8 psql -q db1 db1=# pset title my_watch_title Title is "my_watch_title". db1=# SELECT random(); my_watch_title random ------------------- 0.643378943670541 (1 row) db1=# watch 5 my_watch_title 2016年09月13日 13時53分34秒 (every 5s) random ------------------- 0.167425051797181 (1 row)
これまでは複数行に分かれたコマンドでは、前の行を見なければいけないTab補完規則が無効になっていました。
(9.6 では以下のように複数行でも Tab補完が効きます) db1=# SELECT * FROM pg_user db1-# WHERE u usebypassrls usecreatedb userepl usesysid useconfig usename usesuper
CREATE SEQUENCE、 CREATE LABEL、 CREATE/DROP INDEX CONCURRENTLY、CREATE EXTENSION、 GRANT / REVOKE、 COPY、 REFRESH MATERIALIZED VIEW、ALTER .. SET/RESET、 CREATE/ALTER FOREIGN DATA WRAPPER、CREATE/ALTER SERVER、 CREATE/ALTER USER MAPPING の Tab補完が修正されています。
エラー時にのみ CONTEXT欄を表示するのが現在のデフォルトの振る舞いです。特別変数 SHOW_CONTEXT を設定することで、これを変更できるようになりました。
pgbench
- pgbenchスクリプト内のSQLコマンドは改行ではなく、セミコロン(;)で終える仕様になりました。 (Kyotaro Horiguchi, Tom Lane) (9.6)
- pgbench のバックスラッシュコマンドの式でいくつかのビルトイン関数、および、浮動小数点演算に対応しました。 (Fabien Coelho) (9.6)
- pgbenchスクリプトで setrandom が廃止されました。ビルトイン関数で置き換えられます。 (Fabien Coelho) (9.6)
本変更によりスクリプトに複数行からなる SQLコマンドを記述できます。既存の pgbenchスクリプトは行末にセミコロンが無ければ加える修正が必要です。なお、各行の SQLコマンドがセミコロンで終了していても旧来バージョンで動作します。
ビルトイン関数は pgbenchスクリプトのバックスラッシュコマンド専用のもので、同名のSQL関数とは別物です(例えば random() は 2引数を取り整数を返します)。様々な乱数生成に役立つ関数、任意メッセージ出力をする関数が含まれます。
新たなビルトイン関数に random()、random_exponential()、random_gaussian() が含まれ、setrandom と同様のことができます。複雑な式に埋め込むことができることから、より使いやすくなっています。
(9.5.x までの書き方例) setrandom rid 1 10000 setrandom slp 1 10 exponential 3.0 sleep :slp ms UPDATE t1 SET ts = now() WHERE id = :rid ; (9.6.x からの書き方例) set rid random(1, 10000) set slp random_exponential(1, 10, 3.0) sleep :slp ms UPDATE t1 SET ts = now() WHERE id = :rid ;
新たな -b オプションで以下のようにビルトインスクリプトをカスタムスクリプトのように複数指定することができます。-b では tpcb-like、select-only、simple-update の三種類が指定できます。
$ pgbench -n -c 10 -t 500 -b tpcb-like -b select-only -b simple-update -f custom_script1.sql -f custom_script2.sql db1
複数のスクリプトが指定されているとき、各pgbench トランザクションは実行するものをランダムに一つを選択します。これまでは常に均一な確率でしたが、これからは各々に異なる選択率を指定できます。
以下のように -f、-b オプションの後に @数値 で重みづけを指定します。
(二つのビルトインスクリプトは 1対9 の割合で実行されます) $ pgbench -n -c 10 -t 50 -b tpcb-like@1 -b select-only@9 db1 (二つのカスタムスクリプトは 15対85 の割合で実行されます) $ pgbench -n -c 10 -t 50 -f script1.sql@15 -f script2.sql@85 db1
以下のようにスクリプト毎の報告を得ることができます。
$ pgbench -c 5 -t 10 -n -f script1.sql -f script2.sql db1 transaction type: multiple scripts scaling factor: 1 query mode: simple number of clients: 5 number of threads: 1 number of transactions per client: 10 number of transactions actually processed: 50/50 latency average: 0.000 ms tps = 221.703928 (including connections establishing) tps = 227.219227 (excluding connections establishing) SQL script 1: script1.sql - weight = 1 (targets 50.0% of total) - 25 transactions (50.0% of total, tps = 110.851964) - latency average = 16.467 ms - latency stddev = 4.817 ms SQL script 2: script2.sql - weight = 1 (targets 50.0% of total) - 25 transactions (50.0% of total, tps = 110.851964) - latency average = 17.521 ms - latency stddev = 3.022 ms
クライアント接続数はできる限り各スレッドに等分されるという振る舞いになります。
これまでは、低いトランザクションレートが指定されていると、指定時点よりも大幅に長く待つことがありました。
サーバアプリケーション
- initdb の post-bootstrap 処理段階におけるエラー報告が改善されました。 (Tom Lane) (9.6)
- 一つのスタンドアローンバックエンドセッションを全ての post-bootstrap処理段階のために使うことで、initdb が高速化しました。 (Tom Lane) (9.6)
- ターゲットタイムラインが変わったときでも動作するようにpg_rewind が改良されました。 (Alexander Korotkov) (9.6)
これまでは、エラーが起きたところで、入力ファイル全体が失敗したクエリとして報告されました。これからは、当該のクエリだけが報告されます。この望ましい振る舞いを得るため、initdb の入力ファイルのクエリが空行で区切られました。
これまでは initdb の各サブルーチンがそれぞれスタンドアローンのバックエンドセッションを起動しており、この無駄を削減します。
これにより、例えば、昇格したスタンバイを旧マスタのタイムラインの状態に巻き戻すことができます。
ソースコード
- 旧式の heap_formtuple/heap_modifytuple/heap_deformtuple 関数(内部関数) が削除されました。 (Peter Geoghegan) (9.6)
- AllocSetContextCreate() をシンプルかつ安全に実行するマクロが追加されました。 (Tom Lane) (9.6)
- ヘッダファイル内では無条件で static inline 関数を使うようになりました。 (Andres Freund) (9.6)
- TAPテスト基盤が改良されました。 (Michael Paquier, Craig Ringer, Álvaro Herrera, Stephen Frost) (9.6)
- trace_lwlocks = on のとき、各ロックを名前で識別するようになりました。 (Robert Haas) (9.6)
- psql のTab補完コードの基盤が改良されました。 (Thomas Munro, Michael Paquier) (9.6)
- pg_shseclabel が接続認証のアクセスで利用可能になるように、システムカタログ pg_shseclabel を RelationCache に持つようになりました。 (Adam Brightwell) (9.6)
- インデックスアクセスメソッド(AM) API が C言語レベルの大部分を隠すように再構成されました。 (Alexander Korotkov, Andrew Gierth) (9.6)
- システムカタログ pg_init_privs が追加されました。initdb や 拡張モジュール導入で作られるオブジェクトの当初の権限を保持します。 (Stephen Frost) (9.6)
- 拡張モジュールがカスタムLWLock を割り当てる方法が変更されました。 (Amit Kapila, Robert Haas) (9.6)
- 複数セッションが同時待機できるように分離テスターが改良され、デッドロックシナリオのテストができるようになりました。 (Robert Haas) (9.6)
- 拡張可能なノードタイプが導入されました。 (KaiGai Kohei) (9.6)
- プランナが post-scan/join クエリ段階で、多数のアドホックなロジックに代えて、Path の生成・比較によって処理するようになりました。 (Tom Lane) (9.6)
- 部分的な集約に対応しました。 (David Rowley, Simon Riggs) (9.6)
- 汎用コマンド進捗報告の基盤が追加されました。 (Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas) (9.6)
- psql の flex 字句解析器が他のクライアントプログラムから使えるように切り出しされました。 (Tom Lane, Kyotaro Horiguchi) (9.6)
- 通常は一つの待機から次に変化しないイベントセットを効率的に待機できるwaitEventSet API が 導入されました。 (Andres Freund, Amit Kapila) (9.6)
- WALレコードを書き込む汎用インタフェースが追加されました。 (Alexander Korotkov, Petr Jelínek, Markus Nullmeier) (9.6)
- ロジカルデコーディングむけに汎用WALメッセージがサポートされました。 (Petr Jelínek, Andres Freund) (9.6)
- SP-GiST演算子クラスがインデックスを下るときに任意の横断値(traversalValue)を格納できるようになりました。 (Alexander Lebedev, Teodor Sigaev) (9.6)
- ereport() に LOG_SERVER_ONLY メッセージレベルが追加されました。 (David Steele) (9.6)
- 全ての生成されるヘッダファイルをビルドする Makefileターゲットsubmake-generated-headers が用意されました。 (Michael Paquier, Tom Lane) (9.6)
- OpenSSL 1.1.0 がサポートされました。 (Andreas Karlsson, Heikki Linnakangas) (9.6)
新たなマクロ ALLOCSET_DEFAULT_SIZES、ALLOCSET_SMALL_SIZES、ALLOCSET_START_SMALL_SIZES を使う方が推奨され、あるメモリコンテキストに対して個々にサイズ引数を記述することは、今後は非推奨となります。
しかしながら、既存コードは未だ全て置き換えられていません。
この書き方の変更により開発者がインライン関数をより容易に使うことができます。非常に古いコンパイラでは警告、および/または、無駄なコードスペースが生じるかもしれません。
TAPテストの枠組みでリカバリシナリオをテストできるようになったほか、様々な改修が適用されています。
なお、trace_lwlocks は、コンパイル時にLOCK_DEBUGマクロが定義された場合に使用できる、以前から存在する開発者むけ設定パラメータです。
Tab補完規則がかなり書きやすくなり、また、コンパクトになりました。
本体コードは pg_shseclabel を認証に使いませんが、authentication_hook を使う拡張モジュールで参照したいかもしれません。
インデックスAM API が、外部データラッパーやテーブルサンプルハンドラに採用している、必要な関数が列挙された構造体を使うデザインになりました。これにより、Cコードがシンプルになり、拡張モジュールとしてインデックスAMを定義することがより現実的となります。
結果として、システムカタログpg_am の多くのカラムが廃止されました。これまで pg_am に在ったインデックスAMの属性をSQL問い合わせで調べることができる新たなシステムカタログ情報関数がいくつか追加されました。
これにより pg_dump がシステムオブジェクトの権限を変えている場合について、変更差分をダンプすることができます。これまで、このような変更はダンプとリロードで失われていましたが、今後は維持されます。
RequestAddinLWLocks() 関数は削除され、RequestNamedLWLockTranche() 関数で置き換えられます。これにより、カスタムLWLock の識別が改善され、間違いが起こりにくくなります。
これにより、FDW(外部データラッパ)やカスタムスキャン作成者は、これまでよりも便利な形式でプランツリーにデータを格納できます。
現時点では本変更で得られるユーザから見える改善は僅かです。しかし、古いコード構造上の取り組みでは現実的でなかった、将来の多数の上位プランナ改良を有効にします。
本変更で集約関数を分割して計算できるようになります。例えば、複数のパラレルワーカープロセスが協調して一つの集約を計算できます。
VACUUMコマンドの進捗表示に本枠組みが使われています。
これにより、コマンド境界を識別できるだけの SQLコマンド解析を要するプログラムからコード重複を削減します。
新たなソースコードサブディレクトリ src/fe_utils が作られ、クライアントプログラムで共用されるコードが含まれます。これまでは、シンボリックリンクやビルド時のソースファイルコピーでコード共有を実現していました。
これにより、拡張モジュールがページ変更内容を標準形式にて WALレコードに書くことができます。拡張モジュールにアクセスすることなしにWAL再生しなければいけない問題には、汎用再生コードで対応します。
これにより、拡張モジュールで WAL書き込み対応した新たなインデックスアクセスメソッドを実装することができます。
この機能により、拡張モジュールが WAL に任意データを書き込み、ロジカルデコーディングプラグインから読ませることができます。これを実現する pg_logical_emit_message() 関数が追加されました。
なお、この汎用WALメッセージは物理データのリカバリには関係しません。
従来からある再構築された値(reconstructedValue)と似ていますが、traversalValue は任意の量のデータを置けてインデックス列とデータ型が同じである必要もありません。
本レベルはメッセージが決してクライアントに送られない点を除き、LOG のように動作します。監査等の用途で使うためのものです。
これは単独でビルドされるかもしれないサブディレクトリで便利です。
追加モジュール
- contrib/auto_explain に設定パラメータ auto_explain.sample_rate が追加されました。 (Craig Ringer, Julien Rouhaud) (9.6)
- ブルームフィルタに基づくインデックスアクセスメソッドを実装するcontrib/bloom 拡張モジュールが追加されました。 (Teodor Sigaev, Alexander Korotkov) (9.6)
- contrib/cube でcube型のための距離演算子が追加されました。 (Stas Kelvich) (9.6)
- contrib/hstore の hstore_to_jsonb_loose()関数と hstore_to_json_loose()関数が、何が数値かについて一致するようになりました。 (Tom Lane) (9.6)
問い合わせのうち設定した割合だけを捕捉するようにできます。これにより、平均的には有用な情報が採取できる一方、問い合わせ量が多いときのオーバーヘッドを軽減できます。
これは主として、標準で含まれないインデックスアクセスメソッドを追加することの概念実証のためのものです。しかしながら、多数の列を検索する問い合わせには、本インデックスの機能自体が役立つかもしれません。
cube型列へのGiSTインデックスでの k最近傍(kNN)検索もサポートされました。
これまでは、hstore_to_jsonb_loose() は数値に見える文字列を、たとえ JSON の数値の文法仕様に正確には一致していなくとも JSON の数値に変換していました。
hstore_to_jsonb_loose() の振る舞いが修正され、hstore_to_json_loose() と一致するようになりました。互換性のない変更点と言えます。
(9.5.x での動作) db1=# SELECT hstore_to_jsonb_loose('a=>-01'::hstore); hstore_to_jsonb_loose ----------------------- {"a": -1} (1 row) db1=# SELECT hstore_to_json_loose('a=>-01'::hstore); hstore_to_json_loose ---------------------- {"a": "-01"} (1 row) (9.6 での動作) db1=# SELECT hstore_to_jsonb_loose('a=>-01'::hstore); hstore_to_jsonb_loose ----------------------- {"a": "-01"} (1 row)
heap_page_items() 関数の出力に t_dataカラムが追加されています。また、個別のタプルフィールドを調べるための新たな関数 tuple_data_split()、heap_page_item_attrs() が追加されました。
(3カラムを持つ t1 テーブルのタプル生データをフィールド区切り付きで出力する例) db1=# SELECT * FROM heap_page_item_attrs(get_raw_page('t1',0), 't1'); lp | lp_off | lp_flags | lp_len | t_xmin | t_xmax | t_field3 | t_ctid | t_infomask2 | t_infomask | t_hoff | t_bits | t_oid | t_attrs ----+--------+----------+--------+--------+--------+----------+--------+-------------+------------+--------+--------+-------+------------------------------------------------------------------------- 1 | 8144 | 1 | 48 | 31720 | 0 | 0 | (0,1) | 3 | 2050 | 24 | | | {"\x01000000","\x0d48454c4c4f","\xc08a627ffcde0100"} 2 | 8088 | 1 | 56 | 31721 | 0 | 0 | (0,2) | 3 | 2050 | 24 | | | {"\x02000000","\x1d5468697320697320546573742e","\xc09cdc7ffcde0100"} (2 rows)
ある文字列と、複数語を含む文字列の中の最も類似した単語との類似度を返します。
この閾値はこれまでも調整可能でしたが、専用の関数 set_limit()、show_limit()を使って指定するものとなっていました。これらの関数は今後は非推奨となります。
既存のビジビリティマップを破棄する関数も含まれています。
現在の接続にある X509クライアント証明書の拡張情報(拡張名、値、クリティカルであるか)を出力します。
postgres_fdw
- 外部サーバのオプションにホワイトリストとして拡張モジュールを指定することで、拡張モジュールで提供される関数や演算子もリモート実行できるようになりました。 (Paul Ramsey) (9.6)
以下に pgcrypto の関数をリモートで実行させる例を示します。
(両サーバに pgcrypto を導入) remote=# CREATE EXTENSION pgcrypto; local=# CREATE EXTENSION pgcrypto; (デフォルトではローカルで関数を実行するプランになる) local=# explain SELECT id FROM remote.t1 WHERE digest(c1, 'sha1') = 'xbd564db5d5cc358eb0e3523d3e03041739f230d5'; QUERY PLAN -------------------------------------------------------------------------------------------- Foreign Scan on t1 (cost=100.00..212.38 rows=15 width=4) Filter: (digest(c1, 'sha1'::text) = 'xbd564db5d5cc358eb0e3523d3e03041739f230d5'::bytea) (2 rows) (サーバオプションに指定を追加) local=# ALTER SERVER server1 OPTIONS (ADD extensions 'pgcrypto'); (リモートで関数を実行するプランになる) local=# explain SELECT id FROM remote.t1 WHERE digest(c1, 'sha1') = 'xbd564db5d5cc358eb0e3523d3e03041739f230d5'; QUERY PLAN ----------------------------------------------------------- Foreign Scan on t1 (cost=100.00..154.18 rows=15 width=4) (1 row)
これまではリモートサーバ側のみでソートできる場合でも、ローカルでソートが行われていました。
これまでは同一リモートサーバ上のリモートテーブル同士の結合であっても、テーブル毎に SELECT を実行して、ローカルで結合処理を行っていました。9.6 では可能であればテーブル結合をリモートサーバ上で行います。
これまでは、リモート更新は SELECT ... FOR UPDATE コマンドの送信をして、選択された行を一つずつ更新したり削除する必要がありました。何らかローカル処理が必要な場合には依然として上記の手順が必要ですが、そうでなければリモートだけで実行します。
(これはリモート側で単に下記の通りの SQL が実行されます) DELETE FROM remote_table WHERE id IN (101, 102, 103); (これはローカルデータを参照するので SELECT ... FOR UPDATE と 1行ずつの DELETE が必要です) DELETE FROM remote_table WHERE id IN (SELECT id FROM local_table);
これまではリモート問い合わせで常に1回に100行ずつ取得していましたが、調整可能になります。
なお、当然のことながら、一つのローカルセッション内での再利用となります。
これまではローカルで問い合わせキャンセルの指令を受けても、既に送信したリモート問い合わせに対しては何もしませんでした。