db tech showcase Tokyo 2017
JPOUG in 15 minutes (5/6)
インデックス・チューニング Deep Dive
2
今日話すこと
 SQLチューニングの肝は、やっぱりインデックス!
 インデックスの使い方をおさらいしてみる。
 目指すのは「 Index Only Scan 」
 あのDBではIndex Only Scanできるの?
 Oracle
 MySQL
 PostgreSQL
 MS SQL Server
3
インデックスについて再考する
会員番号 氏 名 性 別 住所コード
0010 佐藤 女 125
0204 高橋 男 001
0700 小林 男 010
住所コード 郵便番号 住 所
001 100-0000 東京都千代田区
002 100-0010 東京都新宿区
125 240-0005 神奈川県横浜市
データベース
住所テーブル
会員テーブル
(質問)以下のSELECT文で、インデックスが活用されるのは①~④のどれ?
SELECT 会員番号,住.住所コード,住所
FROM 会員 会
INNER JOIN 住所 住
ON 会.住所コード = 住.住所コード
WHERE 住所 LIKE ‘神奈川県%’
ORDER BY 氏名
SELECT文
1
2
3
4
①~④の全てでインデックスによる性能改善が可能!
4
データベース
WHERE句で用いられるインデックス
WHERE 住所 LIKE ‘神奈川県%’
• まずはおさらい、WHERE句の検索条件にはインデックスが必要。
id | Operation |テーブル
0 | SELECT |
1 | SORT ORDER BY |
2 | NESTED LOOP |
3 | ROWIDスキャン | 住所
4 | Index Range Scan | 住所
5 | フルスキャン | 会員
実行計画
SQL抜粋
会員番号 氏 名 性 別 住所コード
0010 佐藤 女 125
0204 高橋 男 001
0700 小林 男 010
住所コード 郵便番号 住 所
001 100-0000 東京都千代田区
002 100-0010 東京都新宿区
125 240-0005 神奈川県横浜市
住所テーブル
会員テーブル
WHEREの選択条件列に
インデックスを作成して
フルスキャンを回避、
性能を改善している。
3
5
データベース
結合とインデックス
会員番号 氏 名 性 別 住所コード
0010 佐藤 女 125
0204 高橋 男 001
0700 小林 男 010
住所コード 郵便番号 住 所
001 100-0000 東京都千代田区
002 100-0010 東京都新宿区
125 240-0005 神奈川県横浜市
住所テーブル
会員テーブル
INNER JOIN 住所 住
ON 会.住所コード = 住.住所コード
• Nested Loop時の結合キーにもインデックスが必要。
id | Operation |テーブル
0 | SELECT |
1 | SORT ORDER BY |
2 | NESTED LOOP |
3 | ROWIDスキャン | 住所
4 | Index Range Scan | 住所
5 | ROWIDスキャン | 会員
6 | Index Range Scan | 会員
結合キーにインデックスを
作成して、NL結合を高速化
実行計画
SQL抜粋
2
駆動表
内部表
6
会員番号 氏 名 性 別 住所コード
0010 佐藤 女 125
0204 高橋 男 001
0700 小林 男 010
住所コード 郵便番号 住 所
001 100-0000 東京都千代田区
002 100-0010 東京都新宿区
125 240-0005 神奈川県横浜市
データベース
住所テーブル
会員テーブル
並び替えとインデックス
• ORDER BYの並び替え列にも、インデックス作成で高速化。
ORDER BY 氏名
id | Operation |テーブル
0 | SELECT |
1 | NESTED LOOP |
2 | ROWIDスキャン | 住所
3 | Index Range Scan | 住所
4 | ROWIDスキャン | 会員
5 | Index Range Scan | 会員
4
SQL抜粋
実行計画
インデックス=ソート済、
並び替え処理を回避する
ソート済
未ソート
7
会員番号 氏 名 性 別 住所コード
0010 佐藤 女 125
0204 高橋 男 001
0700 小林 男 010
住所コード 郵便番号 住 所
001 100-0000 東京都千代田区
002 100-0010 東京都新宿区
125 240-0005 神奈川県横浜市
データベース
住所テーブル
会員テーブル
インデックスが全てを覆いつくす
• インデックス・チューニングの究極形は???
2
2 3
4
これまでのチューニングで、SELECT文中の殆どの列にインデックスが
作成されている。会員テーブルの会員番号だけ、インデックスは未作成。
SELECT 会員番号,住.住所コード,住所
FROM 会員 会
INNER JOIN 住所 住
ON 会.住所コード = 住.住所コード
WHERE 住所 LIKE ‘神奈川県%’
ORDER BY 氏名
SELECT文
1
2
3
4
8
複合インデックスを使ったIndex Only Scan
• テーブルアクセスせずに、インデックスだけでSELECTする。
このようなインデックスを
カバリング・インデックス
と呼ぶこともある。
会員番号:1200
氏名:小林~
会員番号 氏 名 性 別 住所コード
0010 佐藤 女 125
0700 小林 男 010
0204 高橋 男 001
0445 江川 女 001
会員番号:0700 会員番号:1000
氏名:田中~
住所コード:010
住所コード⇒氏名⇒会員番号
会員テーブル
データベース 複合インデックスで必要列を
全て取得し、テーブルへの
アクセスを省略できる。
= Index Only Scan
9
実行計画をシンプルにして性能改善!
• Index Only Scanを使ってチューニングした効果を検証する。
id | Operation |テーブル
0 | SELECT |
1 | SORT ORDER BY |
2 | NESTED LOOP |
3 | ROWIDスキャン | 住所
4 | Index Range Scan | 住所
5 | フルスキャン | 会員
id | Operation |テーブル
0 | SELECT |
1 | NESTED LOOP |
2 | Index Range Scan | 住所
3 | Index Range Scan | 会員
カバリング・インデックスを用いて
チューニングした例。コストが激減!
Cost=2,609 Cost=220before after
10
各DBMSでのIndex Only Scanサポート状況
• Index Only Scanをサポートする機能や、複合インデックスの制約などは
DBMSによって異なっている。
特徴的な機能 インデックス長、カラム数の制約
Oracle ・索引構成表をサポート 1ブロックの75%程度、32列まで
MySQL
(InnoDB)
・PKがクラスタ索引になる 3072バイト、各列は767バイト
PostgreSQL
・9.2からIndex Only Scanが可能
・テーブルにCLUSTER句を使える
2713バイト、32列まで
MS SQL Server
・PKのデフォルトがクラスタ索引
・INCLUDE句が使える
900バイト、16列まで
11
Oracleの索引構成表
住所コード 郵便番号 住 所
002 100-0010 東京都新宿区
001 100-0011 東京都千代田区
125 240-0005 神奈川県横浜市
テーブル
• 索引構成表とはレコードを保持するインデックスである。
住所コード:001
住所コード:003
住所コード:005
住所コード:005
インデックス
通常のテーブルとインデックス 索引構成表
テーブル(ヒープ)とインデックスは別のデータ構造。
インデックスはROWID、テーブルがレコードを保持。
住所コード:008
住所コード:001
住所コード:003
住所コード:005
住所コード:005
索引構成表
郵便番号 住 所
100-0001 東京都千代田区
郵便番号 住 所
100-0120 東京都墨田区
リーフ・ブロックにレコードが格納された形で、
常にインデックス経由のアクセスとなる。
住所コード:005
住所コード:008
住所コード:125
郵便番号 住 所
240-0005 神奈川県横浜
ROWID
12
MySQLのクラスタ化インデックス
• MySQL(InnoDB)ではPKがクラスタ化インデックスになる。
innodbのクラスタ化インデックス
住所コード:008
住所コード:001
住所コード:003
住所コード:005
住所コード:005
クラスタ化インデックス(PK)
郵便番号 住 所
100-0001 東京都千代田区
郵便番号 住 所
100-0120 東京都墨田区
クラスタ化インデックスは索引構成表と同じ構成で、
リーフ・ブロックにレコードを持つ。
住所コード:125
郵便番号 住 所
240-0005 神奈川県横浜
innodbのセカンダリインデックス
住所:北海道
住所:~千代田区
住所:東京都~
住所:滋賀県~
住所:奈良県
セカンダリインデックス
住所:宮崎県
二次インデックスではリーフ・ブロックに主キー値を持ち、
それからクラスタ化インデックスのレコードを検索する。
13
PostgreSQLのIndex Only Scan
• PostgreSQLは追記型DBのため、Index Only Scanの利用には制約あり。
PostgreSQLのインデックス構造
追記型DBという構造上、インデックススキャンだけでは
可視データが特定できず、Index Only Scanが難しい。
可視 住所コード 郵便番号 住 所
N 001 100-0010 東京都千代田区1
Y 001 100-0011 東京都千代田区2
Y 125 240-0005 神奈川県横浜市
テーブル
住所コード:001
住所コード:003
住所コード:005
住所コード:005
インデックス
住所コード:005
住所コード:008
PostgreSQLのIndex Only Scan利用条件
対象テーブルでVACUUMが行われていること。
更新が少ないテーブルにおいて、適切なタイミングで
AUTOVACUUMが行われることが運用上は必須。
14
MS SQL Serverのクラスタ索引
• SQL ServerではデフォルトでPKにクラスタ化インデックスが作成される。
• include句を使うことで付加列インデックスも作成できる。
クラスタ化インデックス(デフォルト)
住所コード:008
住所コード:001
住所コード:003
住所コード:005
住所コード:005
クラスタ化インデックス(PK)
郵便番号 住 所
100-0001 東京都千代田区
郵便番号 住 所
100-0120 東京都墨田区
MySQLと同様に、SQL Serverでもデフォルトでは
PKにクラスタ化インデックスが作成される。
住所コード:125
郵便番号 住 所
240-0005 神奈川県横浜
include句を使ったインデックス
住所:北海道
住所:~千代田区
住所:東京都~
住所:滋賀県~
住所:奈良県
付加列インデックス
住所:宮崎県
複合インデックスと異なり、中間ブロックに不要データを
含まないので、サイズを小さく出来る
郵便番号
100-0001
郵便番号
100-0120
郵便番号
240-0005
インデックスは
住所だけに
貼られているが、
郵便番号をリーフに保持する
まとめ
16
今日話したこと
 ここぞの処理では、Index Only Scanを使ってみよう!
 Oracleではこれにピッタリな索引構成表がある。
 PostgreSQLではIndex Only Scanにならないケースがあるので注意!
 MySQLやSQL Serverではクラスタ索引の特性を理解しよう!
 とはいえ、複合インデックスの濫造は考えもの。ご利用は計画的に!

20170907 dbtechshowcase index

  • 1.
    db tech showcaseTokyo 2017 JPOUG in 15 minutes (5/6) インデックス・チューニング Deep Dive
  • 2.
    2 今日話すこと  SQLチューニングの肝は、やっぱりインデックス!  インデックスの使い方をおさらいしてみる。 目指すのは「 Index Only Scan 」  あのDBではIndex Only Scanできるの?  Oracle  MySQL  PostgreSQL  MS SQL Server
  • 3.
    3 インデックスについて再考する 会員番号 氏 名性 別 住所コード 0010 佐藤 女 125 0204 高橋 男 001 0700 小林 男 010 住所コード 郵便番号 住 所 001 100-0000 東京都千代田区 002 100-0010 東京都新宿区 125 240-0005 神奈川県横浜市 データベース 住所テーブル 会員テーブル (質問)以下のSELECT文で、インデックスが活用されるのは①~④のどれ? SELECT 会員番号,住.住所コード,住所 FROM 会員 会 INNER JOIN 住所 住 ON 会.住所コード = 住.住所コード WHERE 住所 LIKE ‘神奈川県%’ ORDER BY 氏名 SELECT文 1 2 3 4 ①~④の全てでインデックスによる性能改善が可能!
  • 4.
    4 データベース WHERE句で用いられるインデックス WHERE 住所 LIKE‘神奈川県%’ • まずはおさらい、WHERE句の検索条件にはインデックスが必要。 id | Operation |テーブル 0 | SELECT | 1 | SORT ORDER BY | 2 | NESTED LOOP | 3 | ROWIDスキャン | 住所 4 | Index Range Scan | 住所 5 | フルスキャン | 会員 実行計画 SQL抜粋 会員番号 氏 名 性 別 住所コード 0010 佐藤 女 125 0204 高橋 男 001 0700 小林 男 010 住所コード 郵便番号 住 所 001 100-0000 東京都千代田区 002 100-0010 東京都新宿区 125 240-0005 神奈川県横浜市 住所テーブル 会員テーブル WHEREの選択条件列に インデックスを作成して フルスキャンを回避、 性能を改善している。 3
  • 5.
    5 データベース 結合とインデックス 会員番号 氏 名性 別 住所コード 0010 佐藤 女 125 0204 高橋 男 001 0700 小林 男 010 住所コード 郵便番号 住 所 001 100-0000 東京都千代田区 002 100-0010 東京都新宿区 125 240-0005 神奈川県横浜市 住所テーブル 会員テーブル INNER JOIN 住所 住 ON 会.住所コード = 住.住所コード • Nested Loop時の結合キーにもインデックスが必要。 id | Operation |テーブル 0 | SELECT | 1 | SORT ORDER BY | 2 | NESTED LOOP | 3 | ROWIDスキャン | 住所 4 | Index Range Scan | 住所 5 | ROWIDスキャン | 会員 6 | Index Range Scan | 会員 結合キーにインデックスを 作成して、NL結合を高速化 実行計画 SQL抜粋 2 駆動表 内部表
  • 6.
    6 会員番号 氏 名性 別 住所コード 0010 佐藤 女 125 0204 高橋 男 001 0700 小林 男 010 住所コード 郵便番号 住 所 001 100-0000 東京都千代田区 002 100-0010 東京都新宿区 125 240-0005 神奈川県横浜市 データベース 住所テーブル 会員テーブル 並び替えとインデックス • ORDER BYの並び替え列にも、インデックス作成で高速化。 ORDER BY 氏名 id | Operation |テーブル 0 | SELECT | 1 | NESTED LOOP | 2 | ROWIDスキャン | 住所 3 | Index Range Scan | 住所 4 | ROWIDスキャン | 会員 5 | Index Range Scan | 会員 4 SQL抜粋 実行計画 インデックス=ソート済、 並び替え処理を回避する ソート済 未ソート
  • 7.
    7 会員番号 氏 名性 別 住所コード 0010 佐藤 女 125 0204 高橋 男 001 0700 小林 男 010 住所コード 郵便番号 住 所 001 100-0000 東京都千代田区 002 100-0010 東京都新宿区 125 240-0005 神奈川県横浜市 データベース 住所テーブル 会員テーブル インデックスが全てを覆いつくす • インデックス・チューニングの究極形は??? 2 2 3 4 これまでのチューニングで、SELECT文中の殆どの列にインデックスが 作成されている。会員テーブルの会員番号だけ、インデックスは未作成。 SELECT 会員番号,住.住所コード,住所 FROM 会員 会 INNER JOIN 住所 住 ON 会.住所コード = 住.住所コード WHERE 住所 LIKE ‘神奈川県%’ ORDER BY 氏名 SELECT文 1 2 3 4
  • 8.
    8 複合インデックスを使ったIndex Only Scan •テーブルアクセスせずに、インデックスだけでSELECTする。 このようなインデックスを カバリング・インデックス と呼ぶこともある。 会員番号:1200 氏名:小林~ 会員番号 氏 名 性 別 住所コード 0010 佐藤 女 125 0700 小林 男 010 0204 高橋 男 001 0445 江川 女 001 会員番号:0700 会員番号:1000 氏名:田中~ 住所コード:010 住所コード⇒氏名⇒会員番号 会員テーブル データベース 複合インデックスで必要列を 全て取得し、テーブルへの アクセスを省略できる。 = Index Only Scan
  • 9.
    9 実行計画をシンプルにして性能改善! • Index OnlyScanを使ってチューニングした効果を検証する。 id | Operation |テーブル 0 | SELECT | 1 | SORT ORDER BY | 2 | NESTED LOOP | 3 | ROWIDスキャン | 住所 4 | Index Range Scan | 住所 5 | フルスキャン | 会員 id | Operation |テーブル 0 | SELECT | 1 | NESTED LOOP | 2 | Index Range Scan | 住所 3 | Index Range Scan | 会員 カバリング・インデックスを用いて チューニングした例。コストが激減! Cost=2,609 Cost=220before after
  • 10.
    10 各DBMSでのIndex Only Scanサポート状況 •Index Only Scanをサポートする機能や、複合インデックスの制約などは DBMSによって異なっている。 特徴的な機能 インデックス長、カラム数の制約 Oracle ・索引構成表をサポート 1ブロックの75%程度、32列まで MySQL (InnoDB) ・PKがクラスタ索引になる 3072バイト、各列は767バイト PostgreSQL ・9.2からIndex Only Scanが可能 ・テーブルにCLUSTER句を使える 2713バイト、32列まで MS SQL Server ・PKのデフォルトがクラスタ索引 ・INCLUDE句が使える 900バイト、16列まで
  • 11.
    11 Oracleの索引構成表 住所コード 郵便番号 住所 002 100-0010 東京都新宿区 001 100-0011 東京都千代田区 125 240-0005 神奈川県横浜市 テーブル • 索引構成表とはレコードを保持するインデックスである。 住所コード:001 住所コード:003 住所コード:005 住所コード:005 インデックス 通常のテーブルとインデックス 索引構成表 テーブル(ヒープ)とインデックスは別のデータ構造。 インデックスはROWID、テーブルがレコードを保持。 住所コード:008 住所コード:001 住所コード:003 住所コード:005 住所コード:005 索引構成表 郵便番号 住 所 100-0001 東京都千代田区 郵便番号 住 所 100-0120 東京都墨田区 リーフ・ブロックにレコードが格納された形で、 常にインデックス経由のアクセスとなる。 住所コード:005 住所コード:008 住所コード:125 郵便番号 住 所 240-0005 神奈川県横浜 ROWID
  • 12.
    12 MySQLのクラスタ化インデックス • MySQL(InnoDB)ではPKがクラスタ化インデックスになる。 innodbのクラスタ化インデックス 住所コード:008 住所コード:001 住所コード:003 住所コード:005 住所コード:005 クラスタ化インデックス(PK) 郵便番号 住所 100-0001 東京都千代田区 郵便番号 住 所 100-0120 東京都墨田区 クラスタ化インデックスは索引構成表と同じ構成で、 リーフ・ブロックにレコードを持つ。 住所コード:125 郵便番号 住 所 240-0005 神奈川県横浜 innodbのセカンダリインデックス 住所:北海道 住所:~千代田区 住所:東京都~ 住所:滋賀県~ 住所:奈良県 セカンダリインデックス 住所:宮崎県 二次インデックスではリーフ・ブロックに主キー値を持ち、 それからクラスタ化インデックスのレコードを検索する。
  • 13.
    13 PostgreSQLのIndex Only Scan •PostgreSQLは追記型DBのため、Index Only Scanの利用には制約あり。 PostgreSQLのインデックス構造 追記型DBという構造上、インデックススキャンだけでは 可視データが特定できず、Index Only Scanが難しい。 可視 住所コード 郵便番号 住 所 N 001 100-0010 東京都千代田区1 Y 001 100-0011 東京都千代田区2 Y 125 240-0005 神奈川県横浜市 テーブル 住所コード:001 住所コード:003 住所コード:005 住所コード:005 インデックス 住所コード:005 住所コード:008 PostgreSQLのIndex Only Scan利用条件 対象テーブルでVACUUMが行われていること。 更新が少ないテーブルにおいて、適切なタイミングで AUTOVACUUMが行われることが運用上は必須。
  • 14.
    14 MS SQL Serverのクラスタ索引 •SQL ServerではデフォルトでPKにクラスタ化インデックスが作成される。 • include句を使うことで付加列インデックスも作成できる。 クラスタ化インデックス(デフォルト) 住所コード:008 住所コード:001 住所コード:003 住所コード:005 住所コード:005 クラスタ化インデックス(PK) 郵便番号 住 所 100-0001 東京都千代田区 郵便番号 住 所 100-0120 東京都墨田区 MySQLと同様に、SQL Serverでもデフォルトでは PKにクラスタ化インデックスが作成される。 住所コード:125 郵便番号 住 所 240-0005 神奈川県横浜 include句を使ったインデックス 住所:北海道 住所:~千代田区 住所:東京都~ 住所:滋賀県~ 住所:奈良県 付加列インデックス 住所:宮崎県 複合インデックスと異なり、中間ブロックに不要データを 含まないので、サイズを小さく出来る 郵便番号 100-0001 郵便番号 100-0120 郵便番号 240-0005 インデックスは 住所だけに 貼られているが、 郵便番号をリーフに保持する
  • 15.
  • 16.
    16 今日話したこと  ここぞの処理では、Index OnlyScanを使ってみよう!  Oracleではこれにピッタリな索引構成表がある。  PostgreSQLではIndex Only Scanにならないケースがあるので注意!  MySQLやSQL Serverではクラスタ索引の特性を理解しよう!  とはいえ、複合インデックスの濫造は考えもの。ご利用は計画的に!