2016-11-22 8 views
-2

昨日作成されたすべてのレコードを数えようとしています。 created_at列があり、索引付けされています。インデックス付き日時フィールドのフィルタリング(*)が長すぎます

私は

explain 
select count(*) from events where created_at::date = current_date - 1; 

を実行する場合それはそう、それはイベントの種類のがありますどのように多くの行を知っている

Aggregate (cost=14365728.05..14365728.06 rows=1 width=0) 
    -> Index Only Scan using index_events_created_at on events (cost=0.57..14362310.20 rows=1367140 width=0) 
     Filter: ((created_at)::date = (('now'::cstring)::date - 1)) 

言います。しかし

select count(*) from events where created_at::date = current_date - 1;

クエリ自体は永遠に実行し続けます。何故ですか?

+0

'イベントから選択カウント(*)'を使用するとどうなりますか? – McNets

+0

「永遠に走り続ける」...あなたは文字通り意味するのですか、それともあなたが望む以上に長く走るのですか?それが長く実行されているが(最終的に終了する場合)、結果はExplainプランに表示される数値に近いですか? –

+0

どのようなタイプが 'created_at'ですか? –

答えて

1

TRYこの:

だから、
SELECT count(*) 
FROM events 
WHERE created_at >= current_date - 1 
    AND created_at < current_date; 
1

、起動するには:なぜそんなに速くクエリを実行することができるよりも数える推定行を提供することが計画を説明していますか?

オプティマイザは、格納された統計および/または格納された統計からの外挿に基づいて行数を見積もります。ご覧のとおり、これはあまり正確ではありません。 (コメントの議論に基づいて、推定値はほぼ20%乖離していました)。したがって、テーブル内のデータまたはインデックス内のデータに基づいて、クエリを実際にカウントする必要があります。それはもっと仕事です。しかし、それがなぜ10分分の "より多くの作業"であるのかは分かりません。

ロック競合が考えられます。トランザクション分離の設定によっては、テーブルの挿入や更新が完了するまでクエリが待機する必要がないことがあります。 (オプティマイザは、同時クエリの影響がその目的のために大きな影響を及ぼさないと仮定しているため、見積もりを計算する際にこの問題は発生しません)。追加されたデータのどれもがあなたのカウントに影響を与えませんが、ロックは依然として競合する可能性があります。

この理論をテストする1つの方法は、誰も照会していない同じデータ(同じインデックスなど)を持つテーブルを持つようにテーブルをコピーして、それに対してより速く実行するかどうかを確認することです。

(余談:一般的には統計情報は、オプティマイザが悪い実行計画を選んいたと思われる可能性がオフ大幅に思える。しかし、それはインデックススキャンがここで間違っている解決策になる可能性がどのように見るのは難しい。)

関連する問題