無料スクリプト配布のPHP.TO   PHPの実用的なtips PHPマニュアル MySQLマニュアル Apacheマニュアル PostgreSQLマニュアル マニュアル検索    

58.2. TOAST

本節では TOAST (過大属性格納技法:The Oversized-Attribute Storage Technique)の概要について説明します。

PostgreSQL は固定長のページサイズ(通常8キロバイト)を使用し、複数ページにまたがるタプルを許しません。 そのため、大規模なフィールド値を直接格納できません。 大規模なフィールド値を圧縮したり、複数の物理的な行に分割したりすることで、この限界はなくなりました。 これはユーザからは透過的に発生し、また、バックエンドのコード全体には小さな影響しか与えませんでした。 この技法は TOAST (または "パンをスライスして以来最善のもの" )という愛称で呼ばれます。 [訳注:“パンをスライスして以来最善のもの(the best thing since sliced bread)”は素晴らしいものを意味します。]

一部のデータ型のみが TOAST をサポートします。 大規模なフィールド値を生成することがないデータ型にオーバーヘッドを負わせる必要はありません。 TOAST をサポートするためには、データ型は可変長( varlena )表現を持たなければなりません。 格納する値の最初の32ビットワードにはバイト単位の値の(このワード自体を含む)長さが含まれます。 TOAST は残りの表現について制限しません。 TOAST 可能なデータ型をサポートするC言語関数はすべて、 TOAST 化された入力値を注意して扱わなければなりません (通常これは、入力に対して何か作業をする前に PG_DETOAST_DATUM を呼び出すことで行われますが、もっと効率的な方法が可能な場合もあります)。

TOAST はvarlenaの長さワードの2ビット(ビッグエンディアンのマシンでは上位ビット、リトルエンディアンのマシンでは下位ビット)を勝手に使用します。 そのため、すべての TOAST 可能なデータ型の値の論理サイズは1ギガバイト(2 30 - 1バイト)までになります。 両ビットが0の場合、値はそのデータ型の普通の TOAST 化されていない値となり、長さワードの残りのビットはデータの(長さワードを含む)総サイズ(バイト単位)となります。 上位側または下位側のどちらか片方のビットが設定された場合、値は通常の4バイトのヘッダを持たず1バイトのヘッダを持ちます。 また、長さワードの残りビットはデータの(長さワードを含む)総サイズ(バイト単位)となります。 特殊な状況として、長さワードの残りビットがすべて0(自身の長さを含みますのでありえません)の場合、その値は別のTOASTテーブルに保存される行外データへのポインタです。 (TOASTポインタのサイズはデータの第2バイト内で与えられます。) 単一バイトヘッダを持つ値は特定の境界に整列されません。 最後に上位側または下位側のビットが0で隣のビットが設定されている場合、データの内容は圧縮され、使用前に伸長しなければなりません。 この場合、長さワードの残りビットは元データのサイズではなく圧縮したデータの総サイズになります。 圧縮が行外データでも起こりえますが、varlenaヘッダには圧縮されているかどうかについての情報がないことに注意してください。 その代わりTOASTポインタの内容にこの情報が含まれています。

テーブルの任意の列が TOAST 可能な場合、そのテーブルは連携する TOAST テーブルを持ちます。 TOAST テーブルのOIDはテーブルの pg_class . reltoastrelid 項目に格納されます。 詳細は後で説明しますが、行外の TOAST 化された値は TOAST テーブル内に保持されます。

使用される圧縮技術は、LZ系の圧縮技術の1つで単純かつ非常に高速なものです。 詳細は src/backend/utils/adt/pg_lzcompress.c を参照してください。

行外の値は(圧縮される場合は圧縮後に)最大 TOAST_MAX_CHUNK_SIZE バイトの塊に分割されます (デフォルトではこの値は4チャンク行が1ページに収まり、およそ2000バイトになるように選ばれます)。 各塊は、データを持つテーブルと連携する TOAST テーブル内に個別の行として格納されます。 すべての TOAST テーブルは chunk_id 列(特定の TOAST 化された値を識別するOID)、 chunk_seq 列(値の塊に対する連番)、 chunk_data (塊の実際のデータ)列を持ちます。 chunk_id chunk_seq に対する一意性インデックスは値の抽出を高速化します。 したがって、行外の TOAST 化された値を示すポインタデータには、検索先となる TOAST テーブルのOIDと指定した値のOID( chunk_id )を格納しなければなりません。 簡便性のために、ポインタデータには論理データサイズ(元々の非圧縮のデータ長)と実際の格納サイズ(圧縮時には異なります)も格納されます。 varlenaヘッダバイトに収納するために TOAST ポインタデータの総サイズは、表現される値の実サイズに関係なく、18バイトになります。

TOAST のコードは、テーブル内に格納される値が TOAST_TUPLE_THRESHOLD バイト(通常2キロバイト)を超える時にのみ実行されます。 TOAST コードは、行の値が TOAST_TUPLE_TARGET バイト(こちらも通常2キロバイト)より小さくなるかそれ以上の縮小ができなくなるまで、フィールド値の圧縮や行外への移動を行います。 更新操作中、変更されない値は通常そのまま残ります。 行外の値を持つ行の更新では、行外の値の変更がなければ TOAST するコストはかかりません。

TOAST コードでは、以下の TOAST 可能な列を格納するための4つの異なる戦略を認めます。

TOAST 可能なデータ型はそれぞれ、そのデータ型の列用のデフォルトの戦略を指定します。 しかし ALTER TABLE SET STORAGE を使用して、あるテーブル列の戦略を変更することができます。

この機構には、ページをまたがる行の値を許可するといった素直な手法に比べて多くの利点があります。 通常問い合わせは比較的小さなキー値に対する比較で条件付けされるものと仮定すると、エクゼキュータの仕事のほとんどは主だった行の項目を使用して行われることになります。 TOAST 化属性の大規模な値は、(それが選択されている時)結果集合をクライアントに戻す時に引き出されるだけです。 このため、主テーブルは行外の格納を使用しない場合に比べて、かなり小さくなり、その行は共有バッファキャッシュにより合うようになります。 ソート集合もまた小さくなり、ソートが完全にメモリ内で行われる頻度が高くなります。 小規模な試験結果ですが、典型的なHTMLページとそのURLを持つテーブルでは、 TOAST テーブルを含め、元々のデータサイズのおよそ半分で格納でき、さらに、主テーブルには全体のデータのおよそ10%のみ(URLと一部の小さなHTMLページ)が格納されました。 TOAST化されないようにすべてのHTMLページを7キロバイト程度に切り詰めてた TOAST かつ圧縮化しないテーブルと比べ、実行時に違いはありませんでした。


powered by SEO.CUG.NET