vp
型のtimestamp
型のテーブルbigint
とbtree
のtimestamp
インデックスを指定した場合、Postgresがインデックスを無視し、timestamp
と浮動小数点値の比較でseqスキャンを実行して、インデックススキャンで同じ結果が生成されるのはなぜですか?
_SELECT * FROM vp WHERE vp.timestamp > 1470752584
_がかかる48ミリ秒:
vpのvp_ts_idxを使用したインデックススキャン(コスト= 0.57..257.87行= 2381幅= 57)(実際の時間= 0.014..38.669行= 80323ループ= 1) インデックス条件:( "タイムスタンプ"> 1470752584) 合計実行時間:48.322ミリ秒
_SELECT * FROM vp WHERE vp.timestamp > 1470752584.1
_は_vp_ts_idx
_を無視してテーブル全体のseqスキャンを実行するため、103秒かかります。
vpのシーケンススキャン(コスト= 0.00..7378353.16行= 95403915幅= 57)(実際の時間= 62625.420..103122.701行= 98240ループ= 1) フィルター:(( "timestamp"):: numeric> 1470752584.1) フィルターによって削除された行数:285945491 合計実行時間:103134.333 ms
コンテキスト:最近の車両位置のクエリは、timestamp
をEXTRACT(Epoch FROM NOW()) - %s
と比較しました。ここで、_%s
_は、bigint
に明示的にキャストせずに、必要な秒数でした。回避策は、CAST(EXTRACT(Epoch FROM NOW()) - %s AS bigint)
を使用することです。
列の型がbigint
の場合、クエリプランナーはこれを自動的に行わないのはなぜですか?これはバグですか、それともこの動作が役立つエッジケースを考慮していませんか?
重要なのは、同じタイプを比較しないことです。 bigint
をnumeric
と比較する場合、簡単な方法は、bigint
を「展開」して小数点以下を0にして(1-> 1.0のように)、他の方法はそれを回避する方法は、丸め/切り捨てを意味します。 (この特定のケースでは、両方が同じ結果につながることが簡単にわかりますが、値が負の場合はどうなりますか?)
したがって、比較で得られるのはnumeric
からnumeric
への比較であり、bigint
インデックスが提供できるものではありません。
どのキャストが可能で、これらのケースで実行されるかは一見の価値があります。このため、ここに pg_cast
の2つの行があります。
SELECT castsource::regtype, casttarget::regtype, castcontext
FROM pg_cast
WHERE castsource::regtype = 'bigint'::regtype
AND casttarget::regtype = 'numeric'::regtype;
castsource │ casttarget │ castcontext
────────────┼────────────┼─────────────
bigint │ numeric │ i
SELECT castsource::regtype, casttarget::regtype, castcontext
FROM pg_cast
WHERE castsource::regtype = 'numeric'::regtype
AND casttarget::regtype = 'bigint'::regtype;
castsource │ casttarget │ castcontext
────────────┼────────────┼─────────────
numeric │ bigint │ a
リンクされたドキュメントページによると、castcontext
キャストを呼び出すことができるコンテキストを示します。
e
は、明示的なキャストとしてのみ意味します(CAST
または::
構文を使用)。a
は、ターゲット列への割り当てで暗黙的に、および明示的に意味します。i
は、他の場合と同様に、式で暗黙的に意味します。
つまり、これは、前者を後者に割り当てた場合にのみ、numeric
-> bigint
の方向が「単独で」発生する(つまり、キャスト演算子の1つを明示的に呼び出さない)ことを意味します。比較のような式では、これは当てはまりません。そのため、パーサーは逆の方法(上記のi
でマークされている)のみを考慮します。つまり、強制しない限り、numeric
からnumeric
への比較が行われます。
注:
psql
はPostgreSQLのコマンドラインクライアントであり、それ自体はこれらのことを何も行いません(それに応じてタイトルを編集しました)。timestamp
など)は決して良い考えではありません。あらゆる場所でキーワードを二重引用符で囲むように注意しない限り、あちこちで予期しない解析エラーが発生する可能性があります