>  > [ホイール1本(単品)] VOSSEN / HF1 (TMS) 19インチ×8.5J PCD:114.3 穴数:5 インセット:29 DISK:FLAT

[ホイール1本(単品)] VOSSEN / HF1 (TMS) 19インチ×8.5J PCD:114.3 穴数:5 インセット:29 DISK:FLAT


インデックスのみのスキャンは、あらゆるチューニング法の中でも最強の方法の1つと言えるでしょう。where句の評価のために テーブルにアクセスする必要がないだけでなく、インデックス自体にお目当ての列があるなら、テーブルに全くアクセスしなくてもよいのです。

クエリ全体をカバーするためには、SQL文に出てくる全ての 列をインデックスに含めなくてはなりません。次の例のように、select句に含まれる列も例外ではありません。

CREATE INDEX sales_sub_eur
 ON sales
 ( subsidiary_id, eur_value )
SELECT SUM(eur_value)
 FROM sales
 WHERE subsidiary_id = ?

もちろん、インデックスを作る際は、他の句よりもwhere句が優先されます。 SUBSIDIARY_ID列は、アクセス述語として 使えるように、インデックスの最初にあります。

協力してください

この記事が気に入ったら、私の書いた本「SQLパフォーマンス詳解」や私によるトレーニングもきっと気にいるはず。

実行計画では、インデックススキャンが行われているとあり、その後にテーブルアクセス(TABLE ACCESS BY INDEX ROWID)は行われていません。

DB2
Explain Plan
---------------------------------------------------------------
ID | Operation | Rows | Cost
 1 | RETURN | | 21
 2 | GRPBY (COMPLETE) | 1 of 34804 ( .00%) | 21
 3 | IXSCAN SALES_SUB_EUR | 34804 of 1009326 ( 3.45%) | 19
Predicate Information
 3 - START (Q1.SUBSIDIARY_ID = ?)
 STOP (Q1.SUBSIDIARY_ID = ?)
Oracle
----------------------------------------------------------
| Id | Operation | Name | Rows | Cost |
----------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 104 |
| 1 | SORT AGGREGATE | | 1 | |
|* 2 | INDEX RANGE SCAN| SALES_SUB_EUR | 40388 | 104 |
----------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
 2 - access("SUBSIDIARY_ID"=TO_NUMBER(:A))

インデックスがクエリ全体をカバーしていることから、 カバリングインデックスとも呼ばれます。

注記

インデックスのはたらきによって、テーブルアクセスしなくても良かった場合のことを、 カバリングインデックスと言います。

これは、インデックスの機能であるかのような響きがあるので、誤解されやすい用語です。インデックスのみのスキャン、という言い方の 方が、実行計画の操作であることを明白に示しています。

データベースがインデックスに保存された値を使えるように、 インデックスはEUR_VALUE列を持っています。クエリの結果を返すための全ての情報をインデックスが持っているので、 テーブルにアクセスする必要はありません。

インデックスのみのスキャンは、桁違いにパフォーマンスを改善してくれます。実行計画の行数見積もりを見てみましょう。 オプティマイザは、

[ホイール1本(単品)] VOSSEN / HF1 (TMS) 19インチ×8.5J PCD:114.3 穴数:5 インセット:29 DISK:FLAT

メーカー名 VOSSEN (ヴォッセ)
商品名 HF1 (HF-1)
カラー チタンメタリックシルバー (TMS)
サイズ 19インチ×8.5J PCD:114.3 穴数:5 インセット:29
DISK FLAT
商品備考 PCD変更可能となります(ご希望の場合はご注文前にお知らせ下さいませ。)
送料 2,000円(※北海道・沖縄・離島は別途ご必要となる場合が御座います。)
適合車種 クルーガー(20系)、ハリアー(10系)、ヴァンガード(30系※ワイド)、ハリアー(30系)、ランサーエボリューションX(GSR)(CZ4A)
適合情報に関しまして 適合に関しましては、メーカー推奨サイズ(カスタムサイズ)/参考サイズとなる場合が御座います。
ご注文前に、事前にご確認下さいませ。(車種/型式/年式/駆動方式/グレード等をご記載下さいませ。)
納期 メーカー取り寄せ商品となります。欠品時、受注生産・廃盤・大幅な納期がご必要となる場合が御座いますので、お急ぎの方はメールにて在庫のご確認をお願い致します。
注意事項 ホイールのみ単品1本の商品となります。
タイヤはセット内容にふくまれませんのでご注意下さいませ。
タイヤを別でご購入等の場合、組み付け料等が別途ご必要となりますので、予めご了承下さいませ。
4本(1台分)ご注文にて送料無料となります。
注意事項 商品画像は共通画像となっております。商品により、デザイン・形状・色合い等が異なる場合が御座います。予めご了承くださいませ。
タイヤ・ナット等は含まれませんのでご了承下さいませ。

 注意事項 ◇ご注文前に◇
お急ぎの方はご注文前に、お問合せフォームより在庫の確認をお願い致します。
弊社、メーカー在庫共に欠品の場合はお届けまでにお時間を要する場合が御座います。
確認が無い場合の納期のクレームに関しては一切お受け出来ませんので予めご了承くださいませ。

商品の中にはメーカーからの取り寄せとなる商品も多数御座います。
時間差欠品や廃盤などにより商品をお届けできない場合はキャンセルとさせて頂く場合が御座います。

ご注文後のキャンセル、商品変更は出来ませんので予めご了承くださいませ。

◇商品到着後◇
商品がお手元に届きましたら、内容物の確認をお願い致します。
商品不備、破損等が御座います場合は、お届けより
7日以内 にご連絡下さいませ。

取付後、加工後の商品に関しましてはいかなる理由の場合でも返品、交換はお受け出来ません。
 送料 ◇配送料◇
商品により異なります為、ページよりご確認くださいませ。
ご不明な点が御座いましたらお問合せフォームよりお気軽にお問い合わせ下さいませ。
 タイヤ/ホイール   ◇返品/キャンセルについて◇
お客様の思い違いによるミスマッチの返品には応じられませんので、適合をよくご確認の上お求め願います。掲載画像と現物のイメージ相違による交換や返品は一切、承ることは出来ませんのでご注意願います。
◇適合に関するお問合せについて◇
適合に関しましては、お気軽に下記内容とあわせて、お問い合わせ下さい。 
■車種 ■型式 ■年式 ■駆動方式 ■グレード名 ■ビッグキャリパー有無 ■現在装着のタイヤサイズ

(例)■車種:トヨタ クラウンアスリート ■型式:DBA-GRS204 ■年式:H24年4月式 ■駆動方式:FR■グレード名:3.5 Gパッケージ ■ビッグキャリパー有無:有 ■現在装着のタイヤサイズ:225/45R18
※インチダウンの適合確認はご回答できない場合があります。
 画像/適合   ◇商品画像◇
一部の商品で共通の画像を使用させて頂いている場合が御座います。
実際にお届けする商品は、品番、適合車種等により形状、デザインが異なる場合が御座います。

◇適合情報◇
商品の適合情報に関しましては最新の情報を追加するように心がけてはおりますが、マイナーチェンジ等により適合する製品の品番が異なる場合がございます。
特に現行生産車両等に関しましてはご注文の前にメーカーホームページにて最新の適合情報をご確認の上、ご注文をお願いいたします。また適合商品がページに掲載されていない場合はお問い合わせいただけましたら対応させていただきます。
ご協力お願いいたします。

、4万行をまとめる必要があるとしています。つまり、各行が別々のブロックに保存されていたのだとすると、 インデックスのみのスキャンによって、4万回のテーブル読み込みをしなくて済んだということです。このインデックスがそこそこのクラスタ化係数を持っている、 つまり少数のテーブルブロックにデータがクラスタ化されているとすると、この利点はかなり小さくなります。

クラスタ化係数に加え、選択する行数によって 18インチ サマータイヤ セット【適応車種:レガシィツーリングワゴン(BR9 17インチ装着車)】WEDS レオニス FY パールブラックミラーカット 7.0Jx18ZIEX ZE914F 225/45R18、インデックスのみのスキャンの パフォーマンス改善効果は限定されてきます。もし1行しか選択しないとすると、1回分のテーブルアクセスしか削減できません。ツリーの走査でも数ブロックを読み込む必要が あることを考えると 【スウェッジライン】SWAGE-LINEブレーキホースキット/クリアホース/ステンレス製フィッティング仕様リアホースKIT クリアコート JZS160/161 アリスト 3000NA/Tb、節約できたテーブルアクセスの回数は、無視できる程度かもしれません。

重要

インデックスのみのスキャンの優位性は、 アクセスされる行数と、クラスタ化係数によって決まります。

インデックスのみのスキャンは、アグレッシブなインデックス戦略です。不要なメモリを確保したり、update文実行時のメンテナンス コストが増えたりするので、見込みだけでインデックスのみのスキャンを狙ってインデックスをデザインしてはなりません。詳しくは、第8章, 「データの変更を 参照してください。実際には、まずはwhere句などを優先し、select句を考えずにインデックスを作って、 必要があればそこから拡張していくべきでしょう。

インデックスのみのスキャンは、あまり嬉しくないことであなたを驚かせる可能性もあります。例えば、クエリを最近の売上だけに限定したものに 変えてみましょう。

SELECT SUM(eur_value)
 FROM sales
 WHERE subsidiary_id = ? AND sale_date > ?

実行計画を見ない内は、選択する行数が減った分、クエリの実行は 速くなると考えるでしょう。しかし、where句が インデックスにない列を参照しようとするので、その列を取得するためデータベースはテーブルへアクセスしなくてはならなくなりました。

DB2
Explain Plan
-------------------------------------------------------------------
ID | Operation | Rows | Cost
 1 | RETURN | | 13547
 2 | GRPBY (COMPLETE) | 1 of 1223 ( .08%) | 13547
 3 | FETCH SALES | 1223 of 34804 ( 3.51%) | 13547
 4 | RIDSCN | 34804 of 34804 (100.00%) | 32
 5 | SORT (UNQIUE) | 34804 of 34804 (100.00%) | 32
 6 | IXSCAN SALES_SUB_EUR | 34804 of 1009326 ( 3.45%) | 19
Predicate Information
 3 - SARG (? < Q1.SALE_DATE)
 SARG (Q1.SUBSIDIARY_ID = ?)
 6 - START (Q1.SUBSIDIARY_ID = ?)
 STOP (Q1.SUBSIDIARY_ID = ?)
Oracle
--------------------------------------------------------------
|Id | Operation | Name | Rows |Cost |
--------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 371 |
| 1 | SORT AGGREGATE | | 1 | |
|*2 | TABLE ACCESS BY INDEX ROWID| SALES | 2019 | 371 |
|*3 | INDEX RANGE SCAN | SALES_DATE| 10541 | 30 |
--------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
 2 - filter("SUBSIDIARY_ID"=TO_NUMBER(:A))
 3 - access("SALE_DATE">:B)

クエリが選択する行数は減ったのに、テーブルアクセスによって レスポンスタイムが増えてしまいます。関係があるのは 、クエリが返す行数ではなく、行を探し出すためにデータベースが何行にアクセスするか なのです。

警告

where句の条件を増やすと、 「不合理な」パフォーマンスの変化を引き起こすことがあります。クエリを変更する前に、実行計画を確認しましょう。

インデックスのみのスキャンにインデックスが使えなくなってしまうと、オプティマイザは次点の実行計画を選択します。つまり、オプティマイザは 全く違う実行計画を選ぶか、上の例のように違うインデックスを使った似たような実行計画を選びます。今回は、前の章で作ったSALE_DATEの インデックスを使っています。

オプティマイザの観点だと、このインデックスはSALES_SUB_EURと 比べると2つの優位点があります。オプティマイザは、SALE_DATEに 対するフィルタは、SUBSIDIARY_IDに対するフィルタよりも 選択性が高いと見ているのです。前の実行計画2つの「Rows」列からもそれが分かります(約1万行と4万行)。このクエリはバインドパラメータを使っているので、 これらの見積もりは、あくまで予想です。例えば、SALE_DATEの 条件に、初めて売上があった日が指定されたら、テーブル全体が選択されてしまいます。

SALES_DATEのインデックスの2つ目の優位点は、 クラスタ化係数がよいことです。SALESテーブルは時系列に大きく なっていくものなので、これは正しい考えと言えます。行が削除されない限り、新しい行は常にテーブルの最後尾に追加されていきます。 テーブルもインデックスもおおむね時系列にソートされているので、テーブルの並び方とインデックスの並び方は一致します。これはすなわち、 クラスタ化係数がよいということになります。

クラスタ化係数のよいインデックスということは、行を取りだす時に 少数のブロックしか読まなくてよいようにデータベースがデータを保存しているはずなので、選択する行は近くに保存されています。このようなインデックスを 使うと、インデックスのみのスキャンでなくても十分にクエリは高速になります。 この場合、他のインデックスから不要な列を削除するべきでしょう。

注記

自動的にクラスタ化係数がよくなるようなインデックスがあるので、 インデックスのみのスキャンのパフォーマンス上の優位性は小さくなります。

今回の例では、良い方の偶然もあります。SALE_DATEに 対する新しいフィルタは、インデックスのみのスキャンができないようにしただけでなく、新しいアクセスパスがあることも示してくれました。 オプティマイザは、この変更によるパフォーマンスの影響を小さくしてはくれましたが、別の句に列を追加することで、インデックスのみのスキャンを しないようにすることも可能です。一方、select句に 列を追加してしまうと センティア.MS-9[HDES][91/5~]JADEコンフォートシートレール【ブリットフルバケットシート専用】【左座席用】受注生産品■代引不可■、インデックスのみのスキャンが出来なくなったことによる影響を限定するアクセスパスは登場しなかったでしょう。

19インチ×8.5J インセット:29 PCD:114.3 VOSSEN DISK:FLAT DISK:FLAT (TMS) 19インチ×8.5J [ホイール1本(単品)] HF1 / 穴数:5

ヒント

インデックスのみのスキャンであることを明記しておきましょう。

インデックスのみのスキャンを使っていることを忘れないように コメントを書いておき、誰でも分かるようにしておきましょう。

関数インデックスも、 インデックスのみのスキャンに関連して、不愉快な不意打ちを仕掛けてくる 可能性があります。LAST_NAME列を選択する時には、 UPPER(last_name)に対するインデックスはインデックスのみのスキャンを使えません。前の節で、 LIKEフィルタをサポートするようにLAST_NAME列にも インデックスを作っておくべきだったかもしれません。そうすれば、 LAST_NAMEを選択する時もインデックスのみのスキャンが使えたでしょう。

ヒント

いつも最適な情報がインデックスに入るように、なるべくオリジナルの データにインデックスを作成するように常に心がけましょう。

アクセス述語として使えない表現に関数インデックスを作るのは やめましょう。

前述のようなクエリをまとめるのは、インデックスのみのスキャンを使う候補になり得ます。これらのクエリは NGK [92220] *1台分5本セット* プレミアムRXプラグ BKR6ERX-PS * ボルボ S70 E-8B5254 B5254 1997年1月~、たくさんの行を選択するけれど 対象の列は少ないので、インデックスのみのスキャンをサポートするスリムなインデックスを作れます。多くの列を対象にすればするほど、 インデックスのみのスキャンをサポートするために、たくさんの列をインデックスに 追加しなくてはなりません。開発者としては、本当に必要な列だけを選択するようにしましょう。

ヒント

select *するのはやめて、必要な列だけを指定しましょう。

多くの行にインデックスを作るとたくさんの容量が必要なのとはまた別に、使用しているデータベースの制限に届いてしまう可能性もあります。 多くのデータベースでは、インデックスあたりの列数やインデックスエントリの 総量に厳格な制限があります。つまり、好きなだけの列をインデックスに追加したり、 どんな長さの列もインデックスに追加したり出来るわけではないということです。特に重要な制限事項を次に列挙します。次の節では、テーブル全体をカバーする インデックスについて取り上げます。

[ホイール1本(単品)] VOSSEN / HF1 (TMS) 19インチ×8.5J 5ドア PCD:114.3 穴数:5 インセット:29 DISK:FLAT 2198

SQL ServerとPostgreSQL 11以降では、Bツリーインデックス内にいわゆる非キー列を作成できます。 この非キー列は、これまで説明してきたキー列とは別にリーフノードに保存されるので、アクセス述語としては使用できません。

非キー列はinclude句で定義できます。

 CREATE INDEX empsubupnam
 ON employees
 (subsidiary_id, last_name)
INCLUDE(phone_number, first_name)
DB2

DB2 LUWでは、インデックスに 含められるのは64列までで、ページサイズの25%までの長さの列に制限されています。

DB2では、インデックスでない列にユニークインデックスを 追加できるINCLUDEをサポートしています。これにより、一意性の文脈を変えずに インデックスのみのスキャンに使えるように、ユニークインデックスに列を追加できます。

MySQL

InnoDBのMySQLでは、(全列の)キー長合計は3072バイトに制限されています。さらに、各列の長さはinnodb_large_prefixが 有効になっていないか、行フォーマットにDYNAMICあるいは COMPRESSEDが使用されていない場合は、767バイトに 制限されています。これは、MySQL 5.6以降ではデフォルトに なっています。MyISAMのインデックスは、16列までで、 かつキーの最大長が1000バイトに制限されています。

MySQLは、「プレフィックスインデックス」 (「部分インデックス」と呼ばれることもある)というユニークな機能があります。 これにより、列の最初の数文字にだけインデックスを作ることができます。一方で、第2章で説明したような部分インデックスはありません。最大長(上述の通り、 767、1000、3072のいずれか)を超えるインデックスを作ろうとすると、SQL モードあるいは行フォーマット の設定によっては、MySQLはその列を自動的に短くします。このような時には、create index文は 「Specified key was too long; max key length is ... bytes」という 警告を出しつつも成功してしまいます。つまり、インデックスは列の完全なコピーではなくなってしまい、この列を選択する際もインデックス のみのスキャンに使えなくなってしまいます(関数インデックスの場合と同様です)。

「Specified key was too long; max key length is … bytes.」のようなエラーが出るようなら、明示的にキーの長さを指定してインデックスを作ることも可能です。これは、 LAST_NAME列の最初の10文字にのみインデックスを作る例です。

CREATE INDEX .. ON employees (last_name(10))
Oracle

インデックスの最大キー長は ミシュラン LATITUDE Tour HP サマータイヤ 215/60R17 ブリヂストン BALMINUM S5 ホイールセット 4本 17 X 7 +45 5穴 114.3、ブロックサイズとインデックスのストレージパラメータに依存します(ブロックサイズの 75%から多少のオーバーヘッドを引いた値)。Bツリーインデックスでは32列に制限されています。

デフォルト構成(8kブロック)のOracle 11gでは、インデックスの最大キー長は6398バイトです。この制限を超えると、 「ORA-01450: maximum key length (6398) exceeded.」のエラーが 発生します。

PostgreSQL

PostgreSQLでは、インデックスのみのスキャンをリリース 9.2からサポートしています。

Bツリーのエントリ長は、2713バイト(ハードコードされており、 およそBLCKSZ/3)に制限されています。エラー時のメッセージは「index row size ... exceeds btree maximum, 2713」で、制限を超えるinsertあるいはupdateが実行された時のみ発生します。Bツリーインデックスは、32 列まで含むことができます。

SQL Server

SQL Server 2016からは32列のキー長をサポートしていますが、全体の長さは1700バイトに制限されています (900バイトはクラスタインデックス用)。 0 非キー列はこの制限に含まれません。

この説明が気に入れば、きっとこの本も 気に入るはず。

ヒント

どの列も選択しないクエリは通常、インデックスのみのスキャンになります。

分かりやすい例を思い浮かべられますか?

前へ次へ

著者について

彼の本

核心をわかりやすく 解説。

Markusから購入します
(送料無料+PDF)

Amazonで購入
(印刷版のみ)

{yahoojp}jpprem01-zenjp40-wl-zd-35868