1

スキーマ:PostgreSQLがインデックスを正しく使用していないのはなぜですか?

create table records(
    id   varchar, 
    updated_at bigint 
); 
create index index1 on records (updated_at, id); 

クエリ。最近更新されたレコードを繰り返し処理します。 10レコードを取得し、最後のレコードを覚えてから次の10レコードを取得します。

select * from objects 
where updated_at > '1' or (updated_at = '1' and id > 'some-id') 
order by updated_at, id 
limit 10; 

それはインデックスを使用していますが、それは賢明にそれを使用して、フィルタを適用すると、レコードのトンを処理していない、以下のクエリの説明でRows Removed by Filter: 31575を参照してください。

orを削除して左または右の状態のままにしておくと、奇妙なことです。これは両方でうまく動作します。しかし、両方の条件がorと同時に使用される場合、インデックスを正しく適用する方法を理解できないかのようです。

Limit (cost=0.42..19.03 rows=20 width=1336) (actual time=542.475..542.501 rows=20 loops=1) 
    -> Index Scan using index1 on records (cost=0.42..426791.29 rows=458760 width=1336) (actual time=542.473..542.494 rows=20 loops=1) 
     Filter: ((updated_at > '1'::bigint) OR ((updated_at = '1'::bigint) AND ((id)::text > 'some-id'::text))) 
     Rows Removed by Filter: 31575 
Planning time: 0.180 ms 
Execution time: 542.532 ms 
(6 rows) 

Postgresのバージョンが9.6

+0

'...どこupdated_atの> '1' ...'あなたは、整数リテラルを引用するべきではありません。 – wildplasser

+0

@wildplasser引用符もなく、同じことを試しました。 –

+0

'width = 1336'それは非常に広いテーブルです、 – wildplasser

答えて

2

である私は、このような彼らの結果を組み合わせ二つの別々のクエリ、としてこれをしようとするだろう:私の推測では、2つのクエリがそれぞれかなりよく最適化するだろうということです

select * 
from 
    (
    select * 
    from  objects 
    where updated_at > 1 
    order by updated_at, id 
    limit 10 
    union all 
    select * 
    from  objects 
    where updated_at = 1 
     and id > 'some-id' 
    order by updated_at, id 
    limit 10 
) t 
order by updated_at, id 
limit 10 

と両方を実行すると、現在のものよりも効率的になります。

可能であれば、これらの列をNULLにしないでください。

+0

そう、私もそれについて考えました。しかし、私はPostgreSQLが十分にスマートで、おそらく私のコードにいくつかの間違いがあると思いました... –

+0

はい、それは問題のおかげで解決しました。奇妙な...私はPostgreSQLからより良いと期待... –

2

PostgreSQLで作成されたインデックスへの呼び出しの最適化があります。例えば

、上のインデックス(A、B、C)とクエリ = 5条件及びb> = 42及びC < 77与えられ、インデックスは、最初のエントリから走査されなければなりません最後のエントリまではa = 5、b = 42までは = 5です。c> = 77のインデックスエントリはスキップされますが、それでもスキャンする必要があります。このインデックスは、原則として、 のクエリに使用できます.bおよび/またはcには制約がなく、-のインデックスは使用できますが、インデックス全体をスキャンする必要があります。したがって、 プランナは、インデックスを使用します。

https://www.postgresql.org/docs/9.6/static/indexes-multicolumn.html

関連する問題