カーディナリティとは?意味・高低の見分け方とインデックス設計を実装目線で解説
カーディナリティとは、データベースの列(カラム)に含まれる一意な値の数を指す指標です。性別のように取りうる値が「男・女」しかない列はカーディナリティが低く、社員番号やメールアドレスのように行ごとに値が異なる列はカーディナリティが高いと表現します。この数の大小が、インデックスの効き方・クエリの速度・実行計画の選択を左右する。本記事では、カーディナリティの意味と高低の見分け方、選択性(selectivity)との関係、インデックスを張るべき列の判断基準、MySQLでの確認方法、統計情報のズレが招く遅延までを、設計と運用の現場で使える粒度で整理します。
目次
まとめ:カーディナリティは列の一意値の数と索引効果を決める指標
カーディナリティは「その列に何種類の値があるか」を表します。全行が同じ値なら1、全行が異なる値なら行数と同じになり、後者ほど高カーディナリティです。判断の軸は一つです。値の種類が多いほど、その列で絞り込んだときに残る行が少なく、インデックスで一気に対象を狭められる。
設計時の結論を先に置きます。高カーディナリティの列(ID・注文番号・メール等)はインデックスが効き、単独索引の第一候補になる。低カーディナリティの列(フラグ・区分・都道府県等)は単独索引だと絞り込みが弱く、多くの行を読むため効果が出にくいか、複合インデックスの後方に置く形が向きます。以降の章で、選択性の計算、複合インデックスの列順、MySQLでの実測、統計情報のズレへの対処を順に示します。
カーディナリティの定義と高低の見分け方をデータベース設計目線で整理
まず言葉の意味と、現場で列を見たときの高低判定の勘所を押さえます。カーディナリティは統計・データモデリング・SQLで少しずつ使われ方が異なるため、ここではDBインデックスの文脈に絞って定義する。
カーディナリティの意味と列に含まれる一意な値の数という考え方
DBインデックスの文脈でのカーディナリティは、対象列に存在する重複を除いた値の個数です。SQLでは SELECT COUNT(DISTINCT col) FROM t; の結果がその列のカーディナリティにあたります。1万行のテーブルで gender 列の COUNT(DISTINCT) が2なら、そのカーディナリティは2。同じ1万行でも email 列が全行ユニークなら、カーディナリティは1万になります。行数に対して一意値がどれだけ多いかが、この指標の本質です。
高カーディナリティと低カーディナリティの具体例と見分け方の目安
高いか低いかは、行数に対する一意値の比で捉えると迷いません。同じ「都道府県」でも47種類は、数百件のマスタなら比較的高め、数百万件の履歴テーブルなら極端に低い、というように母数で相対的に変わる。代表的な列の目安を挙げます。
| 列の例 | 一意な値の数の傾向 | 高低の位置づけ | 索引の効きやすさ |
|---|---|---|---|
| 主キー(id・注文番号) | 行数と一致(全ユニーク) | 最高カーディナリティ | 非常に効く |
| メールアドレス・電話番号 | ほぼ全ユニーク | 高カーディナリティ | 効く |
| 市区町村・カテゴリ | 数十〜数千種類 | 中カーディナリティ | 母数次第 |
| 都道府県・ステータス区分 | 数十種類以下 | 低カーディナリティ | 効きにくい |
| 性別・有効フラグ | 2〜3種類 | 最低カーディナリティ | 単独では効かない |
この一覧で押さえるべきは、絶対値ではなく比率だという点です。ステータスが3種類でも、その1つに全体の99%が偏っていれば、残り1%を指す値だけは実質的に高い絞り込み力を持ちます。値の種類数と分布の偏りを合わせて見るのが実務の勘所になります。
選択性selectivityとカーディナリティの計算式と評価の目安
カーディナリティを行数で正規化した指標が選択性です。選択性は COUNT(DISTINCT col) を COUNT(*) で割った値で求め、0より大きく1以下になります。全ユニークな主キーは選択性1.0、性別のような列は1万行なら0.0002という具合になる。1に近いほど1つの値で残る行が少なく、インデックスで効率よく絞り込めます。
実務では選択性0.1前後を一つの目安に置きます。ある値を指定したとき対象が全体の10%程度まで絞れるなら、多くのDBでインデックス経由の読み取りが全表走査より有利になる。逆に1つの値が全体の3割以上を占める列は、その値を指定してもインデックスをたどるより全行読みのほうが速いとオプティマイザが判断しがちで、索引が使われないこともあります。
インデックス設計においてカーディナリティが果たす役割と列の選び方
ここからは設計判断です。どの列に、どの順で索引を置くかを、カーディナリティを軸に決めていく。SQLやクエリの前提を確認したい場合は、クエリの実行の仕組みと高速化を扱った記事もあわせて参照してください。
高カーディナリティ列にインデックスが効く仕組みとB-treeの動き
B-treeインデックスは、指定した値を木構造でたどって該当行の位置へ到達します。高カーディナリティの列では、1つの値に対応する行がごく少数のため、木をたどった後に読む行がほぼ絞り切れている。主キー検索が一瞬で返るのはこのためです。WHERE句やJOINキー、頻繁に等値検索する列が高カーディナリティなら、単独インデックスの第一候補になります。
低カーディナリティ列に単独インデックスが向かない理由と代替策
有効フラグのような2値の列に単独でインデックスを張ると、木をたどっても「有効な行が全体の半分」といった大量の候補が残ります。DBはその大量の位置情報から実データを1件ずつ取りに行くより、テーブルを順に読んだほうが速いと判断し、せっかくの索引を使わないことがある。低カーディナリティ列は単独索引の効果が出にくく、ディスク容量と書き込みコストだけが増える結果になりがちです。代替策は、後述する高カーディナリティ列との複合インデックスに組み込む形です。
複合インデックスの列順とカーディナリティの関係と並べ方の原則
複数列をまとめた複合インデックスでは、列の並び順が効き目を決めます。基本は等値で絞り込む列を先頭に置き、その中で選択性の高い列を前に寄せる。低カーディナリティ列を先頭にすると入口で候補が絞れず、後続の列の索引をたどる範囲が広がってしまうためです。
- WHERE句で等値指定する列を先頭に置く。
- 先頭候補が複数あるなら、選択性が高い(カーディナリティが高い)列を前へ。
- 範囲検索(>・BETWEEN等)する列は後方に置き、範囲より後の列は索引が効かない前提で並べる。
ただし低カーディナリティ列でも、高カーディナリティ列と組み合わせた複合インデックスの一部としてなら価値が出ます。「有効フラグが真、かつユーザーIDが指定値」のような検索では、フラグとIDを複合にすることで対象を一気に絞れる。単独では効かない列も、組み合わせ方で意味が変わります。
MySQLでカーディナリティを確認する方法とSHOW INDEXの読み方
MySQLは各インデックスの推定カーディナリティを保持しており、SHOW INDEX FROM t; の Cardinality 列で確認できます。information_schema.STATISTICS を参照しても同じ値を取得できる。この値はオプティマイザが実行計画を組む際の根拠になります。実際の環境ごとの挙動は、MySQLの特徴とバージョン選定を扱った記事で前提を確認したうえで検証すると把握しやすくなります。
ここで表示される Cardinality はサンプリングに基づく推定値で、実際の COUNT(DISTINCT) とは一致しないことがあります。推定値であるという性質が、次章の統計情報のズレという運用課題につながる。
統計情報とオプティマイザによるカーディナリティ推定と遅延対策
インデックスを正しく設計しても、DBが持つ統計情報が古いと索引が使われないことがあります。設計と同じくらい、統計情報の鮮度が速度を左右する。
オプティマイザが実行計画を決める仕組みと推定行数の見積もり方
クエリを受け取ったDBは、どの索引を使い、どの順でテーブルを結合するかを、統計情報から推定したカーディナリティをもとに決めます。この推定行数が実態に近ければ、DBは全表走査と索引走査を正しく選び分ける。実行計画は EXPLAIN で確認でき、推定された行数(rows)と実際の行数がどれだけ離れているかが、統計情報の健全性を測る手がかりになります。
統計情報のズレが招く遅延とANALYZE TABLEによる更新対処
大量のデータを一括投入した直後や、特定の値だけが急増したテーブルでは、DBが持つカーディナリティの推定が実態から外れます。実際は数十万行返るクエリを「数十行しか返らない」と誤推定すると、DBは本来向かない索引を選び、結果として遅くなる。ここが実運用で最も多い落とし穴です。対処は統計情報の更新にあります。MySQLやPostgreSQLでは ANALYZE TABLE t; で推定を取り直せます。大規模なバッチ投入やマスタ入れ替えの後に統計更新を組み込んでおくと、推定のズレによる急な遅延を避けられる。既存システムでクエリ遅延の原因が索引設計か統計情報か切り分けきれない場合は、DBの性能改善を含む保守運用・内製化支援のように、実行計画の調査から対処までを外部と分担する選択肢もあります。
インデックスを張るか見送るかをカーディナリティで判断する基準
ここは独自の判断章です。カーディナリティを見て索引を「張る・見送る」をどう決めるか、条件付きで言い切ります。
インデックスを採用してよい条件とカーディナリティでの見極め方
次の条件が揃う列は、索引を張る価値があります。WHERE句・JOIN・ORDER BYで頻繁に使われ、選択性が概ね0.1以上(1つの値で全体の1割以下まで絞れる)で、書き込み頻度が読み取りに比べて過大でないことです。読み取りが主体のマスタ参照系テーブルでは、この条件を満たす列に積極的に索引を置く。索引は検索を速くする一方で、行の挿入・更新のたびに索引側も書き換えるコストを生むため、更新が激しい列では効果と代償を天秤にかけます。
インデックスを見送るべき場面と全列に索引を張る際の失敗パターン
逆に、索引を張らない判断が正解になる場面を明示します。第一に、値が2〜3種類しかない低カーディナリティ列への単独索引は見送る。絞り込みが弱く容量と書き込みコストだけが増えるためで、必要なら高カーディナリティ列との複合インデックスに含める形にします。第二に、数百行規模の小さなテーブルは全表走査でも一瞬で終わるため、索引は過剰になる。第三に、秒間に大量の挿入が走るログ的なテーブルへ検索用の索引を増やしすぎると、書き込みが索引更新で詰まります。「とりあえず全列に索引」は、この3つのいずれかで裏目に出る典型的な失敗パターンです。張る前に、その列の選択性とテーブルの更新頻度を実測してから決めます。
データモデリングの多重度カーディナリティと索引指標としての違い
同じ「カーディナリティ」でも、ER図・データモデリングの文脈では意味が異なります。そこでのカーディナリティは、テーブル間の関連の多重度、つまり「1対1・1対多・多対多」といった対応関係の数を指す。本記事で扱った「列の一意な値の数」とは別概念です。設計フェーズで関連の多重度を表すカーディナリティを整理したい場合は、ER図の書き方とリレーション・多重度を扱った記事で確認してください。索引設計の指標としてのカーディナリティ(本記事)と、モデリング上の多重度としてのカーディナリティ(ER図)を混同しないことが、設計の会話を正確にします。
カーディナリティとインデックス設計に関するよくある質問と回答
設計・運用の現場で挙がりやすい疑問を、5つに絞って答えます。
カーディナリティが高いとはどういう状態ですか?
列に含まれる一意な値の数が、行数に対して多い状態です。全行がユニークな主キーはカーディナリティが最も高く、行数と同じ値になります。逆に性別のように2〜3種類しかない列は低カーディナリティです。高いほどその列での絞り込み力が強く、インデックスが効きやすくなります。
カーディナリティと選択性はどう違いますか?
カーディナリティは一意な値の「個数」そのもの、選択性はそれを行数で割った「比率」です。選択性は COUNT(DISTINCT col) を COUNT(*) で割った値で、0より大きく1以下になります。1に近いほど絞り込みが効く指標です。カーディナリティが同じ100でも、1万行なら選択性0.01、200行なら0.5と、母数によって効き目の評価が変わります。
低カーディナリティの列にはインデックスを張ってはいけませんか?
単独索引としては効きにくいため、原則として単独では張りません。ただし高カーディナリティの列と組み合わせた複合インデックスの構成要素としてなら価値が出ます。値の偏りが強く、めったに出ない値だけを検索するケースでは部分的に効くこともあるため、選択性と検索パターンを実測して判断します。
MySQLでカーディナリティを確認するにはどうすればよいですか?
SHOW INDEX FROM t; を実行し、結果の Cardinality 列を見ます。information_schema.STATISTICS でも同じ値を取得可能です。表示されるのはサンプリングに基づく推定値のため、実態とずれたときは ANALYZE TABLE t; で統計情報を更新してから確認します。
インデックスを追加したのにクエリが速くなりません。なぜですか?
いくつかの原因が考えられます。対象列の選択性が低く絞り込みが弱い、統計情報が古くオプティマイザが索引を選んでいない、WHERE句で関数や型変換をかけていて索引が使えない、複合インデックスの列順が検索条件と合っていない、などです。EXPLAIN で実行計画を確認し、索引が使われているか、推定行数が実態に近いかを順に切り分けます。
関連記事
- クエリとは?種類・実行の仕組みと高速化を実装目線で解説:カーディナリティが左右する実行計画とクエリ高速化の前提を押さえられます。
- MySQLとは?特徴とバージョン選定・採用判断を実装目線で解説:SHOW INDEXでカーディナリティを確認するMySQLそのものの基礎を確認できます。
- ER図とは?書き方・エンティティやリレーション・カーディナリティを実装目線で解説:関連の多重度を表すもう一つのカーディナリティを扱っています。
- SQLとは?文の種類と実行順序・RDBMS方言を実装目線で解説:COUNT(DISTINCT)など本記事で登場したSQL文の土台を確認できます。
- トランザクションとは?ACID・分離レベルを実装目線で解説:索引と並ぶDB設計の基礎として、更新整合の観点を補えます。