SQL Engine Reference (v11)

インデックスの有効な使用法

インデックスは、制限以外の DISTINCT や ORDER BY 句などのクエリ特性を最適化することができます。

ここで使用されている用語の定義については、用語を参照してください。

集計関数の DISTINCT

DISTINCT キーワード付きの集計関数から成る選択リストが指定されているクエリでは、インデックスの使用によって取得する行数を減らすことができます。このタイプの最適化の対象となるには、DISTINCT キーワードが作用する式は単一の列参照で構成されている必要があります。さらに、その列はインデックスの先頭セグメントである必要があります。

たとえば、テーブル t1 に最初のセグメントが列 c1 であるインデックスがあるとします。インデックスを使用すると、列 c1 の値が重複している行の取得を回避することができます。

SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 = 1 

選択リストに先立つ DISTINCT

選択リストの前に DISTINCT キーワードが指定されているクエリでは、インデックスの使用によって取得する行数を減らすことができます。このタイプの最適化の対象となるには、選択リストは列参照のみから成り(算術式やスカラー関数のような複合式を含まない)、参照列は単一インデックスの先頭セグメントである必要があります。

たとえば、テーブル t1 に最初の 3 つのセグメントとして列 c1、c2、c3 を任意の順序で持つインデックスがあるとします。インデックスを使用すると、選択リストの各項目の値が重複している行の取得を回避することができます。

SELECT DISTINCT c1, c2, c3 FROM t1 WHERE c2 = 1 

インデックスのセグメント順序

ORDER BY 句で最適化のためにインデックスが使用されるかどうかは、インデックスのセグメントとして列がどのような順序で現れるかによります。具体的には、このタイプの最適化の対象となるには、ORDER BY 句内の列はインデックスの先頭セグメントである必要があり、インデックス内でセグメントとして現れる順序と同じ順序で ORDER BY 句に現れる必要があります。

これとは対照的に、選択リストや GROUP BY 句の場合はインデックスの先頭セグメントの列で構成されてさえいれば、選択リストの前にある DISTINCT または GROUP BY 句の最適化にインデックスを使用できます。このステートメントは、インデックス内のセグメントとして列が現れる順序にかかわらず真です。

たとえば、テーブル t1 に最初の 3 つのセグメントとして列 c1、c2、c3 を任意の順序で持つインデックスがあるとします。次のクエリでは、DISTINCT で最適化を行うためにインデックスが使用されます。

SELECT DISTINCT c1, c2, c3 FROM t1 
SELECT DISTINCT c2, c3, c1 FROM t1 WHERE c3 > 1 

次のクエリでは、GROUP BY で最適化を行うためにインデックスが使用されます。

SELECT c1, c2, c3, count(*) FROM t1 GROUP BY c2, c1, c3 
SELECT c2, c3, c1, count(*) FROM t1 GROUP BY c3, c2, c1 

ただし、ORDER BY での最適化に使用されるインデックスは、c2、c1、c3 の順序である必要があります。

SELECT c1, c2, c3 FROM t1 ORDER BY c2, c1, c3 

セグメントの昇順属性

ORDER BY 句で最適化にインデックスが使用されるかどうかは、いくつかの条件によって決まります。

具体的には、インデックスは次の条件をすべて満たす場合、最適化に使用されます。

さらに、インデックスは次の逆の条件をすべて満たす場合、最適化に使用されます(ヌル可能列は昇順の ORDER BY では使用できます)。

同様に、関連するすべてのセグメントの昇順または降順属性が ORDER BY 句で指定された ASC または DESC キーワードと完全に反する場合、ORDER BY の最適化にインデックスが使用されます。さらに、降順に定義されたセグメントは、関連する列がヌル可能列でない場合にのみ使用されます。

インデックスは、いずれかのセグメントの属性が昇順であるか降順であるかに関係なく、制限の最適化、DISTINCT の最適化または GROUP BY 句の最適化に使用されます。

たとえば、テーブル t1 に最初の 2 つのセグメントとして列 c1、c2 をこの順序で持つインデックスがあり、セグメントは 2 つとも昇順であるとします。このインデックスは、次のクエリで最適化を行うために使用することができます。

SELECT c1, c2, c3 FROM t1 ORDER BY c1, c2 
SELECT c1, c2, c3 FROM t1 ORDER BY c1 DESC, c2 DESC 
SELECT DISTINCT c1, c2 FROM t1 
SELECT DISTINCT c2, c1 FROM t1 
SELECT * FROM t1 WHERE c1 = 1 

テーブル t1 に最初の 2 つのセグメントとして列 c1、c2 をこの順序で持つインデックスがあり、c1 のセグメントは昇順、c2 のセグメントは降順に定義されているとします。また c2 はヌル可能列であるとします。2 番目のセグメントは降順かつヌル可能列であるため、ORDER BY の最適化には使用できません。このインデックスは、次のクエリで最適化を行うために使用することができます。

SELECT c1, c2, c3 FROM t1 ORDER BY c1 
SELECT c1, c2, c3 FROM t1 ORDER BY c1 DESC 
SELECT DISTINCT c1, c2 FROM t1 
SELECT DISTINCT c2, c1 FROM t1 
SELECT * FROM t1 WHERE c1 = 1 

c2 列がヌル可能列でない場合、インデックスは次のクエリで最適化を行うために使用することができます。

SELECT c1, c2, c3 FROM t1 ORDER BY c1, c2 DESC 
SELECT c1, c2, c3 FROM t1 ORDER BY c1 DESC, c2 

検索更新の最適化

インデックスの先頭セグメントを更新するとき、検索のための WHERE 句で同じインデックスを使うことによって、検索の最適化を利用することができます。データベース エンジンは、UPDATE 用のセッション(クライアント ID)と、もう 1 つ検索用のセッションを使用します。

次のステートメントは、検索の最適化によって利益を得られます。

CREATE TABLE t1 (c1 INT) 
CREATE INDEX t1_c1 ON t1(c1) 
INSERT INTO t1 VALUES (1) 
INSERT INTO t1 VALUES (1) 
INSERT INTO t1 VALUES (9) 
INSERT INTO t1 VALUES (10) 
INSERT INTO t1 VALUES (10) 
UPDATE t1 SET c1 = 2 WHERE c1 = 10 
UPDATE t1 SET c1 = c1 + 1 WHERE c1 >= 1 

プッシュダウン フィルター

テンポラリ テーブルのパフォーマンス