奇妙な PostgreSQL の動作が発生しています。履歴テーブルを時間に基づいて小さな部分に分割しました History -> History_part_YYYY-MM
Check constraints:
"History_part_2013-11_sentdate_check" CHECK (sentdate >= '2013-11-01 00:00:00-04'::timestamp with time zone AND sentdate < '2013-12-01 00:00:00-05'::timestamp with time zone)
継承:「歴史」
各パーティションには、transaction_id 列に独自のインデックスがあります。
History_part_2013-11_transaction_id_idx" btree (transaction_id)
postgresチュートリアルから取得した、パーティション分割の「特別なことは何もない」方法を知っている限りです。
問題は、このクエリの実行が遅いことです:
SELECT * FROM "History" WHERE transaction_id = 'MMS-dev-23599-2013-12-11-13:03:53.349735' LIMIT 1;
このクエリはスクリプトごとに最初の時間だけ遅く、2 回目に実行すると速いという問題を絞り込むことができました。別のスクリプトで再度実行すると、再び遅くなり、2回目の実行(スクリプトで)は再び高速になります...これについては本当に説明がありません。トランザクション内にはありません。
同じスクリプトで 1 つずつ実行される 2 つのクエリの実行時間の例を次に示します。
1.33s SELECT * FROM "History" WHERE transaction_id = 'MMS-dev-14970-2013-12-11-13:18:29.889376' LIMIT 1;...
0.019s SELECT * FROM "History" WHERE transaction_id = 'MMS-dev-14970-2013-12-11-13:18:29.889376' LIMIT 1;
最初のクエリは、「explain analyze」呼び出しをトリガーするのが遅く、次のようになります (そして、非常に高速でもあります)。
Limit (cost=0.00..8.07 rows=1 width=2589) (actual time=0.972..0.973 rows=1 loops=1)
-> Result (cost=0.00..581.07 rows=72 width=2589) (actual time=0.964..0.964 rows=1 loops=1)
-> Append (cost=0.00..581.07 rows=72 width=2589) (actual time=0.958..0.958 rows=1 loops=1)
-> Seq Scan on "History" (cost=0.00..1.00 rows=1 width=3760) (actual time=0.015..0.015 rows=0 loops=1)
Filter: ((transaction_id)::text = 'MMS-dev-23595-2013-12-11-13:20:10.422306'::text)
-> Index Scan using "History_part_2013-10_transaction_id_idx" on "History_part_2013-10" "History" (cost=0.00..8.28 rows=1 width=1829) (actual time=0.040..0.040 rows=0 loops=1)
Index Cond: ((transaction_id)::text = 'MMS-dev-23595-2013-12-11-13:20:10.422306'::text)
-> Index Scan using "History_part_2013-02_transaction_id_idx" on "History_part_2013-02" "History" (cost=0.00..8.32 rows=1 width=1707) (actual time=0.021..0.021 rows=0 loops=1)
Index Cond: ((transaction_id)::text = 'MMS-dev-23595-2013-12-11-13:20:10.422306'::text)
....そして、すべてのテーブルをチェックします(現在約54個-将来のために作成された空のテーブルはほとんどありません)そして最後に
-> Index Scan using "History_part_2014-10_transaction_id_idx" on "History_part_2014-10" "History" (cost=0.00..8.27 rows=1 width=3760) (never executed)
Index Cond: ((transaction_id)::text = 'MMS-dev-23595-2013-12-11-13:20:10.422306'::text)
Total runtime: 6.390 ms
総実行時間は 0,006 秒で、最初のクエリは常に 1 秒を超えます。(それぞれが UNIQUE transaction_id を持つ) 同時実行スクリプトが複数ある場合、最初の実行は最大 20 秒になり、2 番目の実行は数ミリ秒になります。
誰かがそれを経験しましたか?私がやっていることが間違っているのでしょうか、それともpostgresの問題でしょうか??
postgres を 9.2.4 から 9.2.5 にアップグレードしました。わずかに改善されたようですが、問題は確実に残っています。
更新:私は今このクエリを使用します:
SELECT * FROM "History" WHERE transaction_id = 'MMS-live-15425-2013-18-11-17:32:20.917198' AND sentdate>='2013-10-18' AND sentdate<'2013-11-19' LIMIT 1
スクリプトで初めて実行する場合 - このテーブルに対して一度に多くのクエリを実行すると、3 ~ 8 秒かかります (一度にスクリプトのみが存在する場合は、はるかに高速です)。
スクリプトの最初のクエリを (パーティション テーブルを直接呼び出す) に変更すると、次のようになります。
SELECT * FROM "History_part_2013-11" WHERE transaction_id = 'MMS-live-15425-2013-18-11-17:32:20.917198' AND sentdate>='2013-10-18' AND sentdate<'2013-11-19' LIMIT 1
それは 0.03 秒のようです - はるかに高速ですが、「履歴」テーブルに対するクエリを使用するスクリプト内の次のクエリは、まだ約 3 ~ 8 秒です。
「History」に対する最初のクエリの説明分析は次のとおりです。
Limit (cost=0.00..25.41 rows=1 width=2540) (actual time=0.129..0.130 rows=1 loops=1)
-> Result (cost=0.00..76.23 rows=3 width=2540) (actual time=0.121..0.121 rows=1 loops=1)
-> Append (cost=0.00..76.23 rows=3 width=2540) (actual time=0.117..0.117 rows=1 loops=1)
-> Seq Scan on "History" (cost=0.00..58.00 rows=1 width=3750) (actual time=0.060..0.060 rows=0 loops=1)
Filter: ((sentdate >= '2013-10-18 00:00:00-04'::timestamp with time zone) AND (sentdate < '2013-11-19 00:00:00-05'::timestamp with time zone) AND ((transaction_id)::text = 'MMS-live-15425-2013-18-11-17:32:20.917198'::text))
-> Index Scan using "History_part_2013-11_transaction_id_idx" on "History_part_2013-11" "History" (cost=0.00..8.36 rows=1 width=1985) (actual time=0.051..0.051 rows=1 loops=1)
Index Cond: ((transaction_id)::text = 'MMS-live-15425-2013-18-11-17:32:20.917198'::text)
Filter: ((sentdate >= '2013-10-18 00:00:00-04'::timestamp with time zone) AND (sentdate < '2013-11-19 00:00:00-05'::timestamp with time zone))
-> Index Scan using "History_part_2013-10_transaction_id_idx" on "History_part_2013-10" "History" (cost=0.00..9.87 rows=1 width=1884) (never executed)
Index Cond: ((transaction_id)::text = 'MMS-live-15425-2013-18-11-17:32:20.917198'::text)
Filter: ((sentdate >= '2013-10-18 00:00:00-04'::timestamp with time zone) AND (sentdate < '2013-11-19 00:00:00-05'::timestamp with time zone))
Total runtime: 0.572 ms
「メイン」履歴テーブルに対して実行すると(パーティションを直接呼び出すときではなく)常に遅く、初めてだけのようです-それは何かのキャッシュですか?しかし、パーティションを直接呼び出す方がはるかに高速である理由は、メインの履歴テーブルを呼び出すと、すべてのテーブルがチェックされなくなったためです。