23

1億行のMySQL5.0MyISAMテーブルがあり、2つの整数列に1つのインデックス(主キー以外)があるとします。

確かにBツリー構造についての理解が不十分であるため、カーディナリティが低いほど、親ノードが少ないため、インデックスのストレージ効率が向上すると思います。カーディナリティが高いと、ストレージの効率は低下しますが、読み取りパフォーマンスは向上します。これは、クエリの行を絞り込むために、探しているデータに到達するために、より少ないブランチをナビゲートする必要があるためです。

(注-「低」と「高」とは、たとえば1億行のテーブルの場合は100万対9900万という意味ではありません。つまり、9千万対9500万のようになります)

私の理解は正しいですか?

関連する質問-カーディナリティは書き込みパフォーマンスにどのように影響しますか?

4

1 に答える 1

34

カーディナリティが高いと、ストレージの効率は低下しますが、読み取りパフォーマンスは向上します。これは、クエリの行を絞り込むために、探しているデータに到達するために、より少ないブランチをナビゲートする必要があるためです。

定義上、読み取るレコードが少ないため、カーディナリティが高いほど、読み取りパフォーマンスが向上します。

このようなクエリを処理するには:

SELECT  *
FROM    mytable
WHERE   indexed_col = @myvalue

、エンジンは次の手順を実行する必要があります。

  1. 条件を満たす最初のエントリを見つけます。

    これはB-Tree、ルートエントリから開始して、をトラバースして実行されます。

    ページ全体で、検索は次のB-Treeリンクによって実行されます。ページ内では、検索はバイナリ検索を使用して実行されます(キーが圧縮されている場合を除きます。圧縮されている場合は、線形検索です)。

    このアルゴリズムは、カーディナリティの高い列とカーディナリティの低い列の両方で同じ効率です。これらのリストで3(いずれかではなく)最初のものを見つける:3

    1  2  3  4  5  6  7  8  9  10
    
    3  3  3  3  3  3  3  3  4  4
    

    同じO(log(n))手順が必要です。

  2. キー値が変更されるまでインデックスをトラバースします。もちろん、これには線形時間が必要です。レコードが多いほど、トラバースする必要があります。

最初のレコードのみが必要な場合:

SELECT  *
FROM    mytable
WHERE   indexed_col = @myvalue
LIMIT 1

、列のカーディナリティは読み取りパフォーマンスに影響しません。

カーディナリティは書き込みパフォーマンスにどのように影響しますか?

各インデックスキーには、レコードポインタという隠された追加の値があります。これがインデックスを持つことの全体的なポイントです。どのレコードを指しているのかを知る必要があります。

レコードポインタは定義上一意であるため、各インデックスキーも一意です。同じキー値を共有するインデックスエントリは、レコードポインタによって並べ替えられます。

これは、インデックスを保守しやすくするためです。他の何百万ものレコードと共有されているインデックス付き列の値を持つレコードを削除する場合は、対応するインデックスレコードも削除する必要があります。しかし、100万のインデックスレコード全体が調べられていません。代わりに、レコードポインタが追加の検索条件として使用されます。

各インデックスキーは実際には一意であり(インデックスを一意として定義していなくても)、したがって、可能な限り最大のカーディナリティを持ちます。

したがって、質問に対する答えは次のとおりです。いいえ、列のカーディナリティはインデックスの書き込みパフォーマンスに影響しません。

于 2010-04-08T10:15:30.580 に答える