sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQL:このクエリがインデックスを使用しないのはなぜですか?

    すでにお気づきのように、問題はequals以外の演算子の使用に関連しています。インデックスは、等しい(プラス1つの範囲条件)と比較される左端の列に対してのみ最も効率的に使用できます。

    あなたの例では:

    create index i on t (a,b,c,d);
    where a=1 and b=11 and c!=5 and d<8;
    

    インデックスはaにのみ使用できます およびb 効率的。つまり、DBはaに一致するすべての行をフェッチします およびb 条件を設定してから、各行を残りの条件と照合します。

    cでフィルターを変更した場合 等しい場合、フェッチする行は(潜在的に)少なくなります(aに一致する行のみ) およびb およびc )次に、それらの(少ない)行をdと照合します。 フィルター。この場合、インデックスを使用する方が効率的です。

    一般に、PostgreSQLクエリプランナーは両方のオプションを評価します。(1)インデックスを使用する。 (2)SeqScanを実行します。どちらの場合も、コスト値を計算します。値が高いほど、期待されるパフォーマンスは低下します。したがって、コスト値が小さい方を採用します。これは、インデックスを使用するかどうかを決定する方法であり、固定のしきい値はありません。

    最後に、上記の「プラスワンレンジ条件」と書いてあります。つまり、等号を使用している場合に最も効率的な方法でインデックスを使用できるだけでなく、単一の範囲条件に対しても使用できます。

    クエリに単一の範囲条件があることを考えると、次のようにインデックスを変更することをお勧めします。

    create index i on t (a,b,d,c);
    

    これで、aのフィルターを使用できるようになりました およびb およびd インデックスを使用して効率的に処理し、c!=5の行をフィルタリングするだけで済みます。 。このインデックスは、元のインデックスと同じようにクエリでより効率的に使用できますが、PGが自動的に使用することを意味するわけではありません。それはコスト見積もりに依存します。しかし、試してみてください。

    最後に、これが十分に速くない場合は、および5 c!=5という式で使用しています が一定の場合、部分インデックスを検討できます:

     create index i on t (a,b,d)
            where c!=5;
    

    比較する値が定数であれば、他のすべての列でも同じことができます。

    参照:



    1. Oracle Floats vs Number

    2. JOINクエリを使用してレコードを取得する

    3. MySQLエラー:行1の列'amount'の範囲外の値

    4. Javaのランダムな数字