DBアタマアカデミー

第4回 クエリ評価エンジンと実行計画―“シェフおまかせ”はいつも美味しいのか(2)

この記事を読むのに必要な時間:およそ 4.5 分

ランダムアクセスの実行計画

先ほど実行した簡単なクエリにWHERE条件を付けます。

SELECT *
  FROM Shops
  WHERE shop_id = ‘00050’;

再度実行計画を見てみましょうリスト4~6⁠。

リスト4 ランダムアクセスの実行計画(Oracle)

実行計画
----------------------------------------------------------
Plan hash value: 1968021522
                                               
----------------------------------------------------------------------------------------
| Id  | Operation                   | Name        | Rows | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |    1 |    21 |       1 (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| SHOPS       |    1 |    21 |       1 (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN         | SYS_C004155 |    1 |       |       0 (0)| 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

  2 - access("SHOP_ID"='00050')

リスト5 ランダムアクセスの実行計画(PostgreSQL)

                    QUERY PLAN
------------------------------------------------------
                                 
Seq Scan on shops (cost=0.00..1.75 rows=1 width=22)
  Filter: (shop_id = '00050'::bpchar)

リスト6 ランダムアクセスの実行計画(MySQL)

                                                                             
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | type  | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1  | SIMPLE      | Shops | const | PRIMARY       | PRIMARY | 5       | const |    1 |   100.00 |       |
+----+-------------+-------+-------+---------------+---------+---------+-------+------+----------+-------+

3つの結果には,おもしろい変化が見られます。先ほどと同様,3つの項目に注目していきましょう。

操作の対象となるレコード数

まず,いずれのDBMSも,Rows(リスト4~6が1になっています。主キーで「00050」の店舗を指定しているわけですから,結果が必ず1行になるためです。これは当然の変化です。

対象オブジェクトと操作

オブジェクト(リスト4~6と操作(リスト4~6についてはどうでしょう。PostgreSQLには,特段の変化はありません。Shopsに対するシーケンシャルスキャンです。他方,OracleとMySQLには変化が見られます。一言でいうと,両者ともインデックススキャンが行われるようになったのです。

Oracleでは,TABLE ACCESS FULLの代わりにTABLE ACCESS BY INDEX ROWIDと表示され(リスト4⁠,さらにその内訳としてId=2の行にINDEX UNIQUE SCAN対象オブジェクトにSYS_C004155という見たことのないオブジェクトが出ています(リスト4⁠。このSYS_C004155は主キーのインデックスの名前です。テーブル作成時に特に指定しなかったため,適当な名称が自動的に付けられています。

MySQLのほうは,key列にPRIMARYが現れています。これも,主キーのインデックスが使用されたことを意味しています。

インデックススキャン

インデックスについては本稿では解説する紙幅がないため詳細は略しますが注7⁠,一般的に,スキャンする母集合のレコード数に対して,選択されるレコード数が非常に少ない場合に高速なアクセスを実現します。

シーケンシャルスキャンがデータ量に正比例的に処理コストが増大するのに対し,インデックスの中で一般的なB-treeインデックスの場合,データ量に対数関数的に増大します。これは,インデックスのほうが処理コストの増大のしかたが緩やかだということを意味するので,あるデータ量(N)を損益分岐点として,インデックススキャンのほうが効率的にアクセスできるのです図3⁠。

図3 インデックススキャンとシーケンシャルスキャン

図3 インデックススキャンとシーケンシャルスキャン

今は60行しかデータが存在しないので,テーブルを順次読み込むのもインデックスでランダムアクセスするのも,レスポンスは大差ありませんが注8⁠,この差はレコード数が増えたときに効いてきます。

注7)
インデックスについての詳細は本誌Vol.51に掲載の「SQLアタマアカデミー 第7回 性能改善の鍵 インデックスの特性を知るを参照⁠⁠。
注8)
だからPostgreSQLはインデックスの使用を選択していないのです。

著者プロフィール

ミック

SI企業に勤務するDBエンジニア。主にデータウェアハウス業務に従事している。自身のサイト「リレーショナル・データベースの世界」でデータベースとSQLについての技術情報を公開している。『Web+DB Press』で「SQLアタマアカデミー」を連載中。

著書:『SQL ゼロからはじめるデータベース操作』(翔泳社,2010)『達人に学ぶ SQL徹底指南書』(翔泳社,2008)訳書:J.セルコ『SQLパズル 第2版』(翔泳社,2007)

DBアタマアカデミー:サポートページ