SlideShare a Scribd company logo
1 of 29
Download to read offline
SQL Serverのインデックス設計
インデックス設計の基本的な考え方
山田公次
2018/6/12
/28
自己紹介
山田 公次(Yamada Koji)
• 名古屋在住の C#per
• 現在は .NET 系のソフト開発に携わっています
• 約10年ほどフリーランスで活動していた時期もあ
り、青色申告のスキルも得ています(^^)
• これまで、金融やインフラ系、不動産業界などの
様々なシステム開発に携わり、SQL Serverや
OracleなどでDBのスキルを育ててきました
2
@hamu502
/28
目的と対象者
本資料の目的
• 以下のような方が、「何となく」ではなく、論拠
を持ってインデックス設計できること。
• テーブルの正規化は分かるが、インデック
スの理解度が低いと感じている方
• テーブル設計はできるが、インデックス設計に
自信がない方
3
/28
アジェンダ
4
1.インデックスの概要
2.インデックスの種類
3.インデックスの設計基準
1.
インデックスの概要
5
/28
1.インデックスの概要
6
インデックスとは、DBデータの検索を高速に行うための索引のようなもの
インデックスを使うと、テーブルのすべての行を検索せずに目的のデータを特定す
ることができる便利なしくみ
• SQL ServerのインデックスはB-Tree構造で実現されている
参考:MS TechNet 「インデックスの基礎」
(https://technet.microsoft.com/ja-jp/library/ms190457(v=sql.105).aspx)
ルートノード
中間ノード
リーフノード
・・・
・・・・・・・・・・・
B-Tree構造のイメージ
/28
1.インデックスの概要
7
インデックスが存在しない場合
• 2018年3月計上のデータを検索する際、実テーブルの先頭から検索する
処理を行う(Table Scan)
受注ID 計上年月 受注日 顧客ID 担当ID 金額 ・・・
1 2017/4 2017/4/3 10 5 ・・・ ・・・
2 2017/4 2017/4/3 2 7 ・・・ ・・・
3 2017/4 2017/4/3 10 7 ・・・ ・・・
・・・
5000 2017/10 2017/9/30 10 5 ・・・ ・・・
5001 2017/10 2017/10/2 2 13 ・・・ ・・・
・・・
10001 2018/3 2018/3/1 10 13 ・・・ ・・・
10002 2018/3 2018/3/1 8 7 ・・・ ・・・
・・・
10123 2018/5 2018/5/30 2 7 ・・・ ・・・
実テーブル(ヒープ)
Table Scan
テーブルスキャンのイメージ 実テーブルの先頭から最後まで順番に
探し続けるため、検索が遅い
/28
1.インデックスの概要
8
インデックスが存在する場合
• 2018年3月計上のデータを検索する場合、インデックを検索し実テーブル
の場所を特定してから実データにアクセスする処理を行う(Index Seek)
受注ID 計上年月 受注日 ・・・
1 2017/4 2017/4/3 ・・・
2 2017/4 2017/4/3 ・・・
3 2017/4 2017/4/3 ・・・
・・・
5000 2017/9 2017/9/30 ・・・
5001 2017/10 2017/10/2 ・・・
・・・
10001 2018/3 2018/3/1 ・・・
10002 2018/3 2018/3/1 ・・・
・・・
計上年月
2017/4
2017/5
2017/6
計上年月
2017/4~6
2017/7~9
・・・
2018/1~3
計上年月
2018/1
2018/2
2018/3
計上年月 データ行への
ポインタ(RID)
2017/4 ●
2017/4 ●
2017/4 ●
・・・
計上年月 データ行への
ポインタ(RID)
2018/3 ●
2018/3 ●
・・・
ルートノード
中間ノード
リーフノード 実テーブル(ヒープ)
「計上年月」をキーとしたインデックスをSeekするイメージ
…
…
テーブルスキャンと異なり、実テーブルの
先頭から最後まで検索する処理を省け
るため、検索が速い
Index Seek
RID Lookup
2.
インデックスの種類
9
/28
2.インデックスの種類
10
SQL Server での主要なインデックスの種類
• クラスタ化インデックス
• リーフノードがデータ行となるB-Tree構造のインデックス
• テーブルのデータ行を、インデックスに設定したキー値に基づいて並べ替えて格納
• 1テーブルに1つのみ設定可能
• 非クラスタ化インデックス
• データ行とは独立したB-Tree構造のインデックス
• クラスター化インデックスが設定されたテーブル、またはヒープ上に定義
• 1テーブルに複数設定可能
• 付加列インデックス
• キー列に加えて非キー列を付加できるように拡張した非クラスター化インデックス
インデックスの目的による分類
• 一意インデックス
• キーの値が重複することがなく、テーブル行を一意に特定するインデックス
• 複合インデックス
• 複数のキー値を指定したインデックス
• 検索条件や取得列をインデックスのみで賄う目的で作成した複合インデックスを「カバーリ
ングインデックス」と言う
/28
2.インデックスの種類 - クラスタ化インデックス
11
クラスタ化インデックスを一意インデックスで設定した場合の動作
「受注ID」をキーとしたクラスタ化インデックスのイメージ
受注ID 計上年月 受注日 顧客ID 担当ID 金額 ・・・
1 2017/4 2017/4/3 10 5 ・・・ ・・・
2 2017/4 2017/4/3 2 7 ・・・ ・・・
3 2017/4 2017/4/3 10 7 ・・・ ・・・
・・・
受注ID 計上年月 受注日 顧客ID 担当ID 金額 ・・・
10001 2018/3 2018/3/1 10 13 ・・・ ・・・
10002 2018/3 2018/3/1 8 7 ・・・ ・・・
・・・
受注ID
1~10
10~20
・・・
受注ID
1~100
101~200
・・・
10001~
10100
受注ID
10001~
10010
10011~
10020
・・・
ルートノード
中間ノード
リーフノード(データ行)
…
……
受注ID=10002
・リーフノード自体がデータ行
・キーの順序で格納
(1/2)
/28
2.インデックスの種類 - クラスタ化インデックス
12
クラスタ化インデックスを複合インデックスで設定した場合の動作
「受注日」「顧客ID」をキーとしたクラスタ化インデックスのイメージ
受注日 顧客ID
2017/4/1
~6/30
1~10
2017/4/1
~6/30
11~20
・・・
2018/1/1~
3/31
1~10
2018/1/1~
3/31
11~20
・・・
ルートノード
…
受注ID 計上年月 受注日 顧客ID ・・・
2 2017/4 2017/4/3 2 ・・・
1 2017/4 2017/4/3 10 ・・・
3 2017/4 2017/4/3 10 ・・・
・・・
受注日 顧客ID
2017/4/3 1~10
2017/4/3 11~20
・・・
中間ノード
受注日 顧客ID
2018/3/1 1~10
2018/3/1 11~20
・・・
受注ID 計上年月 受注日 顧客ID ・・・
10008 2018/3 2018/3/1 2 ・・・
10002 2018/3 2018/3/1 8 ・・・
10005 2018/3 2018/3/1 8 ・・・
10001 2018/3 2018/3/1 10 ・・・
・・・
…
リーフノード(データ行)
受注日=2018/3/1
顧客ID=8
複数のキーも
設定可能
インデックスの先頭のキー(受注日)が条件に
含まれていないと、テーブルスキャンと似た動
作となる(Clustered Index Scan)
顧客ID=10
(2/2)
/28
2.インデックスの種類 - 非クラスタ化インデックス
13
ヒープのテーブルに非クラスタ化インデックスを設定した場合の動作
「計上年月」をキーとした非クラスタ化インデックスのイメージ
受注ID 計上年月 受注日 ・・・
1 2017/4 2017/4/3 ・・・
2 2017/4 2017/4/3 ・・・
3 2017/4 2017/4/3 ・・・
・・・
5000 2017/9 2017/9/30 ・・・
5001 2017/10 2017/10/2 ・・・
・・・
10001 2018/3 2018/3/1 ・・・
10002 2018/3 2018/3/1 ・・・
・・・
10022 2018/4 2018/4/2 ・・・
・・・
計上年月
2017/4
2017/5
2017/6
計上年月
2017/4~6
2017/7~9
・・・
2018/1~3
計上年月
2018/1
2018/2
2018/3
計上年月 データ行への
ポインタ(RID)
2017/4 ●
2017/4 ●
2017/4 ●
・・・ ●
計上年月 データ行への
ポインタ(RID)
2018/3 ●
2018/3 ●
・・・ ●
ルートノード
中間ノード
リーフノード 実テーブル(ヒープ)
…
…
計上年月=2018/3
データ行とは独立したB-Tree構造の
ため、複数のインデックスを設定可能
(1/3)
/28
2.インデックスの種類 - 非クラスタ化インデックス
14
クラスタ化インデックスに非クラスタ化インデックスを設定した場合の動作
「計上年月」をキーとした非クラスタ化インデックスのイメージ
受注ID 計上年月 受注日 ・・・
1 2017/4 2017/4/3 ・・・
2 2017/4 2017/4/3 ・・・
3 2017/4 2017/4/3 ・・・
・・・
計上年月
2017/4
2017/5
2017/6
計上年月
2017/4~6
2017/7~9
・・・
2018/1~3
計上年月
2018/1
2018/2
2018/3
計上年月 受注ID
2017/4 1
2017/4 2
2017/4 3
・・・
計上年月 受注ID
2018/3 10001
2018/3 10002
・・・
ルートノード
中間ノード
リーフノード
クラスタ化インデックス(受注IDがキー)
…
……
ルートノード
中間ノード
中間ノード
計上年月=2018/3
受注ID 計上年月 受注日 ・・・
10001 2018/3 2018/3/1 ・・・
10002 2018/3 2018/3/1 ・・・
・・・
10022 2018/4 2018/4/2 ・・・
・・・データ行へのポインタ(RID)ではなく、
クラスタ化インデックスのキーの値が格
納される
(2/3)
/28
2.インデックスの種類 - 非クラスタ化インデックス
15
「計上年月」「担当ID」をキーとしたカバーリングインデックスのイメージ
受注ID 計上年月 担当ID ・・・
1 2017/4 5 ・・・
2 2017/4 7 ・・・
3 2017/4 7 ・・・
・・・
16 2017/4 5 ・・・
・・・
カバーリングインデックスとしての非クラスタ化インデックスの動作
• 取得や条件に必要な列がインデックスのキーのみの場合、実テーブルを参照せずに
検索結果を返すため、I/Oコストが低く、検索パフォーマンスが良くなる。
• ただし、インデックスに指定するキーが多くなる傾向があるため、更新パフォーマンス劣
化のリスクを踏まえ、付加列インデックスとの比較検討を推奨。
実テーブル(ヒープ)
・・・
・・・
・・・
・・・
計上年月 担当ID
2017/4~6 1~10
2017/7~9 1~10
・・・
計上年月 担当ID RID
・・・ ●
2017/4 5 ●
2017/4 5 ●
・・・ ●
中間ノード
リーフノード
計上年月=2017/4
担当ID=5
ルートノード
実テーブルは参照
しない
実テーブルを参照せずにインデックス
のみで検索結果を返す
(3/3)
/28
2.インデックスの種類 - 付加列インデックス
16
付加列インデックスを設定した場合の動作
• インデックスのキーとは別の列の値を、インデックスのキーとは別に付加列とし
てリーフノードに保持する。
• 取得する列がインデックスのキーと付加列のみ、かつ、条件に必要な列がインデックス
のキーのみの場合、 実テーブルを参照せずに検索結果を返すため、I/Oコストが低く、
検索パフォーマンスが良くなる。
「計上年月」をキー、金額を付加列とした付加列インデックスのイメージ
受注ID 計上年月 金額 ・・・
1 2017/4 ・・・ ・・・
2 2017/4 ・・・ ・・・
3 2017/4 ・・・ ・・・
・・・
16 2017/4 ・・・ ・・・
・・・
実テーブル(ヒープ)
・・・
・・・
・・・
・・・
計上年月
2017/4~6
2017/7~9
・・・
計上年月 金額(付加列) RID
・・・ ●
2017/4 ・・・ ●
2017/4 ・・・ ●
・・・ ●
中間ノード
リーフノード
SUM(金額)
計上年月=2017/4
ルートノード
実テーブルは参照
しない
実テーブルを参照せずにインデックス
のみで検索結果を返す
付加列はリーフノードのみ
存在する
(1/2)
/28
2.インデックスの種類 - 付加列インデックス
17
付加列インデックス vs カバーリングインデックス
• SQL Serverのデータストレージの基本単位はページであり、カバーリングインデックス
で2つ目以降へ指定した列データは、正確には、ルートノードと中間ノードのページに
も格納する。また、付加列インデックスの付加列データはリーフノードのページのみに
格納する。
• よって、付加列インデックスのサイズはカバーリングインデックスより小さくなり、インデック
ス使用時のI/Oコスト減少が見込まれる。また、付加列に指定した列データの更新
ではリーフノードの付加列のみ更新することなり、更新パフォーマンスも優れる。
計上年月 担当ID
2017/4 5
・・・ ・・・
計上年月 担当ID RID
2017/4 5 ●
2017/4 7 ●
・・・ ●
中間ノードのページ リーフノードのページ
ルートノードのページ
(2/2)
カバーリングインデックスの正確な内部構造
計上年月 担当ID
2017/4 5
2017/4 7
・・・ ・・・
計上年月
2017/4
・・・
中間ノードのページ リーフノードのページ
ルートノードのページ
付加列インデックスの正確な内部構造
計上年月
2017/4
2017/4
・・・
計上年月 担当ID
(付加列)
RID
2017/4 5 ●
2017/4 7 ●
・・・ ●
「担当ID」の更新時、
各ノードの更新が発生
「担当ID」の更新時、
リーフノードの付加列
の値のみ更新が発生
3.
インデックスの設計基準
18
/28
3.インデックスの設計基準 - インデックス全般
インデックス全般の設計ポイント
• 安易に主キーをクラスタ化インデックスにしたり、WHERE句に使われる列を
単純に非クラスタ化インデックスにしない。
• インデックスの基準は「選択度」
• 選択度が高い場合は非クラスタ化インデックスを、低い場合はカバリングインデックスや付
加列インデックスを作成する。
• 選択度が低く、最も重要なデータの順番をクラスタ化インデックスとする。
※参考:YET ANOTHER BRAIN「SQL Serverのインデックス設計基準」
(http://takumayokoo.blogspot.com/2011/02/sql-server_26.html)
「選択度」「必要とする列」を大雑把に分類した場合に、どのインデックスが向いているかのイメージ
クラスタ化インデックス向き
…
データ全体を
100分割する
ようなキー
列のほぼすべてを必要とするクエリ
カバーリングor付加列インデックス向き…
データ全体を
100分割する
ようなキー
列の一部を必要とするクエリ
通常の非クラスタ化インデックス向き
…
10000行データを
完全一意に分割
するキー
列のほぼすべてを必要とするクエリ
選択度
必要とする列
(1/3)
19
「選択度」・・・カーディナリティ度とも言い、列の値のレコード数に
対する度合い(多い・少ない)のこと。例えば、市民データでは、
性別や血液型は選択度が低く、身長や体重は選択度が高い。
/28
3.インデックスの設計基準 - インデックス全般
Microsoftのガイドラインで重要な点(1/2)
• テーブル内のデータが変更された場合にインデックスをすべて調整するため、
INSERT、UPDATE、DELETE、および MERGE のパフォーマンスに影響
することを考慮する。
• 頻繁に更新するテーブルにはインデックスを設定しすぎないようにし、インデックスの幅を狭
く、つまり列数を可能な限り少なくする。
• 更新の必要が少なく、容量の大きいテーブルの場合、クエリのパフォーマンスを向上させる
にはインデックスを多数使用する。
• 小さなテーブルではインデックスを作成しない方がよい場合もある。
• クエリの種類とクエリ内での列の使用方法を評価する。
• 完全一致検索クエリで使用される列は、非クラスター化インデックス、または、クラスター化
インデックスにする適切な候補になる。
※参考:MS TechNet「インデックスの設計の全般的なガイドライン」
(https://technet.microsoft.com/ja-jp/library/ms191195(v=sql.105).aspx)
(2/3)
20
/28
3.インデックスの設計基準 - インデックス全般
Microsoftのガイドラインで重要な点(2/2)
• 列内のデータの分布を調べる
• インデックスを設定した列にほとんど一意の値がない場合や、このような列を結合する場合、
クエリに時間がかかることがよくある。
• インデックスに複数の列が含まれる場合は、列の順序を考慮する。
• 等しい (=)、より大きい (>)、より小さい (<)、BETWEEN などの検索条件の
WHERE 句で使用されるか、結合に含まれる列は、先頭に配置します。その他の列は、
差異の程度、つまり最も差異の大きいものから最も差異の小さいものの順に配置する。
※参考:MS TechNet「インデックスの設計の全般的なガイドライン」
(https://technet.microsoft.com/ja-jp/library/ms191195(v=sql.105).aspx)
(3/3)
21
/28
3.インデックスの設計基準 - クラスタ化インデックス
クラスタ化インデックスの設計ポイント
• データが物理的にかたまっていてほしい単位を表す列をキーとする。
• 「日付」「顧客」「商品カテゴリ」など、全ての仕様を考慮して、最重要なデータの順番をク
ラスタ化インデックスにすべき。
• 安易にテーブルの主キーをクラスタ化インデックスのキーにしない。
• 主キーはサロゲートキーであることも多く、主キーを範囲検索で使うことは、殆ど(もしくは
全く)無い。
• 主キーでクラスタ化インデックスを設定してしまうと、範囲検索に殆ど使われないにもかかわ
らず、データが主キーの順番で並ぶことになり、範囲検索ではパフォーマンスが悪くなる。
• SQL Serverのデフォルトでは、主キーでクラスタ化インデックスを設定するため、仕様理
解が深まったタイミングなどで、再検討することを推奨。
※参考:YET ANOTHER BRAIN「SQL Serverのインデックス設計基準」
(http://takumayokoo.blogspot.com/2011/02/sql-server_26.html)
(1/3)
22
/28
3.インデックスの設計基準 - クラスタ化インデックス
Microsoftのガイドラインで重要な点(1/2)
• ほとんどの場合、各テーブルには、次の条件を満たす単一または複数の列に
基づいて定義されたクラスタ化インデックスを作成することを推奨。
• 頻繁に使用されるクエリに使用可能。
• 一意性が高い。
• 範囲クエリで使用可能。
• データがどのようにアクセスされるかを理解し、次の処理を行うクエリには、クラ
スタ化インデックスを使用することを検討する。
• BETWEEN、>、>=、<、および <= などの演算子を使用して、ある範囲の値を返す。
• 大きな結果セットを返す。
• JOIN 句を使用する。通常、これらは外部キー列になる。
• ORDER BY 句または GROUP BY 句を使用する。
※参考:MS TechNet「クラスタ化インデックスの設計ガイドライン」
(https://technet.microsoft.com/ja-jp/library/ms190639(v=sql.105).aspx)
(2/3)
23
/28
3.インデックスの設計基準 - クラスタ化インデックス
Microsoftのガイドラインで重要な点(2/2)
• キーの定義に使用する列はできるだけ少なくする必要があるため、次の 1 つ
以上の条件を満たす列を使用する。
• 一意な値または多数の異なる値を含む。
• 順次アクセスされる。
• テーブル内で一意であることが確実なため、IDENTITY として定義されている。
• テーブルから取得したデータの並べ替えに頻繁に使用される。
※参考:MS TechNet「クラスタ化インデックスの設計ガイドライン」
(https://technet.microsoft.com/ja-jp/library/ms190639(v=sql.105).aspx)
(3/3)
24
/28
3.インデックスの設計基準 - 非クラスタ化インデックス
非クラスタ化インデックスの設計ポイント
• 安易に非クラスタ化インデックスを作成しない。
• 選択度(Selectivity)が低い列をキーにすると、インデックスで絞り込んだ結果のデータ
行が多くなり、場合によっては、インデックスを経由するよりテーブルスキャンの方が速くなる。
• カバーリングインデックス、付加列インデックスを使い分ける。
• 取得する列と条件に必要な列のみで範囲検索できる、かつ、更新頻度が低い場合は、カ
バーリングインデックスを検討する。
• 条件に必要な列のみで範囲検索できる、かつ、更新頻度が低い場合は、条件に必要な
列をキー、取得する列を付加列とした付加列インデックスを検討する。
※参考:YET ANOTHER BRAIN「SQL Serverのインデックス設計基準」
(http://takumayokoo.blogspot.com/2011/02/sql-server_26.html)
(1/3)
25
/28
3.インデックスの設計基準 - 非クラスタ化インデックス
Microsoftのガイドラインで重要な点(1/2)
• クエリの述語や結合条件で頻繁に使用される列に対して非クラスター化イン
デックスを作成する。
• ただし、不要な列を追加しないようにする。
• インデックス列を追加しすぎると、必要なディスク領域が増え、インデックスのメンテナンスの
パフォーマンスも低下する可能性がある。
• インデックスの列数はできる限り抑える。
• 更新の必要が少なく、容量の大きいデータベースまたはテーブルの場合、ク
エリのパフォーマンスを向上させるには非クラスター化インデックスを多数作成
するのが適している。
• 適切に定義されたデータのサブセットに対してフィルター選択されたインデックスを作成する
ことを検討
• テーブルの更新頻度が高いOLTPアプリケーションでは、インデックスを過度に
作成することは勧めない。
※参考:MS TechNet「非クラスタ化インデックスの設計ガイドライン」
(https://technet.microsoft.com/ja-jp/library/ms179325(v=sql.105).aspx)
(2/3)
26
/28
3.インデックスの設計基準 - 非クラスタ化インデックス
Microsoftのガイドラインで重要な点(2/2)
• データがどのようにアクセスされるかを理解し、次に示す特徴があるクエリには
非クラスター化インデックスを使用することを検討する。
• JOIN 句または GROUP BY 句を使用している。
• 大きな結果セットを返さないクエリ。
• 完全一致を返すクエリの検索条件 (WHERE 句など) に頻繁に使用される列を含んで
いる。
• 次に示す特徴に 1 つ以上該当する列を考慮する。
• クエリを包括している。
• 姓と名の組み合わせなど、多数の異なる値が格納されている。(他の列にクラスター化イン
デックスが使用されている場合)
※参考:MS TechNet「非クラスタ化インデックスの設計ガイドライン」
(https://technet.microsoft.com/ja-jp/library/ms179325(v=sql.105).aspx)
(3/3)
27
/28
3.インデックスの設計基準 - 実際に有効か確認する
28
実際には、各テーブルのデータ量やテーブル内のキーの値の偏りなどDBの統計
情報により、SQL Server のオプティマイザがインデックスの使用有無を含む
「実行計画」を作成し、DBにアクセスします。
よって、想定するデータ量や値の偏りのあるテストデータを用いて、使用するクエ
リの「実行計画」を取得し、設計したインデックスが有効に機能するか確認する
ことが大切です。
以下のサイトを参考に「実行計画」を取得し、作成したインデックスが「Index
Seek」で使われることを確認し、インデックスが使われなかったり、 「Index
Seek」で使われなかった場合はクエリやインデックスを見直してください。
• Markus Winand氏「開発者のためのSQLパフォーマンスの全て」内の
「実行計画」 - 「 SQL Server」
• https://use-the-index-luke.com/ja/sql/explain-plan/sql-server
ご清聴ありがとうございました

More Related Content

What's hot

Twitterのsnowflakeについて
TwitterのsnowflakeについてTwitterのsnowflakeについて
Twitterのsnowflakeについて
moai kids
 
NW遅延環境(Paas)でのPostgreSQLの利用について
NW遅延環境(Paas)でのPostgreSQLの利用についてNW遅延環境(Paas)でのPostgreSQLの利用について
NW遅延環境(Paas)でのPostgreSQLの利用について
kawarasho
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
増田 亨
 

What's hot (20)

SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
Twitterのsnowflakeについて
TwitterのsnowflakeについてTwitterのsnowflakeについて
Twitterのsnowflakeについて
 
トランザクションスクリプトのすすめ
トランザクションスクリプトのすすめトランザクションスクリプトのすすめ
トランザクションスクリプトのすすめ
 
NW遅延環境(Paas)でのPostgreSQLの利用について
NW遅延環境(Paas)でのPostgreSQLの利用についてNW遅延環境(Paas)でのPostgreSQLの利用について
NW遅延環境(Paas)でのPostgreSQLの利用について
 
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
CEDEC2019 大規模モバイルゲーム運用におけるマスタデータ管理事例
 
異次元のグラフデータベースNeo4j
異次元のグラフデータベースNeo4j異次元のグラフデータベースNeo4j
異次元のグラフデータベースNeo4j
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターン
 
データモデリング・テクニック
データモデリング・テクニックデータモデリング・テクニック
データモデリング・テクニック
 
TLS, HTTP/2演習
TLS, HTTP/2演習TLS, HTTP/2演習
TLS, HTTP/2演習
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
実践!Elasticsearch + Sudachi を用いた全文検索エンジン
実践!Elasticsearch + Sudachi を用いた全文検索エンジン実践!Elasticsearch + Sudachi を用いた全文検索エンジン
実践!Elasticsearch + Sudachi を用いた全文検索エンジン
 
データ分析を支える技術 DWH再入門
データ分析を支える技術 DWH再入門データ分析を支える技術 DWH再入門
データ分析を支える技術 DWH再入門
 
DiI/DIコンテナを一から学んでみた
DiI/DIコンテナを一から学んでみたDiI/DIコンテナを一から学んでみた
DiI/DIコンテナを一から学んでみた
 
SQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するかSQL大量発行処理をいかにして高速化するか
SQL大量発行処理をいかにして高速化するか
 
組織にテストを書く文化を根付かせる戦略と戦術
組織にテストを書く文化を根付かせる戦略と戦術組織にテストを書く文化を根付かせる戦略と戦術
組織にテストを書く文化を根付かせる戦略と戦術
 
PlaySQLAlchemy: SQLAlchemy入門
PlaySQLAlchemy: SQLAlchemy入門PlaySQLAlchemy: SQLAlchemy入門
PlaySQLAlchemy: SQLAlchemy入門
 
ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方ドメイン駆動設計のための Spring の上手な使い方
ドメイン駆動設計のための Spring の上手な使い方
 
Elasticsearch勉強会#44 20210624
Elasticsearch勉強会#44 20210624Elasticsearch勉強会#44 20210624
Elasticsearch勉強会#44 20210624
 
AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)
AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)
AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
SQL Server Performance Tuning Essentials
SQL Server Performance Tuning EssentialsSQL Server Performance Tuning Essentials
SQL Server Performance Tuning Essentials
 

Similar to SQL Server のインデックス設計

[B15] HiRDBのSQL実行プランはどのように決定しているのか?by Masaaki Narita
[B15] HiRDBのSQL実行プランはどのように決定しているのか?by Masaaki Narita[B15] HiRDBのSQL実行プランはどのように決定しているのか?by Masaaki Narita
[B15] HiRDBのSQL実行プランはどのように決定しているのか?by Masaaki Narita
Insight Technology, Inc.
 

Similar to SQL Server のインデックス設計 (20)

【2017年4月時点】Oracle Essbase 概要
【2017年4月時点】Oracle Essbase 概要【2017年4月時点】Oracle Essbase 概要
【2017年4月時点】Oracle Essbase 概要
 
Data Scientists Love SQL Server
Data Scientists Love SQL ServerData Scientists Love SQL Server
Data Scientists Love SQL Server
 
[B15] HiRDBのSQL実行プランはどのように決定しているのか?by Masaaki Narita
[B15] HiRDBのSQL実行プランはどのように決定しているのか?by Masaaki Narita[B15] HiRDBのSQL実行プランはどのように決定しているのか?by Masaaki Narita
[B15] HiRDBのSQL実行プランはどのように決定しているのか?by Masaaki Narita
 
AWS朝会2022/1 セッション① 数年間、レイクハウスを設計運用してみた
AWS朝会2022/1	セッション① 数年間、レイクハウスを設計運用してみたAWS朝会2022/1	セッション① 数年間、レイクハウスを設計運用してみた
AWS朝会2022/1 セッション① 数年間、レイクハウスを設計運用してみた
 
2023年はTiDBの時代!
2023年はTiDBの時代!2023年はTiDBの時代!
2023年はTiDBの時代!
 
ビッグデータIoT向けDB GridDBの紹介
ビッグデータIoT向けDB GridDBの紹介ビッグデータIoT向けDB GridDBの紹介
ビッグデータIoT向けDB GridDBの紹介
 
Redash・SQL勉強会 ~目指せクエリ女子~
Redash・SQL勉強会 ~目指せクエリ女子~ Redash・SQL勉強会 ~目指せクエリ女子~
Redash・SQL勉強会 ~目指せクエリ女子~
 
【ウェブ セミナー】AI / アナリティクスを支えるビッグデータ基盤 Azure Data Lake [概要編]
【ウェブ セミナー】AI / アナリティクスを支えるビッグデータ基盤 Azure Data Lake [概要編]【ウェブ セミナー】AI / アナリティクスを支えるビッグデータ基盤 Azure Data Lake [概要編]
【ウェブ セミナー】AI / アナリティクスを支えるビッグデータ基盤 Azure Data Lake [概要編]
 
TREASUREDATAのエコシステムで作るロバストなETLデータ処理基盤の作り方
TREASUREDATAのエコシステムで作るロバストなETLデータ処理基盤の作り方TREASUREDATAのエコシステムで作るロバストなETLデータ処理基盤の作り方
TREASUREDATAのエコシステムで作るロバストなETLデータ処理基盤の作り方
 
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
Rustで DDD を実践しながら API サーバーを実装・構築した(つもり)
 
データウェアハウスモデリング入門(ダイジェスト版)(事前公開版)
データウェアハウスモデリング入門(ダイジェスト版)(事前公開版) データウェアハウスモデリング入門(ダイジェスト版)(事前公開版)
データウェアハウスモデリング入門(ダイジェスト版)(事前公開版)
 
Logstashを愛して5年、370ページを超えるガチ本を書いてしまった男の話.
Logstashを愛して5年、370ページを超えるガチ本を書いてしまった男の話.Logstashを愛して5年、370ページを超えるガチ本を書いてしまった男の話.
Logstashを愛して5年、370ページを超えるガチ本を書いてしまった男の話.
 
オンプレ、クラウドを組み合わせて作るビックデータ基盤 データ基盤の選び方
オンプレ、クラウドを組み合わせて作るビックデータ基盤  データ基盤の選び方オンプレ、クラウドを組み合わせて作るビックデータ基盤  データ基盤の選び方
オンプレ、クラウドを組み合わせて作るビックデータ基盤 データ基盤の選び方
 
ビッグデータ活用を加速する!分散SQLエンジン Spark SQL のご紹介 20161105 OSC Tokyo Fall
ビッグデータ活用を加速する!分散SQLエンジン Spark SQL のご紹介 20161105 OSC Tokyo Fallビッグデータ活用を加速する!分散SQLエンジン Spark SQL のご紹介 20161105 OSC Tokyo Fall
ビッグデータ活用を加速する!分散SQLエンジン Spark SQL のご紹介 20161105 OSC Tokyo Fall
 
【de:code 2020】 Microsoft Teams の最新情報
【de:code 2020】 Microsoft Teams の最新情報【de:code 2020】 Microsoft Teams の最新情報
【de:code 2020】 Microsoft Teams の最新情報
 
【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜
【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜
【JJUG CCC 2016 Fall 公開版】ドメイン駆動設計とscala 〜既存プロジェクトへの適用〜
 
Snowflake Architecture and Performance(db tech showcase Tokyo 2018)
Snowflake Architecture and Performance(db tech showcase Tokyo 2018)Snowflake Architecture and Performance(db tech showcase Tokyo 2018)
Snowflake Architecture and Performance(db tech showcase Tokyo 2018)
 
SKYDISCのIoTを支えるテクノロジー
SKYDISCのIoTを支えるテクノロジーSKYDISCのIoTを支えるテクノロジー
SKYDISCのIoTを支えるテクノロジー
 
20170218 list format4bi
20170218 list format4bi20170218 list format4bi
20170218 list format4bi
 
201806 jawsug bgnr12
201806 jawsug bgnr12201806 jawsug bgnr12
201806 jawsug bgnr12
 

SQL Server のインデックス設計

  • 2. /28 自己紹介 山田 公次(Yamada Koji) • 名古屋在住の C#per • 現在は .NET 系のソフト開発に携わっています • 約10年ほどフリーランスで活動していた時期もあ り、青色申告のスキルも得ています(^^) • これまで、金融やインフラ系、不動産業界などの 様々なシステム開発に携わり、SQL Serverや OracleなどでDBのスキルを育ててきました 2 @hamu502
  • 7. /28 1.インデックスの概要 7 インデックスが存在しない場合 • 2018年3月計上のデータを検索する際、実テーブルの先頭から検索する 処理を行う(Table Scan) 受注ID 計上年月 受注日 顧客ID 担当ID 金額 ・・・ 1 2017/4 2017/4/3 10 5 ・・・ ・・・ 2 2017/4 2017/4/3 2 7 ・・・ ・・・ 3 2017/4 2017/4/3 10 7 ・・・ ・・・ ・・・ 5000 2017/10 2017/9/30 10 5 ・・・ ・・・ 5001 2017/10 2017/10/2 2 13 ・・・ ・・・ ・・・ 10001 2018/3 2018/3/1 10 13 ・・・ ・・・ 10002 2018/3 2018/3/1 8 7 ・・・ ・・・ ・・・ 10123 2018/5 2018/5/30 2 7 ・・・ ・・・ 実テーブル(ヒープ) Table Scan テーブルスキャンのイメージ 実テーブルの先頭から最後まで順番に 探し続けるため、検索が遅い
  • 8. /28 1.インデックスの概要 8 インデックスが存在する場合 • 2018年3月計上のデータを検索する場合、インデックを検索し実テーブル の場所を特定してから実データにアクセスする処理を行う(Index Seek) 受注ID 計上年月 受注日 ・・・ 1 2017/4 2017/4/3 ・・・ 2 2017/4 2017/4/3 ・・・ 3 2017/4 2017/4/3 ・・・ ・・・ 5000 2017/9 2017/9/30 ・・・ 5001 2017/10 2017/10/2 ・・・ ・・・ 10001 2018/3 2018/3/1 ・・・ 10002 2018/3 2018/3/1 ・・・ ・・・ 計上年月 2017/4 2017/5 2017/6 計上年月 2017/4~6 2017/7~9 ・・・ 2018/1~3 計上年月 2018/1 2018/2 2018/3 計上年月 データ行への ポインタ(RID) 2017/4 ● 2017/4 ● 2017/4 ● ・・・ 計上年月 データ行への ポインタ(RID) 2018/3 ● 2018/3 ● ・・・ ルートノード 中間ノード リーフノード 実テーブル(ヒープ) 「計上年月」をキーとしたインデックスをSeekするイメージ … … テーブルスキャンと異なり、実テーブルの 先頭から最後まで検索する処理を省け るため、検索が速い Index Seek RID Lookup
  • 10. /28 2.インデックスの種類 10 SQL Server での主要なインデックスの種類 • クラスタ化インデックス • リーフノードがデータ行となるB-Tree構造のインデックス • テーブルのデータ行を、インデックスに設定したキー値に基づいて並べ替えて格納 • 1テーブルに1つのみ設定可能 • 非クラスタ化インデックス • データ行とは独立したB-Tree構造のインデックス • クラスター化インデックスが設定されたテーブル、またはヒープ上に定義 • 1テーブルに複数設定可能 • 付加列インデックス • キー列に加えて非キー列を付加できるように拡張した非クラスター化インデックス インデックスの目的による分類 • 一意インデックス • キーの値が重複することがなく、テーブル行を一意に特定するインデックス • 複合インデックス • 複数のキー値を指定したインデックス • 検索条件や取得列をインデックスのみで賄う目的で作成した複合インデックスを「カバーリ ングインデックス」と言う
  • 11. /28 2.インデックスの種類 - クラスタ化インデックス 11 クラスタ化インデックスを一意インデックスで設定した場合の動作 「受注ID」をキーとしたクラスタ化インデックスのイメージ 受注ID 計上年月 受注日 顧客ID 担当ID 金額 ・・・ 1 2017/4 2017/4/3 10 5 ・・・ ・・・ 2 2017/4 2017/4/3 2 7 ・・・ ・・・ 3 2017/4 2017/4/3 10 7 ・・・ ・・・ ・・・ 受注ID 計上年月 受注日 顧客ID 担当ID 金額 ・・・ 10001 2018/3 2018/3/1 10 13 ・・・ ・・・ 10002 2018/3 2018/3/1 8 7 ・・・ ・・・ ・・・ 受注ID 1~10 10~20 ・・・ 受注ID 1~100 101~200 ・・・ 10001~ 10100 受注ID 10001~ 10010 10011~ 10020 ・・・ ルートノード 中間ノード リーフノード(データ行) … …… 受注ID=10002 ・リーフノード自体がデータ行 ・キーの順序で格納 (1/2)
  • 12. /28 2.インデックスの種類 - クラスタ化インデックス 12 クラスタ化インデックスを複合インデックスで設定した場合の動作 「受注日」「顧客ID」をキーとしたクラスタ化インデックスのイメージ 受注日 顧客ID 2017/4/1 ~6/30 1~10 2017/4/1 ~6/30 11~20 ・・・ 2018/1/1~ 3/31 1~10 2018/1/1~ 3/31 11~20 ・・・ ルートノード … 受注ID 計上年月 受注日 顧客ID ・・・ 2 2017/4 2017/4/3 2 ・・・ 1 2017/4 2017/4/3 10 ・・・ 3 2017/4 2017/4/3 10 ・・・ ・・・ 受注日 顧客ID 2017/4/3 1~10 2017/4/3 11~20 ・・・ 中間ノード 受注日 顧客ID 2018/3/1 1~10 2018/3/1 11~20 ・・・ 受注ID 計上年月 受注日 顧客ID ・・・ 10008 2018/3 2018/3/1 2 ・・・ 10002 2018/3 2018/3/1 8 ・・・ 10005 2018/3 2018/3/1 8 ・・・ 10001 2018/3 2018/3/1 10 ・・・ ・・・ … リーフノード(データ行) 受注日=2018/3/1 顧客ID=8 複数のキーも 設定可能 インデックスの先頭のキー(受注日)が条件に 含まれていないと、テーブルスキャンと似た動 作となる(Clustered Index Scan) 顧客ID=10 (2/2)
  • 13. /28 2.インデックスの種類 - 非クラスタ化インデックス 13 ヒープのテーブルに非クラスタ化インデックスを設定した場合の動作 「計上年月」をキーとした非クラスタ化インデックスのイメージ 受注ID 計上年月 受注日 ・・・ 1 2017/4 2017/4/3 ・・・ 2 2017/4 2017/4/3 ・・・ 3 2017/4 2017/4/3 ・・・ ・・・ 5000 2017/9 2017/9/30 ・・・ 5001 2017/10 2017/10/2 ・・・ ・・・ 10001 2018/3 2018/3/1 ・・・ 10002 2018/3 2018/3/1 ・・・ ・・・ 10022 2018/4 2018/4/2 ・・・ ・・・ 計上年月 2017/4 2017/5 2017/6 計上年月 2017/4~6 2017/7~9 ・・・ 2018/1~3 計上年月 2018/1 2018/2 2018/3 計上年月 データ行への ポインタ(RID) 2017/4 ● 2017/4 ● 2017/4 ● ・・・ ● 計上年月 データ行への ポインタ(RID) 2018/3 ● 2018/3 ● ・・・ ● ルートノード 中間ノード リーフノード 実テーブル(ヒープ) … … 計上年月=2018/3 データ行とは独立したB-Tree構造の ため、複数のインデックスを設定可能 (1/3)
  • 14. /28 2.インデックスの種類 - 非クラスタ化インデックス 14 クラスタ化インデックスに非クラスタ化インデックスを設定した場合の動作 「計上年月」をキーとした非クラスタ化インデックスのイメージ 受注ID 計上年月 受注日 ・・・ 1 2017/4 2017/4/3 ・・・ 2 2017/4 2017/4/3 ・・・ 3 2017/4 2017/4/3 ・・・ ・・・ 計上年月 2017/4 2017/5 2017/6 計上年月 2017/4~6 2017/7~9 ・・・ 2018/1~3 計上年月 2018/1 2018/2 2018/3 計上年月 受注ID 2017/4 1 2017/4 2 2017/4 3 ・・・ 計上年月 受注ID 2018/3 10001 2018/3 10002 ・・・ ルートノード 中間ノード リーフノード クラスタ化インデックス(受注IDがキー) … …… ルートノード 中間ノード 中間ノード 計上年月=2018/3 受注ID 計上年月 受注日 ・・・ 10001 2018/3 2018/3/1 ・・・ 10002 2018/3 2018/3/1 ・・・ ・・・ 10022 2018/4 2018/4/2 ・・・ ・・・データ行へのポインタ(RID)ではなく、 クラスタ化インデックスのキーの値が格 納される (2/3)
  • 15. /28 2.インデックスの種類 - 非クラスタ化インデックス 15 「計上年月」「担当ID」をキーとしたカバーリングインデックスのイメージ 受注ID 計上年月 担当ID ・・・ 1 2017/4 5 ・・・ 2 2017/4 7 ・・・ 3 2017/4 7 ・・・ ・・・ 16 2017/4 5 ・・・ ・・・ カバーリングインデックスとしての非クラスタ化インデックスの動作 • 取得や条件に必要な列がインデックスのキーのみの場合、実テーブルを参照せずに 検索結果を返すため、I/Oコストが低く、検索パフォーマンスが良くなる。 • ただし、インデックスに指定するキーが多くなる傾向があるため、更新パフォーマンス劣 化のリスクを踏まえ、付加列インデックスとの比較検討を推奨。 実テーブル(ヒープ) ・・・ ・・・ ・・・ ・・・ 計上年月 担当ID 2017/4~6 1~10 2017/7~9 1~10 ・・・ 計上年月 担当ID RID ・・・ ● 2017/4 5 ● 2017/4 5 ● ・・・ ● 中間ノード リーフノード 計上年月=2017/4 担当ID=5 ルートノード 実テーブルは参照 しない 実テーブルを参照せずにインデックス のみで検索結果を返す (3/3)
  • 16. /28 2.インデックスの種類 - 付加列インデックス 16 付加列インデックスを設定した場合の動作 • インデックスのキーとは別の列の値を、インデックスのキーとは別に付加列とし てリーフノードに保持する。 • 取得する列がインデックスのキーと付加列のみ、かつ、条件に必要な列がインデックス のキーのみの場合、 実テーブルを参照せずに検索結果を返すため、I/Oコストが低く、 検索パフォーマンスが良くなる。 「計上年月」をキー、金額を付加列とした付加列インデックスのイメージ 受注ID 計上年月 金額 ・・・ 1 2017/4 ・・・ ・・・ 2 2017/4 ・・・ ・・・ 3 2017/4 ・・・ ・・・ ・・・ 16 2017/4 ・・・ ・・・ ・・・ 実テーブル(ヒープ) ・・・ ・・・ ・・・ ・・・ 計上年月 2017/4~6 2017/7~9 ・・・ 計上年月 金額(付加列) RID ・・・ ● 2017/4 ・・・ ● 2017/4 ・・・ ● ・・・ ● 中間ノード リーフノード SUM(金額) 計上年月=2017/4 ルートノード 実テーブルは参照 しない 実テーブルを参照せずにインデックス のみで検索結果を返す 付加列はリーフノードのみ 存在する (1/2)
  • 17. /28 2.インデックスの種類 - 付加列インデックス 17 付加列インデックス vs カバーリングインデックス • SQL Serverのデータストレージの基本単位はページであり、カバーリングインデックス で2つ目以降へ指定した列データは、正確には、ルートノードと中間ノードのページに も格納する。また、付加列インデックスの付加列データはリーフノードのページのみに 格納する。 • よって、付加列インデックスのサイズはカバーリングインデックスより小さくなり、インデック ス使用時のI/Oコスト減少が見込まれる。また、付加列に指定した列データの更新 ではリーフノードの付加列のみ更新することなり、更新パフォーマンスも優れる。 計上年月 担当ID 2017/4 5 ・・・ ・・・ 計上年月 担当ID RID 2017/4 5 ● 2017/4 7 ● ・・・ ● 中間ノードのページ リーフノードのページ ルートノードのページ (2/2) カバーリングインデックスの正確な内部構造 計上年月 担当ID 2017/4 5 2017/4 7 ・・・ ・・・ 計上年月 2017/4 ・・・ 中間ノードのページ リーフノードのページ ルートノードのページ 付加列インデックスの正確な内部構造 計上年月 2017/4 2017/4 ・・・ 計上年月 担当ID (付加列) RID 2017/4 5 ● 2017/4 7 ● ・・・ ● 「担当ID」の更新時、 各ノードの更新が発生 「担当ID」の更新時、 リーフノードの付加列 の値のみ更新が発生
  • 19. /28 3.インデックスの設計基準 - インデックス全般 インデックス全般の設計ポイント • 安易に主キーをクラスタ化インデックスにしたり、WHERE句に使われる列を 単純に非クラスタ化インデックスにしない。 • インデックスの基準は「選択度」 • 選択度が高い場合は非クラスタ化インデックスを、低い場合はカバリングインデックスや付 加列インデックスを作成する。 • 選択度が低く、最も重要なデータの順番をクラスタ化インデックスとする。 ※参考:YET ANOTHER BRAIN「SQL Serverのインデックス設計基準」 (http://takumayokoo.blogspot.com/2011/02/sql-server_26.html) 「選択度」「必要とする列」を大雑把に分類した場合に、どのインデックスが向いているかのイメージ クラスタ化インデックス向き … データ全体を 100分割する ようなキー 列のほぼすべてを必要とするクエリ カバーリングor付加列インデックス向き… データ全体を 100分割する ようなキー 列の一部を必要とするクエリ 通常の非クラスタ化インデックス向き … 10000行データを 完全一意に分割 するキー 列のほぼすべてを必要とするクエリ 選択度 必要とする列 (1/3) 19 「選択度」・・・カーディナリティ度とも言い、列の値のレコード数に 対する度合い(多い・少ない)のこと。例えば、市民データでは、 性別や血液型は選択度が低く、身長や体重は選択度が高い。
  • 20. /28 3.インデックスの設計基準 - インデックス全般 Microsoftのガイドラインで重要な点(1/2) • テーブル内のデータが変更された場合にインデックスをすべて調整するため、 INSERT、UPDATE、DELETE、および MERGE のパフォーマンスに影響 することを考慮する。 • 頻繁に更新するテーブルにはインデックスを設定しすぎないようにし、インデックスの幅を狭 く、つまり列数を可能な限り少なくする。 • 更新の必要が少なく、容量の大きいテーブルの場合、クエリのパフォーマンスを向上させる にはインデックスを多数使用する。 • 小さなテーブルではインデックスを作成しない方がよい場合もある。 • クエリの種類とクエリ内での列の使用方法を評価する。 • 完全一致検索クエリで使用される列は、非クラスター化インデックス、または、クラスター化 インデックスにする適切な候補になる。 ※参考:MS TechNet「インデックスの設計の全般的なガイドライン」 (https://technet.microsoft.com/ja-jp/library/ms191195(v=sql.105).aspx) (2/3) 20
  • 21. /28 3.インデックスの設計基準 - インデックス全般 Microsoftのガイドラインで重要な点(2/2) • 列内のデータの分布を調べる • インデックスを設定した列にほとんど一意の値がない場合や、このような列を結合する場合、 クエリに時間がかかることがよくある。 • インデックスに複数の列が含まれる場合は、列の順序を考慮する。 • 等しい (=)、より大きい (>)、より小さい (<)、BETWEEN などの検索条件の WHERE 句で使用されるか、結合に含まれる列は、先頭に配置します。その他の列は、 差異の程度、つまり最も差異の大きいものから最も差異の小さいものの順に配置する。 ※参考:MS TechNet「インデックスの設計の全般的なガイドライン」 (https://technet.microsoft.com/ja-jp/library/ms191195(v=sql.105).aspx) (3/3) 21
  • 22. /28 3.インデックスの設計基準 - クラスタ化インデックス クラスタ化インデックスの設計ポイント • データが物理的にかたまっていてほしい単位を表す列をキーとする。 • 「日付」「顧客」「商品カテゴリ」など、全ての仕様を考慮して、最重要なデータの順番をク ラスタ化インデックスにすべき。 • 安易にテーブルの主キーをクラスタ化インデックスのキーにしない。 • 主キーはサロゲートキーであることも多く、主キーを範囲検索で使うことは、殆ど(もしくは 全く)無い。 • 主キーでクラスタ化インデックスを設定してしまうと、範囲検索に殆ど使われないにもかかわ らず、データが主キーの順番で並ぶことになり、範囲検索ではパフォーマンスが悪くなる。 • SQL Serverのデフォルトでは、主キーでクラスタ化インデックスを設定するため、仕様理 解が深まったタイミングなどで、再検討することを推奨。 ※参考:YET ANOTHER BRAIN「SQL Serverのインデックス設計基準」 (http://takumayokoo.blogspot.com/2011/02/sql-server_26.html) (1/3) 22
  • 23. /28 3.インデックスの設計基準 - クラスタ化インデックス Microsoftのガイドラインで重要な点(1/2) • ほとんどの場合、各テーブルには、次の条件を満たす単一または複数の列に 基づいて定義されたクラスタ化インデックスを作成することを推奨。 • 頻繁に使用されるクエリに使用可能。 • 一意性が高い。 • 範囲クエリで使用可能。 • データがどのようにアクセスされるかを理解し、次の処理を行うクエリには、クラ スタ化インデックスを使用することを検討する。 • BETWEEN、>、>=、<、および <= などの演算子を使用して、ある範囲の値を返す。 • 大きな結果セットを返す。 • JOIN 句を使用する。通常、これらは外部キー列になる。 • ORDER BY 句または GROUP BY 句を使用する。 ※参考:MS TechNet「クラスタ化インデックスの設計ガイドライン」 (https://technet.microsoft.com/ja-jp/library/ms190639(v=sql.105).aspx) (2/3) 23
  • 24. /28 3.インデックスの設計基準 - クラスタ化インデックス Microsoftのガイドラインで重要な点(2/2) • キーの定義に使用する列はできるだけ少なくする必要があるため、次の 1 つ 以上の条件を満たす列を使用する。 • 一意な値または多数の異なる値を含む。 • 順次アクセスされる。 • テーブル内で一意であることが確実なため、IDENTITY として定義されている。 • テーブルから取得したデータの並べ替えに頻繁に使用される。 ※参考:MS TechNet「クラスタ化インデックスの設計ガイドライン」 (https://technet.microsoft.com/ja-jp/library/ms190639(v=sql.105).aspx) (3/3) 24
  • 25. /28 3.インデックスの設計基準 - 非クラスタ化インデックス 非クラスタ化インデックスの設計ポイント • 安易に非クラスタ化インデックスを作成しない。 • 選択度(Selectivity)が低い列をキーにすると、インデックスで絞り込んだ結果のデータ 行が多くなり、場合によっては、インデックスを経由するよりテーブルスキャンの方が速くなる。 • カバーリングインデックス、付加列インデックスを使い分ける。 • 取得する列と条件に必要な列のみで範囲検索できる、かつ、更新頻度が低い場合は、カ バーリングインデックスを検討する。 • 条件に必要な列のみで範囲検索できる、かつ、更新頻度が低い場合は、条件に必要な 列をキー、取得する列を付加列とした付加列インデックスを検討する。 ※参考:YET ANOTHER BRAIN「SQL Serverのインデックス設計基準」 (http://takumayokoo.blogspot.com/2011/02/sql-server_26.html) (1/3) 25
  • 26. /28 3.インデックスの設計基準 - 非クラスタ化インデックス Microsoftのガイドラインで重要な点(1/2) • クエリの述語や結合条件で頻繁に使用される列に対して非クラスター化イン デックスを作成する。 • ただし、不要な列を追加しないようにする。 • インデックス列を追加しすぎると、必要なディスク領域が増え、インデックスのメンテナンスの パフォーマンスも低下する可能性がある。 • インデックスの列数はできる限り抑える。 • 更新の必要が少なく、容量の大きいデータベースまたはテーブルの場合、ク エリのパフォーマンスを向上させるには非クラスター化インデックスを多数作成 するのが適している。 • 適切に定義されたデータのサブセットに対してフィルター選択されたインデックスを作成する ことを検討 • テーブルの更新頻度が高いOLTPアプリケーションでは、インデックスを過度に 作成することは勧めない。 ※参考:MS TechNet「非クラスタ化インデックスの設計ガイドライン」 (https://technet.microsoft.com/ja-jp/library/ms179325(v=sql.105).aspx) (2/3) 26
  • 27. /28 3.インデックスの設計基準 - 非クラスタ化インデックス Microsoftのガイドラインで重要な点(2/2) • データがどのようにアクセスされるかを理解し、次に示す特徴があるクエリには 非クラスター化インデックスを使用することを検討する。 • JOIN 句または GROUP BY 句を使用している。 • 大きな結果セットを返さないクエリ。 • 完全一致を返すクエリの検索条件 (WHERE 句など) に頻繁に使用される列を含んで いる。 • 次に示す特徴に 1 つ以上該当する列を考慮する。 • クエリを包括している。 • 姓と名の組み合わせなど、多数の異なる値が格納されている。(他の列にクラスター化イン デックスが使用されている場合) ※参考:MS TechNet「非クラスタ化インデックスの設計ガイドライン」 (https://technet.microsoft.com/ja-jp/library/ms179325(v=sql.105).aspx) (3/3) 27
  • 28. /28 3.インデックスの設計基準 - 実際に有効か確認する 28 実際には、各テーブルのデータ量やテーブル内のキーの値の偏りなどDBの統計 情報により、SQL Server のオプティマイザがインデックスの使用有無を含む 「実行計画」を作成し、DBにアクセスします。 よって、想定するデータ量や値の偏りのあるテストデータを用いて、使用するクエ リの「実行計画」を取得し、設計したインデックスが有効に機能するか確認する ことが大切です。 以下のサイトを参考に「実行計画」を取得し、作成したインデックスが「Index Seek」で使われることを確認し、インデックスが使われなかったり、 「Index Seek」で使われなかった場合はクエリやインデックスを見直してください。 • Markus Winand氏「開発者のためのSQLパフォーマンスの全て」内の 「実行計画」 - 「 SQL Server」 • https://use-the-index-luke.com/ja/sql/explain-plan/sql-server