データベース・マネージャーでは、 列内でのデータ値の分布を簡潔に記述する 2 種類の統計として、 「頻出値統計」と 「変位値」を、収集、保守、および使用することができます。 最適化プログラムでそれらの統計を使用すると、ある列に関して、 所定の等号述部または範囲述部を満たす行の数をかなり正確に見積もりできるようになります。 こうしたより正確な見積もりにより、 最適化プログラムが最適の計画を選択する可能性が大きくなります。
RUNSTATS コマンドで WITH DISTRIBUTION 文節を使用すると、 こうしたデータ値の分布に関する統計を収集することができます。 そのような付加的な統計を収集すると、 RUNSTATS ユーティリティーには追加のオーバーヘッドが生じますが、 SQL コンパイラーはこの情報を使用して最適なアクセス・プランを選択できるようになります。
場合によっては、データベース・マネージャーは分布統計を収集せずエラーも戻らないことがあります。 たとえば、以下のようになります。
分布統計は、索引の最初の列の場合には正確です。 この列以降の各列については、 正確な統計を計算するには余りにも多くの時間とメモリーが必要となるため、 データベース・マネージャーは、ハッシュおよびサンプリングの技法を使って、 分布統計を見積もります。 これらの技法は、かなり正確な統計方法とされています。
分布統計は、 SYSSTAT.COLDIST を更新し、 分布統計の必要がなくなった列のすべての COLVALUE 値および VALCOUNT 値に 0 または -1 のいずれかを設定することにより、 除去することができます。
以下のトピックは、管理者が上記の分布統計を理解し、 使用することについてのものです。
N を N>=1 の定数とすると、 列内の N 個の最大頻出値 は、 頻度 (重複の数) が最高のデータ値、 2 番目に頻度の高いデータ値、 そして、N 番目に頻度の高いデータ値に至るまでのデータ値によって構成されるものです。 対応する頻出値統計 は、 それらの"N"個のデータ値と、 列内のそれらの値の頻度とで構成されるものです。
列の K 変位値 とは、さまざまなデータ値のうち、 データ値がそれ以下である行が"K"個以上あるような最小のデータ値 V のことです。 K 変位値は、データ値の昇順により列内の行を分類することで計算できます。 K 変位値は、その分類された列の K 番目の行にあるデータ値です。
たとえば、ある列のデータが次のようであるとします。
C1 -- B E Y B F G E A J K E L
この列を分類すると、次のようになります。
C1' -- A B B E E E F G J K L Y
列 C1 の中には 9 種類の異なるデータ値が存在しています。 N = 2 の場合、頻出値統計は次のようになります。
SEQNO COLVALUE VALCOUNT ----- --------- -------- 1 E 3 2 B 2
収集される変位数が 5 の場合 (列変位数の数 (num_quantiles)を参照)、 K = 1、3、6、9、および 12 のときのこの列の K 変位数は、 次のようになります。
SEQNO COLVALUE VALCOUNT ----- --------- -------- 1 A 1 2 B 3 3 E 6 4 J 9 5 Y 12
この例では、分類後の列の 6 番目の行のデータ値が E なので、 6 変位値は E ということになります (また元の列でデータ値が E 以下の行は 6 行ある、 ということです)。
変位値が共通の値の場合、同じ変位値が複数生じることがあります。 ある 1 つの値について 2 つの変位数のうちの最大値が保管されます。 この 2 つの変位数のうち 1 番目のものには COLCOUNT があり、 これは厳密に COLVALUE 未満の行数になります。 一方、2 番目のものは COLVALUE 以下の行数になります。
所定の表に関して分布統計を維持すべきかどうかを判断するには、 次の 2 つの要因を考慮する必要があります。
分布統計は、ホスト変数を使用しない動的 SQL および静的 SQL で最も便利です。 ホスト変数と一緒に SQL を使用すると、 最適化プログラムは分布統計を限定された方法で使用することになります。
表内の少なくとも 1 つの列に、かなり 「不均一」なデータ分布があり、 その列が下記のような等号述部または範囲述部に頻繁に現れる場合、 分布統計を維持することをお勧めします。
WHERE C1 = KEY; WHERE C1 IN (KEY1, KEY2, KEY3); WHERE (C1 = KEY1) OR (C1 = KEY2) OR (C1 = KEY3); WHERE C1 <= KEY; WHERE C1 BETWEEN KEY1 AND KEY2;
データ分布における不均一性には、次の 2 種類がありますが、 これらは一緒に発生する可能性があります。
C1 ----- 0.0 5.1 6.3 7.1 8.2 8.4 8.5 9.1 93.6 100.0
このタイプの不均一がある場合は、変位値を維持するのが便利です。
以下の例は、列の不均一性が高いかどうかを調べるための照会です。
SELECT C1, COUNT(*) AS OCCURRENCES FROM T1 GROUP BY C1 ORDER BY OCCURRENCES DESC;
データ値 頻度 ---------- --------- 20 5 30 10 40 10 50 25 60 25 70 20 80 5
このタイプの不均一がある場合は、 変位値と頻出値の両方を維持するのが便利です。
分布統計は、RUNSTATS コマンドで WITH DISTRIBUTION 文節を使用するか、 または RUNSTATS API を呼び出すときに statsopt パラメーターに D、E、 あるいは A を指定することによって収集します。 アプリケーション・プログラミング・インターフェースについて詳しくは、 管理 API 解説書 を参照してください。
列分布統計をたくさん保持するなら、 最適化プログラムによるアクセス・プランの選択は改善されるかもしれませんが、 それらの統計を収集し照会をコンパイルするためのコストも大きくなってしまいます。 統計ヒープのサイズ (統計ヒープ・サイズ (stat_heap_sz)を参照) により、計算し保管できる統計の数が制限される場合があります。
分布統計が要求されると、 データベース・マネージャーは、1 つの列に関して省略時値として 10 個の最頻出値を保管します。 ほとんどの場合、 10 〜 100 個の頻出値で十分です。 頻出値の頻度とそれ以外の値の頻度が互いにほぼ等しいか、 または頻出値以外の値の頻度が最頻出値の頻度に比べて無視できる程度になるよう、 頻出値統計を維持するのが理想です。
収集する頻出値の数を設定するには、 num_freqvalues 構成パラメーターを使います (頻度の高い値の保存数 (num_freqvalues)を参照)。 データベース・マネージャーはこの頻出値統計の数より小さい数を収集することがあります。 その理由は、複数個あるデータ値に限りこの統計は収集されるからです。 変位値統計だけを収集する場合は、このパラメーターをゼロに設定できます。
分布統計が要求されるデータベース・マネージャーは、 1 つの列に関して省略時値として 20 個の変位値を保管します。 この値では、最大見積エラーは、 不等号範囲述部 (>、>=、<、または <=) に関しては約 2.5%、 BETWEEN 述部では 5% が保証されます。 変位値の数を決めるときの経験則は、次のとおりです。
たとえば、変位値を 25 にすると、BETWEEN 述部の場合の見積エラーは最大で 4%、 ">" 述部の場合の見積エラーは最大で 2% ということになります。 一般に、最低 10 個の変位値を保持するようにします。 50 以上の変位値が必要になるのは、極端に不均一なデータの場合です。
変位値の数を設定するには、 num_quantiles 構成パラメーターを使います (列変位数の数 (num_quantiles)を参照)。 頻出値統計だけを収集する場合は、このパラメーターをゼロに設定できます。 このパラメーターを「1」に設定すると、値の範囲が全部 1 つの変位数に収まるので、 この場合も変位数統計は収集されません。
なぜ分布統計を収集し、保管するのでしょうか。 それは、最適化プログラムが、 コストが最低のアクセス・プランを選択するために、 列の中で等号述部または範囲述部を満たす行の数を見積もる必要があるためです。 見積もりが正確になるほど、 最適化プログラムが最適のアクセス・プランを選択する可能性が大きくなります。 たとえば、次の照会を考えてみます。
SELECT C1, C2 FROM TABLE1 WHERE C1 = 'NEW YORK' AND C2 <= 10
C1 に索引が 1 つ、C2 に索引 が 1 つあるとします。 この場合に可能なアクセス・プランの一つとしては、 C1 の索引を使用して C1 = 'NEW YORK' の行をすべて検索してから、 取り出された行ごとに C2 <= 10 かどうかを調べるというものが考えられます。 別の計画としては、 C2 の索引を使用して C2 <= 10 の行をすべて検索してから、 取り出された行ごとに C1 = 'NEW YORK' であるかどうか調べる、 という方法があります。 一般に、こうした照会を実行するときの主なコストは、行の検索に要するコストなので、 最小限の数の検索で済むプランを選択することが望ましくなります。 最善のプランを選択するには、各述部を満たす行の数を見積もることが必要です。
分布統計を要求しないなら、最適化プログラムは、 ある列について、2 番目に高いデータ値 (HIGH2KEY)、2 番目に低いデータ値 (LOW2KEY)、 値の種類の数 (COLCARD)、および行数 (CARD) だけを維持します。 これにより、等号または範囲の述部を満たす行の数は、 列内の各データ値の頻度はすべて等しく、 データ値が区間 (LOW2KEY、HIGH2KEY) にわたって均等に分布する、 という仮定の下に見積もられます。 具体的には、等号述部 C1 = KEY を満たす行の数は、 CARD/COLCARD として見積もられ、 また範囲述部 C1 BETWEEN KEY1 AND KEY2 を満たす行の数は、 次のように見積もられます。
KEY2 - KEY1 ------------------- x CARD (1) HIGH2KEY - LOW2KEY
以上の見積もりが正確な見積もりとなるのは、 列内のデータ値の真の分布が、十分に均一である場合だけです。 使用できる分布統計がなく、データ値の頻度が相互に大きく異なっているか、 またはデータ値が幅の狭い区間 (LOW_KEY、HIGH_KEY) の中に クラスター化されている場合は、見積もりはけた違いのものになり、 最適化プログラムが最適でないアクセス・プランを選択する可能性があります。
分布統計が使用できるときは、 等価述部を満たす行数を計算するのに頻出値統計を使用し、 範囲述部を満たす行数を計算するのに頻出値統計と変位数とを使用することによって、 前述のエラーを大幅に小さくすることができます。
等価述部への影響の例:
まず、C1 = KEY の形式の述部を考えます。 KEY が、N 最大頻出値のいずれかである場合、 最適化プログラムは単に、カタログ内に保管されている KEY の頻度を使用します。 KEY が N 最大頻出値のどれでもない場合、最適化プログラムは、 (COLCARD - N) 個の非頻出値が均一に分布しているという仮定の下に、 述部を満たす行の数を見積もります。 つまり、行の数は、次のように見積もられます。
CARD - NUM_FREQ_ROWS -------------------- (2) COLCARD - N
NUM_FREQ_ROWS は N 最大頻出値のいずれかと値の等しい行の合計数です。
たとえば、ある列 (C) のデータ値の頻度が以下のようになっているとします。
データ値 頻度 ---------- --------- 1 2 2 3 3 40 4 4 5 1
最頻出値 (つまり N = 1) にのみ基づいた頻出値統計が使用可能であるとします。 この列の場合、CARD = 50 および COLCARD = 5 です。 述部 C = 3 の場合、ちょうど 40 個の行がそれを満たしています。 データ分布が均一であると仮定すると、 述部を満たす行の数は 50/5 = 10 と見積もられ、エラーは -75% になります。 頻出値統計を使用すると、行の数は 40 と見積もられ、エラーなしになります。
同様に、述部 C = 1 を満たす行は 2 行あります。 頻出値統計を使用しないと、述部を満たす行の数は 10 で 400% のエラーと見積もられます。 以下の式を使って、見積エラーを (パーセント比率で) 計算できます。
見積もられた行数 - 実際の行数 ----------------------------- X 100 実際の行数
頻出値統計 (N = 1) を使用すると、 最適化プログラムは、たとえば以下のように前述の式 (2) を使用して、 この値の行の数を見積もります。
(50 - 40) --------- = 3 (5 - 1)
また、エラー率は、次のように 1 桁減ります。
3 - 2 ------- = 50% 2
範囲述部を満たす行の数は、 変位値を使用して見積もることができます。 以下の例でこれを示します。 次のような列 (C) があるとします。
C ------- 0.0 5.1 6.3 7.1 8.2 8.4 8.5 9.1 93.6 100.0
K 変位値は、K = 1、4、7、および 10 のものが使用可能であるとします。
K K-quantile --- ---------- 1 0.0 4 7.1 7 8.5 10 100.0
まず最初に述部 C <= 8.5 について考えます。 前述のデータでは、正確には 7 つの行がこの述部を満たしています。 データ分布が均一であると仮定し、 前述の式 (1) で KEY1 を LOW2KEY に置き換えると、 述部を満たす行の数は、次のように見積もられます。
8.5 - 5.1 ---------- x 10 *= 0 93.6 - 5.1
*= は 「ほぼ等しい」という意味です。 この見積もりのエラーは、約 -100% です。
変位値を使用する場合は、まず K 変位値の 1 つである 8.5 を見つけて、 それに対応する K の値 7 を見積もりとして使用することによって、 同じ述部 (C <= 8.5) を満たす行の数が見積もられます。 この場合、エラーは 0 になります。
次に、述部 C <= 10 について考えます。 正確には 8 行がこの述部を満たしています。 前述の例とは異なり、値 10 は、保管された K 変位値のどれでもありません。 データ分布が均一であると仮定し、式 (1) を使用すると、 述部を満たす行の数は 1 と見積もられ、エラーは -86% になります。
変位値を使用する場合は、 最適化プログラムは述部を満たす行の数を r_1 + r_2 と見積もります。 ここで、r_1 は、述部 C <= 8.5 を満たす行の数、 r_2 は、述部 C > 8.5 かつ C <= 10 を満たす行の数です。 前述の例のとおり、r_1 = 7 です。 r_2 を見積もるため、最適化プログラムは線形補完を使用します。
100.0 - 10.0 r_2 *= ------------ x (> 8.5 かつ <= 100.0 を満たす行の数) 100.0 - 8.5 100.0 - 10.0 = ----------- x (10 - 7) 100.0 - 8.5 *= 3
最終的な見積もりは、r_1 + r_2 *= 10 であり、 エラーの絶対値は 3 分の 1 以下になります。
前述の例で変位値を使うと見積もりの正確さが増したのは、 実際のデータ値は範囲 5〜10 でクラスター化しているのに、 標準の見積式ではそのデータ値が 0〜100 の間で均一に分布していると想定されているためです。
このほかにも、変位値を使うと、 データ値ごとの頻度の差が非常に大きい場合に正確さを向上させることができます。 ある列のデータ値の頻度が次のようになっているものとします。
データ値 頻度 ---------- --------- 20 5 30 5 40 15 50 50 60 15 70 5 80 5
K 変位値は、K = 5、25、75、95、および 100 のものが使用可能であるとします。
K K 変位値 ---- ---------- 5 20 25 40 75 50 95 70 100 80
さらに、3 個の最頻出値に基づく頻出値統計が使用可能であるとします。
述部 C BETWEEN 20 AND 30 を考えてみましょう。 データ値の分布状況からは、 正確には 10 個の行がこの述部を満たしていることが分かります。 データ分布が均一であると仮定し、 式 (1) を使うと、述部を満たす行の数は次のように見積もられます。
30 - 20 ------- x 100 = 25 70 - 30
エラーは 150% です。
頻出値統計と変位値を使用すると、 述部を満たす行の数は r_1 + r_2 と見積もられます。 ここで、r_1 は述部 (C = 20) を満たす行数、 r_2 は述部 C > 20 AND C <= 30 を満たす行数となります。 式 (2) を使用すると、r_1 は次のように見積もられます。
100 - 80 -------- = 5 7 - 3
線形補完を使用すると、r_2 は次のように見積もられます。
30 - 20 ------- x (> 20 かつ <= 40 を満たす行の数) 40 - 20 30 - 20 = ------- x (25 - 5) 40 - 20 = 10,
最終見積もりは 15 になり、エラーは 3 分の 1 になりました。