※当サイトの記事には、広告・プロモーションが含まれます。

PostgreSQLの「過大属性格納技法(TOAST:The Oversized-Attribute Storage Technique)」とは

www.itmedia.co.jp

www.itmedia.co.jp

 募集背景には、「KADOKAWAグループではこれまで(情報セキュリティや情報管理を)各社で個別運用していたが、ガバナンス強化やコンプライアンス強化を目的に、グループ横断での情報セキュリティ管理体制の構築や社内規定の見直しを図っている」などと説明。数年単位を想定した新たな情報セキュリティ体制の構築を目指す。

KADOKAWAグループ、セキュリティエンジニア募集中 最大年収800万円 「0→1を経験」 - ITmedia NEWS

KADOKAWAグループ社内でセキュリティエンジニアを育成する方針の話は出なかったのかしらね...

PostgreSQLの「過大属性格納技法(TOAST:The Oversized-Attribute Storage Technique)」とは

「第47回PostgreSQLアンカンファレンス」に参加して、

  • 大属性格納技法(TOAST:The Oversized-Attribute Storage Technique)

という機能が存在することを知ったのですが、どんな目的を実現する想定で用意されているものなのかが分からなかったので調べてみました。

PostgreSQLの公式ドキュメントの日本語版によると、

www.postgresql.jp

PostgreSQLは固定長のページサイズ(通常8キロバイト)を使用し、複数ページにまたがるタプルを許しません。 そのため、大規模なフィールド値を直接格納できません。 この限界を克服するため、大規模なフィールド値を圧縮したり、複数の物理的な行に分割したりしています。 これはユーザからは透過的に発生し、また、バックエンドのコード全体には小さな影響しか与えません。 

https://www.postgresql.jp/docs/16/storage-toast.html

この技法はTOAST(またはパンをスライスして以来最善のもの)という愛称で呼ばれます。 [訳注:TOASTはパンのトーストと綴りが同じなので、スライスしたパンを美味しく食べる方法に掛けて洒落ています。] TOASTの基盤は大きなデータ値のインメモリで処理の改善にも使用されています。

https://www.postgresql.jp/docs/16/storage-toast.html

⇧ とのこと。

う~む、分からん。

前提として、

PostgreSQLシステム上の制限

  • PostgreSQLは固定長のページサイズ(通常8キロバイト)を使用し、複数ページにまたがるタプルを許しません。 そのため、大規模なフィールド値を直接格納できません。

■解決策

  • この限界を克服するため、大規模なフィールド値を圧縮したり、複数の物理的な行に分割したりしています。

ということらしく、この「解決策」を実現する技法のことを、

  • 大属性格納技法(TOAST:The Oversized-Attribute Storage Technique)

命名してるらしい。

PostgreSQLのタプルって何なのか

そもそもとして、PostgreSQLの「タプル」って何?

PostgreSQLの公式のドキュメントの日本語版だと、

www.postgresql.jp

Tuple【タプル】

属性を一定の順序で集めたもの。 この順序はタプルが含まれるテーブル(または他のリレーション)によって定義されます。その場合タプルは、しばしばと呼ばれます。 また結果セットの構造によって定義される場合もあります。その場合、タプルはレコードと呼ばれることがあります。

https://www.postgresql.jp/docs/16/glossary.html#GLOSSARY-TUPLE

Attribute【属性】

タプル内にある特定の名前とデータ型を持つ要素。

https://www.postgresql.jp/docs/16/glossary.html#GLOSSARY-TUPLE

⇧ 上記のような説明になっている。

う~む、分からん。

PostgreSQLアーキテクチャが関係しているらしい

とりあえず、

soudai.hatenablog.com

 富士通が後述の資料を参考にまとめたのだろうなと思われる記事。 非常によくまとまっているのでわかりやすい。

PostgreSQLの仕組みから学ぶために必要な資料 - そーだいなるらくがき帳

もっと細かく知りたいならPostgreSQL Internalsがおすすめ。 富士通の資料と重複するところがあるがこっちが本家。 Githubで管理されているので誤字脱字などあったら気軽にPRを出してほしい。

PostgreSQLの仕組みから学ぶために必要な資料 - そーだいなるらくがき帳

⇧ 上記サイト様が紹介してくれているサイトの情報を見てみる。

www.fujitsu.com

PostgreSQLの基本構成

PostgreSQLの基本的な構成について説明します。はじめに、主なプロセス、メモリー、および、ファイルについての構成図を示します。

PostgreSQLのアーキテクチャー概要|PostgreSQLインサイド : 富士通

■共有バッファー(shared_buffers)

ディスク上にあるテーブルやインデックスのデータを、ブロック単位で共有メモリー上にキャッシュするための領域です。データファイルは、複数の8,192バイトのブロックで構成されおり、この単位でキャッシュします(OSのシステムキャッシュを経由します)。PostgreSQLのサーバープロセスは、共有バッファー上のテーブルやインデックスのデータにアクセスすることで、ディスクI/Oを削減しパフォーマンスを向上させます。共有バッファーに読み込まれたブロックは、「ページ」と呼びます。なお、各種技術文書では、「ページ」のことを「ブロック」や「バッファー」と表現されることもあります。

PostgreSQLのアーキテクチャー概要|PostgreSQLインサイド : 富士通

www.postgresqlinternals.org

PostgreSQLの基本的なアーキテクチャ

図の一番右側に共有バッファと呼ばれるメモリの空間がありますが、PostgreSQLの基本的なアーキテクチャというのは、共有バッファを中心として複数のプロセッサに連携しながら処理を行うというものです。

https://www.postgresqlinternals.org/chapter1/

⇧ とあり、PostgreSQLでディスクとしている場所に保管しているデータをメモリ上に展開する際に、

データファイルは、複数の8,192バイトのブロックで構成されおり、この単位でキャッシュします(OSのシステムキャッシュを経由します)

共有バッファーに読み込まれたブロックは、「ページ」と呼びます。なお、各種技術文書では、「ページ」のことを「ブロック」や「バッファー」と表現されることもあります。

という制限があることから、

PostgreSQLは固定長のページサイズ(通常8キロバイト)を使用し、複数ページにまたがるタプルを許しません。

の話に戻ってくると。

PostgreSQLにおける「Tuple」が何なのか今いちハッキリしないのだけど、現状のPostgreSQLアーキテクチャでは、

  1. PostgreSQLは固定長のページサイズ(通常8キロバイト)を使用
  2. 複数ページにまたがるタプルを許しません。

という縛りがあるせいで、

  • 大属性格納技法(TOAST:The Oversized-Attribute Storage Technique)

という仕組みが必要になったと。

と言うか、

kaigai.hatenablog.com

PostgreSQLで可変長データ型を扱う時、内部的にはTOASTと呼ばれる機構を利用して、別の隠しテーブルに可変長のデータを格納するようになっている。この時、可変長のデータは適正な長さに分割されて格納されるので、タプル一個あたりのデータ長がブロックサイズを超える事はない。

TOASTメカニズム - KaiGaiの俺メモ

⇧ 上記サイト様によりますと、PostgreSQL内部の処理で利用されている機能だったっぽい。

qiita.com

すごく雑に言うと、超長いデータを8KB固定のページに収めるための技術。
ユーザからみると基本的にはこれを意識することなく、勝手にPostgreSQLでやってくれる。

PostgreSQL 14がやってくる(4) - TOAST圧縮方式の変更 #PostgreSQL14 - Qiita

TOAST機能でデータを圧縮する場合、従来は規定の圧縮方式(pglz)のみを使っていたが、PostgreSQL 14からはlz4を選択可能になった。

PostgreSQL 14がやってくる(4) - TOAST圧縮方式の変更 #PostgreSQL14 - Qiita

⇧ 圧縮方式とかが設定できるそうな。

一応、PostgreSQL 17が出てはいるけど、現時点で、日本語版のドキュメントが用意されてるのが、PostgreSQL 16までっぽいので、PostgreSQL 16のドキュメントがの日本語版を確認したところ、

www.postgresql.jp

行内あるいは行外の圧縮データで使用される圧縮技術は、CREATE TABLEまたはALTER TABLECOMPRESSION列オプションを設定することで各列に対して選択できます。 明示的な設定のない列に対するデフォルトは、データが挿入されるときにdefault_toast_compressionパラメータを参照することです。

https://www.postgresql.jp/docs/16/storage-toast.html

www.postgresql.jp

default_toast_compression (enum

この変数は圧縮可能な列の値のデフォルトTOAST圧縮方式を設定します。 (これはCREATE TABLEあるいはALTER TABLECOMPRESSION列オプションを設定することにより、置き換えることができます。) サポートされている圧縮方式は、pglzlz4PostgreSQL--with-lz4コンパイルされている場合)です。 デフォルトはpglzです。

https://www.postgresql.jp/docs/16/runtime-config-client.html#GUC-DEFAULT-TOAST-COMPRESSION

⇧ 圧縮方式は、

  1. pglz
  2. lz4

の2つというのは変わっていないっぽいのだけど、デフォルトは「pglz」になっていますと。

選択肢が増えてしまったことから、PostgreSQLを利用するユーザーとしても意識せざるを得ないような...

まぁ、

www.postgresql.jp

一部のデータ型のみがTOASTをサポートします。 大規模なフィールド値を生成することがないデータ型にオーバーヘッドを負わせる必要はありません。

https://www.postgresql.jp/docs/16/storage-toast.html

TOASTをサポートするためには、データ型は可変長(varlena)表現を持たなければなりません。 通常は、格納する値の最初の4バイトワードには値の長さ(このワード自体を含む)がバイト単位で含まれます。 TOASTは残りのデータ型の表現について制限しません。 TOAST化された値として集合的に呼ばれる特別な表現は、この先頭の長さのワードを更新または再解釈することで動作します。

https://www.postgresql.jp/docs/16/storage-toast.html

 したがって、TOAST可能なデータ型をサポートするC言語関数は、潜在的TOAST化されている入力値の扱い方に注意しなければなりません。 つまり、入力がTOAST解除されなければ、それは実際には4バイトの長さのワードと内容から構成されていないかもしれないのです。 (通常これは、入力に対して何か作業をする前にPG_DETOAST_DATUMを呼び出すことで行われますが、もっと効率的な方法が可能な場合もあります 詳しくは38.13.1を参照してください)。

https://www.postgresql.jp/docs/16/storage-toast.html

⇧ テーブルのカラムのデータ型で、

  • 大属性格納技法(TOAST:The Oversized-Attribute Storage Technique)

が必要になるようなものを採用していなければ関係なさそうではありますが...

毎度モヤモヤ感が半端ない…

今回はこのへんで。