PostgreSQL 7.2 に関する技術情報

このリリースは PostgreSQL 7.2 (2002/02/04リリース)に関する技術情報をお届けします。本ドキュメントは PostgreSQL のリリースノートを元に弊社で解説を加えたものです。

PostgreSQL 7.1 から 7.2 への変更点

注意: ここにあげた変更点は,すべてを網羅していない可能性があります.詳しくはソースに付属の HISTORY というファイルを見てください.

互換性のない変更点

  1. データベースのフォーマットが変わったので、7.1.x またはそれ以前で作成したデータベースは使えません。pg_dump か copy コマンドを使ってデータベースを再ロードする必要があります。
  2. フロントエンド/バックエンドの通信プロトコルについては、7.1と7.2 は同じなので通信は可能です.
  3. 7.2では,OID(Object Id)を持たないシステムテーブルがあります.また,OIDを持たないテーブルを作ることができるようになりました.したがって,OIDを使って行を特定しているようなアプリケーションが動かなくなる可能性があります.OIDを作らないメリットは,OIDの限界(2^32)を心配する必要がなくなることです.
    • pg_classに relhasoids という bool 型の列が追加されました.OIDを持たない場合はこれが”f”になります.
    • OIDを持つシステムテーブルは以下です.
      • pg_type
      • pg_class
      • pg_database
      • pg_operator
      • pg_opclass
      • pg_am
      • pg_language
      • pg_aggregate
      • pg_trigger
      • pg_proc
      • pg_rewrite

      OIDを持たないシステムテーブルは以下です.

      • pg_attribute
      • pg_group
      • pg_inherits
      • pg_index
      • pg_amop
      • pg_amproc
      • pg_largeobject
      • pg_listener
      • pg_shadow
      • pg_attrdef
      • pg_description
      • pg_relcheck
      • pg_statistic
    • CREATE TABLEでは,デフォルトではOIDが作成されます.OIDを生成しないテーブルを作るには,キーワード “WITHOUT OIDS” を使用します.
                例:
      
                CREATE TABLE t1(i INTEGER) WITHOUT OIDS;
      
  4. CHAR(n), VARCHAR(n)で,nはバイト数ではなく,文字数を表すようになりました(SQL99のスペック通り).
  5. CHAR(n), VARCHAR(n)で,n文字を超えるデータを入力しようとすると,暗黙的にn文字を超える部分がカットされるのではなく,エラーとなるようになりました(SQL99のスペック通り).
  6. 2バイト目以降に不正なバイトを含むマルチバイト文字を入力しようとすると,エラーになるようになりました.
  7. TEXT型のOCTET_LENGTHは,圧縮前のバイト数を返すようになりました (VARCHAR/CHAR型は以前から圧縮前のバイト数を返していたので,これで一貫性が取れるようになりました).
  8. 以下の文字列が予約語になり,列名などに使えなくなりました.
    • time, timestamp
  9. 上記により,time, timestampを関数名として使えなくなりました.7.1までは許されていた,
            select timestamp(date '1998-02-24', time '23:07');
    

    はエラーになります.代りに以下の記法を使ってください.

            select "timestamp"(date '1998-02-24', time '23:07');
            select timestamptz(date '1998-02-24', time '23:07');
            select (date '1998-02-24' + time '23:07');
    
  10. 現在を表す「CURRENT」が廃止されました.代りに CURRENT_TIMESTAMP,CURRENT_DATE,CURRENT_TIMEを使ってください.
  11. INSERTルールはINSERTの前ではなく,後で実行されるようになりました.
  12. foo = NULLは foo IS NULL とは見なされなくなりました.したがって,foo = NULL は常に NULL となります.この挙動を変更したい場合は,「GUCパラメータの追加/変更」の項目を参照してください.

    追加された機能

  13. デフォルトではVACUUMはテーブルをロックしなくなりました.VACUUM中でもテーブルを検索したり,更新できます.ただし,このVACUUMは空き領域を再利用するだけで,テーブルサイズを小さくはしません.テーブルを小さくするためには,従来と同じテーブルをロックするVACUUMを使います.単に “FULL” というキーワードを追加するだけです.
         例:
         VACUUM FULL;
    
  14. ANALYZEがVACUUMから独立しました.従来通り,VACUUM ANALYZE を使うこともできます.
         例:
         ANALYZE;
    
  15. VACUUM FREEZEが追加されました.詳しくは,管理者ガイドの “8.2.3. Preventing transaction ID wraparound failures” を御覧下さい.ここでは簡単に説明します.PostgreSQLでは,すべてのトランザクションにトランザクションID(XID)という連番の数字が割り当てられています.この数字は32ビットの整数で表され,最大値は2の32乗,すなわち約42億です.一方,PostgreSQLではMVCC を採用しており,ある行の「バージョン」をこのXIDで識別します.すなわち,現在のトランザクションT1のXIDがXである場合,T1から見える行は,XID が X以下であることが条件となります.Xより大きなXIDを持つ行は,T1よりも新しいトランザクションが生成したものと見なし,T1からは見えません.

    もしもXIDが2の32乗を超えるとどうなるでしょう.XIDは0になり,再びそこからカウントを開始します.その結果,新しいトランザクションから見ると,ほとんどの行は自分よりも大きなXID持っているので不可視になってしまいます.つまり突然データが消えたように見えるのです.

    この問題を解決するために導入されたのが”FrozenXID”です.FrozenXIDは値が2の特別なXIDで,このXIDは他のどんなXIDよりも「古い」と見なされます(この他,値が1の特別なXIDがあり,これも同様です).普通にVACUUM をかけると,現在よりも10億よりも過去のXIDを持つ行が”FREEZE”され,XIDとして2がアサインされます.FREEZEされた行は,以後トランザクションIDが0を回ってしまっても安全です.ただし,現在のXIDから遡って10億過去までのXIDを持つ行はFREEZEされていませんから,いずれはVACUUMをかけてFREEZEする必要があります.この目安とするために,pg_databaseに datfrozenxidという列が追加されました.FREEZEされた最大のXIDがここに格納されます.datfrozenxidと現在のXIDの差が15億よりも広がったら VACUUMをかけることが推奨されており,そのためにageという関数が提供されています.

    例:
    SELECT datname, age(datfrozenxid) FROM pg_database;
      datname  |    age
    -----------+------------
     test      |         41
     test2     | 1073741946
     template1 |        490
     template0 |        490
    (4 rows)
    

    御覧のように,”test2″というDBは現在ageが約10億7千万ですので,後4億 2千万トランザクションほど余裕があることになります.うっかりVACUUMを忘れるのを防止するために,VACUUMは,ageが15億を超えると警告を出します.

    lay=# vacuum;
    NOTICE:  Some databases have not been vacuumed in 1613770184 transactions.
            Better vacuum them within 533713463 transactions,
            or you may have a wraparound failure.
    VACUUM
    

    さらに完璧にFREEZEするために,VACUUM FREEZEというオプションがあります.VACUUM FREEZEを実行すると,トランザクション処理中でないすべての行のXIDが2にセットされます.

  16. スーパーユーザ以外でも自分が所有するDBのテーブルにVACUUMがかけられるようになりました.ただし,グローバルテーブルである pg_group,pg_database, pg_shadow は別です.
  17. pg_logがpg_clogというディレクトリの下の複数のセグメントファイルに分割されました.また,可能ならば不要なセグメントがVACUUM時に削除されるようになりました.
  18. ISO 8859シリーズの文字コードの対応が強化されました.以下の文字コードに対応しています.なお「別名」ですが,7.2からはエンコーディング名の「別名」に対応しており,別名のエンコーディング名でも受け付けます.ただし,getdatabaseencoding()などの関数が返すエンコーディング名は常に「PostgreSQLでのエンコーディング名称」になります.
    文字コード PostgreSQLでのエンコーディング名称 別名 7.2で追加
    ISO-8859-1 LATIN1 ISO_8859_1
    ISO-8859-2 LATIN2 ISO_8859_2
    ISO-8859-3 LATIN3 ISO_8859_3
    ISO-8859-4 LATIN4 ISO_8859_4
    ISO-8859-5 ISO_8859_5
    ISO-8859-6 ISO_8859_6
    ISO-8859-7 ISO_8859_7
    ISO-8859-8 ISO_8859_8
    ISO-8859-9 LATIN5 ISO_8859_9
    ISO-8859-10 LATIN6 ISO_8859_10
    ISO-8859-13 LATIN7 ISO_8859_13
    ISO-8859-14 LATIN8 ISO_8859_14
    ISO-8859-15 LATIN9 ISO_8859_15
    ISO-8859-16 LATIN10 ISO_8859_16

    ☆ 7.1までは”LATIN5″はISO-8859-5に対応していましたが,実はこれは正しい対応ではないことが分かったため,7.2からはLATIN5=ISO-8859-9に変更されています.

  19. 7.1からUnicode対応が強化されUTF-8 <–> その他のコード変換を自動的に行う機能が追加されましたが,7.2では自動変換が可能なエンコーディングが増えて以下のようになっています.
    • EUC_JP
    • EUC_CN
    • EUC_KR
    • EUC_TW
    • ISO 8859-1から16まで
    • SJIS
    • BIG5
    • ALT
    • KOI8_R
    • WIN1251

    なお,7.2では –enable-multibyte するだけでこの機能が有効になるので,configure時に –enable-unicode-conversion オプションを指定する必要がなくなりました.

  20. 任意の文字コードの間でコード変換を行うconvert(), convert2()が追加されました.
  21. 以下の関数がマルチバイト対応になりました.
    • lpad
    • rpad
    • btrim
    • ltrim
    • rtrim
    • trim
    • translate
  22. 一時シーケンスが作れるようになりました.CREATE TEMPORARY(または TEMP) SEQUENCE… とします.
  23. シーケンスの内部管理データ型がint8になりました.これに伴い,int8を扱えるSERIAL8型が追加されました.
  24. DROP CONSTRAINTでCHECK制約を削除できるようになりました.
  25. CONSTRAINT TRIGGERをADD/DROPできるようになりました.
  26. すべてのオプションを表示するSHOW ALLが追加されました.また,すべてのオプションを初期状態に戻すRESET ALLも追加されました.
  27. GUCパラメータの追加/変更
    • default_transaction_isolation.デフォルトのトランザクション隔 離レベルを指定します.デフォルトは ‘read committed’ です.
    • max_files_per_process.バックエンドプロセス単位で使用するファイルディスクリプタ数の上限を設定できるようになりました.
    • authentication_timeout.ユーザ認証のタイムアウトを秒単位で指定します.デフォルトは60秒です.
    • dynamic_library_path.7.2では,バックエンドが関数オブジェクトをロードする際,オブジェクトのパスが’/’で始っていない場合,ここで指定したパスからサーチします.デフォルトでは’$libdir’ (通常 /usr/local/pgsql/lib)になっていますが,以下のように指定することもできます.
      dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
      
    • max_fsm_relations.7.2では,VACUUMはテーブルの空き領域を調べ,その情報を共有メモリにキャッシュします.その際に格納するテーブル数の上限を指定します.デフォルトは100です.
    • max_fsm_pages.空き領域の管理対象となるページ数の上限を指定します.デフォルトは10000です.
    • password_encryption.CREATE USER または ALTER USER で ENCRYPTED も UNENCRYPTEDも指定されなかったときに,パスワードを MD5で暗号化すべきかどうかを指定します.デフォルトは「暗号化しない」(false)です.
    • transform_null_equals.”foo = NULL”という式を”foo IS NULL”と同じものと見なすかどうかを指定します.デフォルトは「見なさない」(false)です.
    • vacuum_mem.vACUUMで再利用可能なタプルを探す際に使用するメモリの上限を8192Kb単位で指定します.デフォルトは1です.
  28. LOCKで複数のテーブルをロックできるようになりました.
         例:
         LOCK t1, t2, t3;
    
  29. パスワードをMD5で暗号化して格納できるようになりました.
         例:
         CREATE foo USER ENCRYPTED PASSWORD 'mypassword';
    

    これにともない,pg_hba.confに”md5″というキーワードが追加されています.使用例:

    host       template1   192.168.12.10 255.255.255.255    md5
    
  30. SET SESSION AUTHORIZATIONが追加されました.このコマンドはスーパーユーザーだけが使用可能で,バックエンドに接続し直すことなしにユーザーを変えることができます.
    SELECT SESSION_USER, CURRENT_USER;
     current_user | session_user
    --------------+--------------
     peter        | peter
    
    SET SESSION AUTHORIZATION 'paul';
    
    SELECT SESSION_USER, CURRENT_USER;
     current_user | session_user
    --------------+--------------
     paul         | paul
    
  31. GRANT/REVOKEで新しい権限 “REFERENCES”, “TRIGGER”が追加されました.
  32. UPDATE, DELETE の権限が別々に扱われるようになりました.
  33. 新しい関数 “has_table_privilege()” が追加されました.
  34. ALTER TABLE ADD UNIQUEでユニーク制約を追加できるようになりました.
  35. ALTER TABLE SET STATISTICS integer でオプティマイザが使用する統計情報の中の,頻繁に現れる値の数をデフォルトの10から変更できます.
  36. bit_length()が追加されました.
  37. トランザクションの開始時刻の精度が,秒単位からマイクロ秒単位になりました(実際の精度はプラットフォームに依存します).
  38. TIME/TIMESTAMP型で時刻精度の指定がサポートされました.
    test=# CREATE TABLE t1(d TIME(2));
    CREATE
    test=# INSERT INTO t1 VALUES(CURRENT_TIME);
    INSERT 116742 1
    test=# SELECT * FROM t1;
          d
    -------------
     15:11:34.05
    (1 row)
    
  39. CREATE OR REPLACE FUNCTIONがサポートされました.REPLACEでは,関数の OID は変りません.
  40. PL/pgSQL関係
    • カーソルがサポートされました.
                DECLARE
                    ...
                    curname CURSOR [(argname type [, ...])]
                            IS ;
                    ...
      

      では,変数が使えます.宣言したカーソルは以下のように開きます.

                BEGIN
                    ...
                    OPEN curname [(expr [, ...])];
                    ...
      

      REFCURSORはカーソルに対応するデータ型です.REFCURSORはデータ型なので,関数の引数や関数の戻値に使えます.

                DECLARE
                    ...
                    varname REFCURSOR [:= カーソル名];
                    ...
      

      REFCURSORは以下のように開きます.

                BEGIN
                    ...
                    OPEN varname FOR ;
                    -- or
                    OPEN varname FOR EXECUTE ;
                    ...
      

      関数の戻値を REFCURSOR にすることよって,複数の行を返す関数をPL/pgSQLで作ることができます.

      CREATE OR REPLACE FUNCTION reftest() RETURNS REFCURSOR AS
      '
      DECLARE
              ret REFCURSOR := ''r1'';
      
      BEGIN
              OPEN ret FOR SELECT * FROM t1;
              RETURN ret;
      END;
      ' LANGUAGE plpgsql;
      BEGIN;
      SELECT reftest();
      FETCH r1;
      END;
      

      カーソルは以下のように使います.

                BEGIN
                    ...
                    FETCH cursorvar INTO {record | row | var [, ...]};
                    ...
                    CLOSE cursorvar;
      

      カーソルを使ったループ.

                BEGIN
                    OPEN myrefcur FOR SELECT * FROM mytab;
                    LOOP
                        FETCH myrefcur INTO myrow;
                        EXIT WHEN NOT FOUND;
                     -- Process one row
                    END LOOP;
                    CLOSE myrefcur;
      
    • ELSEIFが PL/pgSQLで使えるようになりました.
  41. PostgreSQLの様々なパフォーマンス情報を収集するstatistics collector というデーモンプロセスが追加されました.postmasterを起動すると,以下のようなプロセスが起動されます.
    29621 ttyp0    S      0:00 postgres: stats buffer process
    29623 ttyp0    S      0:00 postgres: stats collector process
    

    この2本が,パフォーマンス情報を収集するプロセスです.実際にこのプロセスに情報を収集させるには,postgresql.confの以下のフラグを trueにする必要があります.

    • stats_command_string.有効にすると,pg_stat_activity viewにて,以下のように実行中のユーザ,SQL文などに関する情報が収集できます.
      test=#  select * from pg_stat_activity;
       datid | datname | procpid | usesysid | usename |                          current_query
      -------+---------+---------+----------+---------+------------------------------------------------------------------
       16556 | test    |    6229 |        1 | t-ishii | update branches set bbalance = bbalance + 19 where bid = 1
       16556 | test    |    6230 |        1 | t-ishii | update branches set bbalance = bbalance + 576 where bid = 1
       16556 | test    |    6231 |        1 | t-ishii | select abalance from accounts where aid = 49892
       16556 | test    |    6232 |        1 | t-ishii | <IDLE>
       16556 | test    |    6233 |        1 | t-ishii | end
       16556 | test    |    6234 |        1 | t-ishii | update accounts set abalance = abalance + 669 where aid = 5572
       16556 | test    |    6235 |        1 | t-ishii | update accounts set abalance = abalance + 520 where aid = 53106
       16556 | test    |    6236 |        1 | t-ishii | select abalance from accounts where aid = 50896
       16556 | test    |    6237 |        1 | t-ishii | <IDLE>
       16556 | test    |    6238 |        1 | t-ishii | update tellers set tbalance = tbalance + 548 where tid = 5
       16556 | test    |    6240 |        1 | t-ishii | <IDLE>
      (11 rows)
      
    • stats_row_level.行レベルの情報を収集します.
      test=# select * from pg_stat_sys_tables where relname = 'pg_am';
      -[ RECORD 1 ]-+------
      relid         | 16396
      relname       | pg_am
      seq_scan      | 17
      seq_tup_read  | 17
      idx_scan      | 0
      idx_tup_fetch | 0
      n_tup_ins     | 0
      n_tup_upd     | 0
      n_tup_del     | 0
      
    • stats_block_level.ブロックレベルのアクセスに関する情報を収集します.
      test=# select * from pg_statio_sys_tables where relname = 'pg_am';
      -[ RECORD 1 ]---+------
      relid           | 16396
      relname         | pg_am
      heap_blks_read  | 1
      heap_blks_hit   | 16
      idx_blks_read   | 0
      idx_blks_hit    | 0
      toast_blks_read |
      toast_blks_hit  |
      tidx_blks_read  |
      tidx_blks_hit   |
      
  42. plperlu(Untrusted PL/Perl)が追加されました.
  43. PL/Python が追加されました.

    性能向上,改良

  44. concurrent VACUUMにより,長期間にわたって初期の性能を維持できるようになりました.
  45. 部分インデックス(partial index)が追加されました.部分インデックスとは,列のすべての値をインデックス化するのではなく,WHERE 句で与えた条件を満たすものだけをインデックスにする機能です.検索時には,部分インデックス作成時の条件に該当するWHERE句が与えられたときだけインデックスが使われます.たとえば,ほとんどの値が 0 で,意味のある値が100-200であり,ほとんどの検索がその値の範囲に行われるような列では,100-200の値を持つ列に対してだけインデックスを作れば効率がよくなります.これが部分インデックスの考え方です.例を見てみましょう.まず部分インデックスを作ります.
    test=# CREATE INDEX pindex ON history(tid) WHERE tid BETWEEN 4 AND 6;
    

    これで,tidが4,5,6だけの部分インデックスが作られます.tidがこの値をはずれるような検索では,

    test=# EXPLAIN SELECT * FROM history WHERE tid = 8;
    NOTICE:  QUERY PLAN:
    
    Seq Scan on history  (cost=0.00..203.57 rows=49 width=50)
    
    EXPLAIN
    

    御覧のようにインデックスは使われません.それに対して,tid = 4の検索では,

    test=# EXPLAIN SELECT * FROM history WHERE tid = 4;
    NOTICE:  QUERY PLAN:
    
    Index Scan using pindex on history  (cost=0.00..5.99 rows=49 width=50)
    
    EXPLAIN
    

    インデックスが使われます.

  46. オプティマイザが使用する統計情報が改良されました.
  47. pg_hba.confはpostmasterの起動時か,SIGHUPシグナルを受けたときだけ読み込まれるようになりました.SIGHUPシグナルを送るためには,pg_ctl reloadを使用するのが便利です.
  48. コンパイル時の変数MAXBACKENDSがなくなり,カーネルが許す限りバックエンド数をいくらでも増やすことができるようになりました.
  49. SUM(), AVG(), COUNT() で内部計算がNUMERICからINT8に変り,性能が向上しました.

    修正されたバグ(主なもの)

  50. 7.1で動かなくなった関数の再帰呼び出しが動くようになりました.
  51. デッドロック後ロックが解放されないバグが修正されました.