web-dev-qa-db-ja.com

PostgreSQLはインデックスにnullを使用できますか?

私は読んでいます この本

データベースは、Indexed_Col IS NOT NULLがカバーする範囲が大きすぎて有用ではないと想定しているため、データベースはこの条件からインデックスに移動しません。

この本は10年以上前のものであると認識していますが、すでにかなり便利であることが証明されています-ページから収集した指示を使用して、 10倍のクエリ。

さらに、EXPLAIN ANALYZESELECTクエリで、自分のインデックスが使用されていないことがわかりました。

したがって、私の質問は:

列が "NOT NULL"を含む列を持つテーブルがあり、この列をカバーするインデックスが存在する場合、このインデックスは、列がクエリの一部であるテーブルのクエリで使用されますか?

お気に入り:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;
10
FuriousFolder

PostgreSQLは確かにcan _IS NOT NULL_のインデックスを使用します。その条件についてのクエリプランナーの想定もわかりません。

列(_pg_statistic.stanullfrac_)のnull分数が十分に低く、インデックスがクエリに対して有効に選択的であることを示唆している場合、PostgreSQLはインデックスを使用します。

私はあなたが何を言おうとしているのか理解できません:

これが正しい場合、「NOT NULL」として定義された列のインデックスは、その列を使用するクエリで使用されないことを理解していますか?

確かに、インデックスは_IS NOT NULL_列の_NOT NULL_条件に使用されません。それは常に100%の行に一致するため、seqscanはほとんど常に非常に高速です。

インデックスがクエリの行の大部分を除外しない場合、PostgreSQLはインデックスを使用しません。唯一の例外は、単一のインデックスでカバーされる列のセットを、インデックスの列と一致する順序で要求する場合です。その場合、PostgreSQLはインデックスのみのスキャンを行う可能性があります。例えば。 t(a, b, c)にインデックスがあり、次の場合:

_select a, b FROM t ORDER BY a, b, c;
_

行がフィルターで除外されていなくても、PostgreSQLはインデックスを使用する場合があります。これは、インデックスを読み取るだけで、ヒープの読み取りをスキップしたり、並べ替えを回避したりできるためです。

9
Craig Ringer

クレイグの完全な回答に加えて、私はあなたが参照する本の表紙が言うことを付け加えたかった:

Oracle、DB2、SQL Serverをカバー

そのため、特にPostgreSQLに関する素晴らしいアドバイスになるとは信じていません。すべてのRDBMSは驚くほど異なる可能性があります。

私はあなたの元の質問について少し混乱していますが、これは本のセクションが100%正しくないことを示す例です。さらに混乱を避けるために、関連する段落全体を以下に示します。これは Googleブック検索 で確認できます。

データベースは、Indexed_Col IS NOT NULLがカバーする範囲が大きすぎて有用ではないと想定しているため、データベースがこの条件からインデックスにアクセスすることはありません。まれに、null以外の値が存在することはまれです可能なすべての非null値に対するインデックスレンジスキャンは有益です。そのような場合、すべての可能な値の範囲の安全な下限または上限を理解できれば、Positive_ID_Column>-などの条件でレンジスキャンを有効にできます。 1またはDate_Column> TO_DATE( '0001/01/01'、 'YYYY/MM/DD')。

Postgresは実際に(以下の不自然なケースで)インデックスを使用して、推奨されるIS NOT NULLのような範囲スキャンクルージを追加せずにPositive_ID_Column > -1クエリを満たすことができます。この特定のケースでPostgresがこのインデックスを選択する理由については、Craigの質問のコメントと、部分インデックスの使用に関する注意を参照してください。

CREATE TABLE bar (a int);
INSERT INTO bar (a) SELECT NULL FROM generate_series(1,1000000);
INSERT INTO bar (a) VALUES (1);
CREATE INDEX bar_idx ON bar (a);

EXPLAIN ANALYZE SELECT * FROM bar WHERE a IS NOT NULL;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Only Scan using bar_idx on bar  (cost=0.42..8.44 rows=1 width=4) (actual time=0.094..0.095 rows=1 loops=1)
   Index Cond: (a IS NOT NULL)
   Heap Fetches: 1
 Total runtime: 0.126 ms
(4 rows)

ちなみにこれはPostgres 9.3ですが、「インデックスのみのスキャン」を使用しない場合でも、結果は9.1とほぼ同じだと思います。

編集:あなたはあなたの元の質問を明確にしたと思います、そしてあなたはどうやらPostgresが次のような簡単な例でインデックスを使用していないのかと疑問に思っています:

CREATE TABLE my_table(
a varchar NOT NULL
);

CREATE INDEX ix_my_table ON my_table(a);

SELECT a from my_table;

おそらくテーブルに行がないためです。テストデータとANALYZE my_table;を追加します。

2