原文はこちら。
https://blogs.oracle.com/In-Memory/entry/what_is_an_in_memory
以前の一連のエントリ"Getting Started"で、In-Memory column store (IM column store / インメモリ列ストア)がSystem Global Area(SGA)に含める方法、初期化パラメータ inmemory_sizeを設定してインスタンス立ち上げ時に割り当てる方法を紹介してきました。
この結果、SGAの割り当ては以下のようになっています。
説明しなかったことは、IM列ストアは実際には2個のプール(1MBと64KBのプール)に分かれており、動的パフォーマンスビューの v$inmemory_area をクエリすることで監視することができます。
IM列ストアに割り当てられている800MBのうち、639MBが1MBプールに、144MBが64KBプールに割り当てられていることがわかります。
それでは、これらのプールがどのような目的で使われるのでしょうか。
1MBプールは移入されたデータをIM列ストアに格納するために、64KBプールは移入されたデータのメタデータを格納するために使われています。よく領域の割り当てを変更できるのか、という質問をいただきますが、その答えはNoで、これらのサイズはOracle Databaseが判断、決定します。
下図はIM列ストアを1MBプールと64KBプールのイメージを図示したものです。
1MBプールのデータがIMCUに格納され、64KBプールのデータがSMUに格納されていることがわかります。
ところで、インメモリー圧縮単位(IMCU、In-Memory Compression Unit)とスナップショットメタデータ単位(SMU、Snapshot Metadata Unit)って何なんでしょうか。
IMCUは、IM列ストア内のストレージの論理単位で、凡そ表領域内のエクステントとほぼ同等です。
セグメントをIM列ストアに移入した場合、1個もしくはそれ以上のIMCUに格納されます。各IMCUにはセグメントからのたくさんの行が含まれています。行の長さの平均値と選択された圧縮タイプによってIMCU毎の行数が管理されます。高圧縮レベルを選択すると、それに応じてIMCU中の行の個数が増えます。指定されたセグメントのすべてのIMCUにはほぼ同数の行が含まれます。IMCU内に含まれる行数は動的パフォーマンスビュー(v$im_header dynamic)で確認することができます(後述します)。
IMCUにはIMCUヘッダが含まれています。これはIMCUに関するメタデータとcolumn compression unit(column CU / 列圧縮単位)を保持しています。デフォルトではセグメントの各列に対し1個のcolumn CUがありますが、列の値に対応するROWIDのためにもう一つcolumn CUが加わります。デフォルトでは、セグメント内の各列に1個のcolumnn CUがあり、さらに列の値に対応するROWIDのための1個のcolumn CUがあります。この構成により、簡単に元の行に対応する列をステッチバックすることができます。基本的なレイアウトを以下に示します。
各IMCUは、IMCUのメタデータを保持する64KBプールのSMUにマップされます。
v$inmemory_areaビューをクエリする場合、IMCUと1MBプールの関係性についてよく質問を受けます。
オブジェクトをIM列ストアに移入し、IMCUとSMU、そしてこの2個のプールの関係について調べてみましょう。例としてLINEORDER表を使います。表をINMEMORYに変更してから、MEMCOMPRESS FOR QUERY LOWのデフォルトの圧縮レベルを受け入れます。この場合、デフォルトの優先度がNONE(LINEORDER表へ初めてアクセスされるまでインメモリへの移入は発生しないことを意味します)なので、表からSELECTを実行します。
移入の間、バックグラウンドプロセスが実際の移入を実施しています。これらのプロセスはora_wxxx_sidという形式の名前になっており、今回の例ではora_w000_orcl、ora_w001_orcl、ora_w002_orclという3個のプロセスをtopコマンドで確認できます。
移入が完了し、v$im_segmentsとv$inmemory_areaビューをクエリすると以下のような結果を得ることができます。
LINEORDER表は完全に移入され(つまりbytes_not_populated = 0)ており、1MBプールで550MB、64KBプールで1472KB使っていることがわかります。それではこの値とIMCUの関係はどうなっているのでしょうか。
これはつまりLINEORDER表のために550IMCUを有しているということでしょうか(つまり550 1MB IMCU)。
確認してみましょう。
別の動的パフォーマンスビュー(v$im_header)を使って先ほど述べた把握することができます。これはセグメントが割り当てるIMCUを表示するものです。1個のセグメントだけが移入されたので、LINEORDER表をどのように移入したかを非常に簡単に確認できるはずです。
クエリに抽出条件「where is_head_piece = 1」がついていることにお気づきかもしれません。この条件を追加した理由は、v$im_headerビューの複数列が取り出される場合、IMCUが1個以上の「piece」から構成されうることがわかるでしょう。
このクエリの結果、1MBプールから割り当てられているため、IMCUが1個もしくはそれ以上の1MBエクステントから構成されていて、各IMCUは1個以上のピースから構成される可能性があることがわかります。
ではなぜIMCUが1個以上のピースから構成されているのでしょうか。
前述のように、IMCUが保持する行数はIMCUが消費する領域の量に影響します。対象となる行数によって、IMCUが1MBプールで利用可能な連続した1MBエクステントのサイズを上回ると、追加ピースもしくはエクステントを作成して、残りのcolumn CUを保持しようとします。
まとめると、オブジェクトをIM列ストアに移入する場合、1個もしくは複数個のIMCUに移入され、これらのIMCUには、1MBプールから割り当てられた一つもしくは複数の1MBエクステントが含まれます。各IMCUには対応するSMUもあり、これは64KBプールから割り当てられます。
https://blogs.oracle.com/In-Memory/entry/what_is_an_in_memory
以前の一連のエントリ"Getting Started"で、In-Memory column store (IM column store / インメモリ列ストア)がSystem Global Area(SGA)に含める方法、初期化パラメータ inmemory_sizeを設定してインスタンス立ち上げ時に割り当てる方法を紹介してきました。
Getting Started / Oracle Database In-Memoryこのブログエントリの目的のため、今回の実行環境では、Oracle Database 12.1.0.2をinmemory_sizeとして800MB、sga_targetとして3008MBを割り当てています。
https://blogs.oracle.com/In-Memory/tags/getting_started
この結果、SGAの割り当ては以下のようになっています。
説明しなかったことは、IM列ストアは実際には2個のプール(1MBと64KBのプール)に分かれており、動的パフォーマンスビューの v$inmemory_area をクエリすることで監視することができます。
IM列ストアに割り当てられている800MBのうち、639MBが1MBプールに、144MBが64KBプールに割り当てられていることがわかります。
それでは、これらのプールがどのような目的で使われるのでしょうか。
1MBプールは移入されたデータをIM列ストアに格納するために、64KBプールは移入されたデータのメタデータを格納するために使われています。よく領域の割り当てを変更できるのか、という質問をいただきますが、その答えはNoで、これらのサイズはOracle Databaseが判断、決定します。
下図はIM列ストアを1MBプールと64KBプールのイメージを図示したものです。
1MBプールのデータがIMCUに格納され、64KBプールのデータがSMUに格納されていることがわかります。
ところで、インメモリー圧縮単位(IMCU、In-Memory Compression Unit)とスナップショットメタデータ単位(SMU、Snapshot Metadata Unit)って何なんでしょうか。
IMCUは、IM列ストア内のストレージの論理単位で、凡そ表領域内のエクステントとほぼ同等です。
セグメントをIM列ストアに移入した場合、1個もしくはそれ以上のIMCUに格納されます。各IMCUにはセグメントからのたくさんの行が含まれています。行の長さの平均値と選択された圧縮タイプによってIMCU毎の行数が管理されます。高圧縮レベルを選択すると、それに応じてIMCU中の行の個数が増えます。指定されたセグメントのすべてのIMCUにはほぼ同数の行が含まれます。IMCU内に含まれる行数は動的パフォーマンスビュー(v$im_header dynamic)で確認することができます(後述します)。
IMCUにはIMCUヘッダが含まれています。これはIMCUに関するメタデータとcolumn compression unit(column CU / 列圧縮単位)を保持しています。デフォルトではセグメントの各列に対し1個のcolumn CUがありますが、列の値に対応するROWIDのためにもう一つcolumn CUが加わります。デフォルトでは、セグメント内の各列に1個のcolumnn CUがあり、さらに列の値に対応するROWIDのための1個のcolumn CUがあります。この構成により、簡単に元の行に対応する列をステッチバックすることができます。基本的なレイアウトを以下に示します。
各IMCUは、IMCUのメタデータを保持する64KBプールのSMUにマップされます。
v$inmemory_areaビューをクエリする場合、IMCUと1MBプールの関係性についてよく質問を受けます。
オブジェクトをIM列ストアに移入し、IMCUとSMU、そしてこの2個のプールの関係について調べてみましょう。例としてLINEORDER表を使います。表をINMEMORYに変更してから、MEMCOMPRESS FOR QUERY LOWのデフォルトの圧縮レベルを受け入れます。この場合、デフォルトの優先度がNONE(LINEORDER表へ初めてアクセスされるまでインメモリへの移入は発生しないことを意味します)なので、表からSELECTを実行します。
移入の間、バックグラウンドプロセスが実際の移入を実施しています。これらのプロセスはora_wxxx_sidという形式の名前になっており、今回の例ではora_w000_orcl、ora_w001_orcl、ora_w002_orclという3個のプロセスをtopコマンドで確認できます。
移入が完了し、v$im_segmentsとv$inmemory_areaビューをクエリすると以下のような結果を得ることができます。
LINEORDER表は完全に移入され(つまりbytes_not_populated = 0)ており、1MBプールで550MB、64KBプールで1472KB使っていることがわかります。それではこの値とIMCUの関係はどうなっているのでしょうか。
これはつまりLINEORDER表のために550IMCUを有しているということでしょうか(つまり550 1MB IMCU)。
確認してみましょう。
別の動的パフォーマンスビュー(v$im_header)を使って先ほど述べた把握することができます。これはセグメントが割り当てるIMCUを表示するものです。1個のセグメントだけが移入されたので、LINEORDER表をどのように移入したかを非常に簡単に確認できるはずです。
クエリに抽出条件「where is_head_piece = 1」がついていることにお気づきかもしれません。この条件を追加した理由は、v$im_headerビューの複数列が取り出される場合、IMCUが1個以上の「piece」から構成されうることがわかるでしょう。
このクエリの結果、1MBプールから割り当てられているため、IMCUが1個もしくはそれ以上の1MBエクステントから構成されていて、各IMCUは1個以上のピースから構成される可能性があることがわかります。
ではなぜIMCUが1個以上のピースから構成されているのでしょうか。
前述のように、IMCUが保持する行数はIMCUが消費する領域の量に影響します。対象となる行数によって、IMCUが1MBプールで利用可能な連続した1MBエクステントのサイズを上回ると、追加ピースもしくはエクステントを作成して、残りのcolumn CUを保持しようとします。
まとめると、オブジェクトをIM列ストアに移入する場合、1個もしくは複数個のIMCUに移入され、これらのIMCUには、1MBプールから割り当てられた一つもしくは複数の1MBエクステントが含まれます。各IMCUには対応するSMUもあり、これは64KBプールから割り当てられます。