limit 1
を追加すると、クエリが非常に遅くなります。
オブジェクトのタイムスタンプ付きの値を持つテーブルobject_values
があります:
timestamp | objectID | value
--------------------------------
2014-01-27| 234 | ksghdf
オブジェクトごとに最新の値を取得したい:
SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC LIMIT 1;
(10分以上後にクエリをキャンセルしました)
特定のobjectIDに値がない場合、このクエリは非常に低速です(結果がある場合は高速です)。制限を削除すると、結果がないことがほぼ瞬時にわかります。
SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC;
...
Time: 0.463 ms
limit 1
を含むクエリはインデックスを使用しないため、無制限のクエリはインデックスを使用することを説明しています。
クエリが遅い:
explain SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC limit 1;
QUERY PLAN`
----------------------------------------------------------------------------------------------------------------------------
Limit (cost=0.00..2350.44 rows=1 width=126)
-> Index Scan Backward using object_values_timestamp on object_values (cost=0.00..3995743.59 rows=1700 width=126)
Filter: (objectID = 53708)`
高速クエリ:
explain SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------
Sort (cost=6540.86..6545.11 rows=1700 width=126)
Sort Key: timestamp
-> Index Scan using object_values_objectID on working_hours_t (cost=0.00..6449.65 rows=1700 width=126)
Index Cond: (objectID = 53708)
テーブルには、44,884,559行と66,762の異なるobjectIDが含まれます。
両方のフィールドに別々のインデックスがあります:timestamp
とobjectID
。
テーブルでvacuum analyze
を実行し、テーブルのインデックスを再作成しました。
さらに、制限を3以上に設定すると、スロークエリが高速になります。
explain SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp DESC limit 3;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------
Limit (cost=6471.62..6471.63 rows=3 width=126)
-> Sort (cost=6471.62..6475.87 rows=1700 width=126)
Sort Key: timestamp
-> Index Scan using object_values_objectID on object_values (cost=0.00..6449.65 rows=1700 width=126)
Index Cond: (objectID = 53708)
一般的には、実行コストに関してプランナーが誤った仮定をしているため、実行プランを遅くすることに関係していると思います。
これが本当の理由ですか?これに対する解決策はありますか?
行の相関関係に関する統計の欠如に関連する問題に直面しています。これが最新バージョンのPostgresを使用している場合、参照用にpg-bugsに報告することを検討してください。
あなたの計画のために私が提案する解釈は次のとおりです。
limit 1
は、Postgresが単一の行を探すようにし、その際、object_idが十分に一般的であり、インデックススキャンで適度にすばやく表示されると想定します。
あなたが考えた統計に基づいて、おそらく、適合する行を見つけるために平均で〜70行を読む必要があるでしょう。 object_idとタイムスタンプがテーブルの大部分を実際に読み取ろうとしているポイントと相関していることを認識していません。
対照的に、limit 3
は、それが十分に珍しいことを認識させます。したがって、期待するobject_id
を使用して、期待される1700行を_nソートすることを真剣に検討します。おそらく安くなります。
たとえば、これらの行の分布により、すべての行がディスク上の同じ領域にパックされることがわかっている場合があります。
limit
句がないと、とにかく1700をフェッチすることになるので、object_id
のインデックスに直接進みます。
解決策、ところで:(object_id, timestamp)
または(object_id, timestamp desc)
にインデックスを追加します。
不要なORDER BY
句をクエリに追加することにより、この問題を回避できます。
SELECT * FROM object_values WHERE (objectID = 53708) ORDER BY timestamp, objectID DESC limit 1;
更新が多いテーブルで同様の症状が出始めましたが、私の場合に必要なのは
analyze $table_name;
この場合、統計を更新する必要があり、それにより発生していたクエリプランが遅くなりました。
サポートドキュメント: https://www.postgresql.org/docs/current/sql-analyze.html