YakstYakstは、海外の役立つブログ記事などを人力で翻訳して公開するプロジェクトです。5.7.8で公式となった。主な機能についての振返りと、いくつかの簡単な性能テストの結果をお伝えする。InnoDB」(2015/8/11)をユーザが翻訳したものであり、Oracle公式の文書ではありません。4月に私はブログ投稿を行い、JSONのlab版リリースへの新しいInnoDBの仮想列および効果的な関数インデックスについて紹介した。5.7.8で機能は公式なものとなっている。5.7のリリース候補版に何があるのかを記し、追加の例を示すにあたりその話題は再度確認する価値がある。いくつかの簡単な性能テストも実施しており、テーブルへの簡単な操作における仮想カラムおよびインデックスがある場合とない場合の比較および、マテリアライズされた生成列との比較を実施した。以前の投稿で、設計の詳細については述べている。確認されていない場合は、始めに確認することをお勧めする。全ての設計の詳細には踏み込まないが、いくつかキーとなる点を再度述べることにする。仮想列はテーブルにおいて、もはやマテリアライズされない。完全に「仮想」でありInnoDBの行として保存されず(InnoDBはテーブルのデータをプライマリキーのレコード、つまりクラスタインデックス、に保存し、仮想列はInnoDBのプライマリキーのレコードに存在しない)、全体のテーブルのサイズを小さくする。これにより、テーブルスキャンおよび他の大きな操作が高速化されうる。完全に「仮想」であるので、仮想列の追加および削除にテーブルの再構成が不要である。新しいメタデータを登録する為のシステムテーブルの更新が必要なだけである。これによりスキーマ変更がシンプルで高速となる。仮想列へのインデックスの作成(セカンダリインデックスのみが許される)は、必然的に仮想列を計算された値がセカンダリインデックス内に保存されるようにインデックスレコードに"マテリアライズする"。値はプライマリキー(クラスタインデックス)には保存されない。従ってテーブル自体は小さいまま、セカンダリインデックス内の計算済みの(保存された)仮想列の値を素早く参照できる。インデックスが仮想列に対して生成されたら、仮想列へのロールバックおよびパージ操作が発生したときに仮想列の値を不必要に再計算しなくてよいように、仮想列の値をMVCCで記録する。この目的はセカンダリインデックスのみを維持することにあるので、スペースを節約する為にある特定のデータ長までのみを記録する。インデックスはCOMPACTおよびREDUNDANT形式の場合は767バイト、DYNAMICおよびCOMPRESSED形式の場合は3072バイトのキー長の制限がある。初期のlab版のリリースから変更/追加されたもののうち有用で重要なものをいくつか紹介する。単一の「関数インデックス」が、仮想列および非仮想列の両方を含んだ組合わせに対して作成可能となった。これは仮想および非仮想生成列の混合に対してコンポジット(複合)インデックスが作成可能となった。インプレイスアルゴリズムを利用することで関数インデックスをオンラインで作成可能となった。これはDML文がインデックス作成中でも処理されるようにするためである。これを達成する為に、DML文が同時に発生する箇所の仮想列の値は、インデックス作成中に計算および記録され、後で関数インデックスに対してリプレイされる。仮想列が他の仮想列に対して作成可能となりそれに対してもインデックスを作成できるようになった。次の改善はユーザーにとっては分かりにくいが、言及するに値する。インデックスが作成された仮想列に対するパージ関連のアクティビティーに関する機能拡張に関するものだ。新しいコールバック(WL#8841)はサーバーレイヤの機能を提供し、これはInnoDBのパージスレッドから呼ばれ、仮想列のインデックスの値を計算する。一般的にこの計算はコネクションスレッド(またはセッション)から行われるが、内部のInnoDBパージスレッドはコネクションおよびセッションに対応付かないため、スレッドをもたないし、アクセスするテーブルオブジェクトをもたない。この取組みはパージスレッドが必要な計算を行う為に必要なサーバーレイヤのコールバックを提供する為に必要であった。して「関数インデックス」周辺にはいくつかの特筆すべき制限事項がある。いくつかに関しては、後の取組みで解決する予定である。仮想列は繰返し不可能な/非決定的な関数に対して作成できない。仮想列の追加および削除は操作が単体で行われたときのみインプレイスあるいはオンラインで実行でき、他のテーブル変更と同時には実行できない。この制限は後に削除される予定だが、インプレイスの仮想列の追加および削除操作を別々のDDL文になるようにすることで対処可能である。前回のブログ投稿で我々はいくつかのJSON関数と共に「関数インデックス」をどのように使うのかの例を示した。ユーザーは仮想カラムに対して非決定的でない限り(例えばNOW())どんな関数も利用可能である。それでは、JSON関数以外の追加の例をみてみよう。経度)間の距離(メートル)を保存する仮想列をどのように追加するかを例として示す。地理データを格納するテーブルを作成する。sec)ここで2点間の距離(メートルで)を計りたい。テーブルを再構成することなく、仮想列を追加しインデックスを作成することができる。0これで、このテーブルを新しく追加された仮想列およびインデックスを利用することで、簡単にそして素早くクエリを発行できる。使った列をいくつか加えることもできる。例としては下記である。sec)最後に、独自の関数(もしくはユーザー定義関数)を作成することも可能であり、これを仮想列のベースとして利用できることを述べておこう。簡単なベンチマーク予想されている通り、仮想列上のインデックスを利用している場合は、それらをマテリアライズする必要がある場合(例えば、INSERTまたはUPDATE)、必要とされる計算の為に、追加の書込みコスト、言い換えればインデックスを作成あるいは維持するのに関連したコストがかかる。列に関数インデックスがなければ、コストは行の読取りに関連し、これは行が検査されるたびに値がマテリアライズされる必要があるためである。この追加のコストは利用される関数の計算の複雑さに直接関連する。追加のコストがあるとはいえ、仮想生成列および「関数インデックス」は後にデータをクラスタインデックス(主キー)にマテリアライズする為に、ストアド生成列を含むテーブルを作成するよりははるかに良く、結果としてより大きなテーブル(ディスク上、メモリ上いずれも)となる。次の簡単なテストを3種類のテーブルに対して実施する。ENGINE=InnoDB;このテーブルは4つの通常の列と5つの仮想生成列をもつ。関数自体の影響を最小化する為に、仮想列に利用される関数は簡易なものとした。column)」の総称である。なし」「マテリアライズされた、あるいはストアド生成列」となっている。修正して意訳している。ENGINE=InnoDB;それから、次のプロシージャを各テーブルに行をINSERTするのに使う。GNU/Linuxのマシンで、InnoDBバッファプールが10GBの状態で実施された。テストはシングルスレッドで実施され、結果は3回の結果の平均値である。ここに結果を記載する。secセカンダリインデックスのないテーブルに対する挿入に関しては、仮想列の全くないテーブルと、仮想生成列があるテーブルでとても良く似た実行時間である。後者は列をマテリアライズしていないので、挿入されるデータの量は2つのテーブルで厳密に等しい。列がマテリアライズされると(テーブル3)、かかる時間は明らかに長くなる。1つだけ述べておく必要があるのはテーブル1とテーブル2でかかる時間がほとんど同じとはいえ、テーブル1の挿入の方がわずかに長いということだ。これは不要な計算が仮想生成列のあるテーブルに対して行われている為で、これはそのうち修正される予定である。インデックスの作成3つのテーブルの同じ位置づけの列にインデックスを作成する。secテーブル1の仮想生成列v_eへのインデックスの作成は、テーブル2の基底列へのそれよりわずかにコストが高く、これは仮想生成列へのインデックス作成が値の計算を必要とする為である。このケースにおいては、ストアド生成列の同じ列にインデックスを作成するより高速である。これはただ単に仮想列のあるテーブルは大きいため、単純なスキャンに時間がかかるためである。INDEXのいくつかの結果を示す。テーブル1は仮想生成列のあるテーブルt既に述べた通り、仮想生成列へのインデックス作成は、各行への計算が必要となるため、通常の列へのインデックス作成よりコストがかかる。COLUMNを行うのに通常テーブル全体の再構成が必要となる。仮想生成列を追加し、それが必要とされなければほぼ一瞬でおわる。同じように、仮想生成列の削除はいくつかの理由で、はるかに高速である。sec仮想列または「関数インデックス」を用いたDMLINSERTこの例で示されたように、インデックスが作成された仮想生成列のあるテーブルへの挿入時間は、クラスタインデックス(プライマリキー)に値をマテリアライズするテーブル3に比べてはるかに短い。secUPDATE次のUPDATE文が3つのテーブルに実施され結果は下記の通りであった。secお分かりの通り、インデックスが作成された仮想生成列へのUPDATE文はよりコストがかかる。これは追加のMVCCのコストが操作(e列関連のあらゆる操作に加え)に関連していることを実証している。v_eの古い値が計算される必要がある(UNDOログ用)v_eの新旧の値がUNDOログに記録される必要がある為である。secDELETE文に関しては、ストアド生成列があるテーブルより、仮想生成列があるテーブルの方が高速である。仮想生成列のあるテーブルは明らかにマテリアライズされたカラムのあるテーブルより小さい。従って削除操作ははるかに高速となる。DELETE操作は、仮想生成列にインデックスが作成されている場合は、いくらか追加のMVCCの操作も必要となる。v_eの古い値は計算される必要がある(UNDOログ用)v_eの新旧の値がUNDOログに記録される必要がある為である。従って、DELETE文は通常の列を利用するよりもわずかにコストが高いが、ストアド生成列に比べるとはるかに高速である。SELECTクエリもちろん、お察しの通り、ストアド生成列のあるテーブルは、仮想生成列のあるテーブルよりはるかに大きい。これはテーブルスキャンを簡単に行ってみれば明らかである(事前にデータをバッファプール上に持ってくる為クエリを実行しておく)。sec上記で示された通り、ストアド生成列のあるテーブルへのスキャンは、仮想生成列のあるテーブルへのスキャンより3倍時間がかかった。仮想生成列および仮想インデックスがあるテーブルは小さい一方で、クエリを効果的に実行させる為のマテリアライズ(セカンダリ)インデックスをもつ長所を活かしている。secchar_length(a)への「関数インデックス」がなければ、テーブル2は結果を得る為にフルテーブルスキャンが必要である。これはすばらしい機能で、ユーザーが仮想生成列を追加/削除可能であり、同時にこれらの列に対してオプションでセカンダリインデックスを作成することができ、かつこれがオンライン操作で可能である。上記の簡単な性能調査で示した通り、マテリアライズしたデータは基底テーブルの容量を小さくし(InnoDBのクラスタ/プライマリインデックスの重複したコピーをもたないため)、永続化ストレージ領域およびメモリの利用をより効率化し、同時にクエリの性能を大幅に改善する。@yakstcom_req_jaYakstYakstお問い合わせ。