web-dev-qa-db-ja.com

Postgresは、order by、index、およびlimitを使用したクエリを遅くします

Postgres(9.6)クエリのパフォーマンスを改善しようとしています。これが私のスキーマで、テーブルには約6000万行が含まれています。

          Column          |            Type             | Modifiers
--------------------------+-----------------------------+-----------
 transaction_id           | text                        | not null
 network_merchant_name    | text                        |
 network_merchant_id      | text                        |
 network_merchant_mcc     | integer                     |
 network_merchant_country | text                        |
 issuer_country           | text                        |
 merchant_id              | text                        |
 remapped_merchant_id     | text                        |
 created_at               | timestamp without time zone |
 updated_at               | timestamp without time zone |
 remapped_at              | timestamp without time zone |
Indexes:
    "mapped_transactions_pkey" PRIMARY KEY, btree (transaction_id)
    "ix_mapped_transactions_remapped_at" btree (remapped_at NULLS FIRST)

これが私が実行しようとしているクエリです。

SELECT *
FROM mapped_transactions
ORDER BY remapped_at ASC NULLS FIRST
LIMIT 10000;

クエリプランは次のとおりです。

    QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.57..1511.67 rows=10000 width=146) (actual time=327049.374..327345.341 rows=10000 loops=1)
   Buffers: shared hit=574937 read=210425 dirtied=356 written=4457
   I/O Timings: read=146625.381 write=59.637
   ->  Index Scan using ix_mapped_transactions_remapped_at on mapped_transactions  (cost=0.57..16190862.91 rows=107145960 width=146) (actual time=327049.364..327339.402 rows=10000 loops=1)
         Buffers: shared hit=574937 read=210425 dirtied=356 written=4457
         I/O Timings: read=146625.381 write=59.637
 Planning time: 0.125 ms
 Execution time: 327348.322 ms
(8 rows)  

remapped_atcolumnにインデックスがあると、なぜこんなに時間がかかるのかわかりません。

逆に逆に注文すると早いです。

SELECT *
FROM mapped_transactions
ORDER BY remapped_at DESC NULLS LAST
LIMIT 10000;

そして計画は:

QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.57..1511.67 rows=10000 width=146) (actual time=0.020..9.268 rows=10000 loops=1)
   Buffers: shared hit=1802
   ->  Index Scan Backward using ix_mapped_transactions_remapped_at on mapped_transactions  (cost=0.57..16190848.04 rows=107145866 width=146) (actual time=0.018..4.759 rows=10000 loops=1)
         Buffers: shared hit=1802
 Planning time: 0.080 ms
 Execution time: 11.561 ms
(6 rows)

誰かが最初のクエリのパフォーマンスを向上させる方法を教えてくれませんか?

アップデート

  1. これを解決するには、テーブルを再構築し、データのインデックスを再作成します。 VACUUM FULL ANALYZEはオプションではありませんでした。テーブルが使用されていて、ロックしたくなかったためです。

  2. インデックスのパフォーマンスは非常に速く低下しています。 7時間前にインデックスを再構築したところ、パフォーマンスは良好でした。これで、クエリは約10秒で応答します。このテーブルは書き込みが多いことに注意してください。インデックスを高速化するにはどうすればよいですか?テーブルのインデックスを頻繁に再作成する必要がありますか?このテーブルには削除はありませんが、多くの更新があります。

6
Zeeshan

さらにいくつかのテストを実行しましたが、このソリューションはうまくいかないようです。インデックスは時間の経過とともに常に低下していきます。インデックスの再作成(または削除して再作成)を行わないと、実行するクエリが次第に遅くなります。他の読み取り/書き込みをブロックせずにインデックスを作成する方法はいくつかありますが、簡単にスケーラブルでないため、現時点ではそれらを使用しません。この問題は私が持っている知識では解決できないので、別の方法を使用します。このアプローチでは、定数であり、更新されない列を持つインデックスを使用します。助けてくれてありがとう。

0
Zeeshan

PostgreSQL 9.5では確認できません。したがって、これは回帰である可能性があります。サンプルデータ、

CREATE TABLE mapped_transactions(remapped_at)
AS
  SELECT CASE WHEN x::int % 42 = 0 THEN null ELSE x::int END
  FROM generate_series( 1, 40e6 )
    AS gs(x);

CREATE INDEX ON mapped_transactions (remapped_at NULLS FIRST);
VACUUM ANALYZE mapped_transactions;

ここでNULLS FIRSTと動作します

EXPLAIN ANALYZE
SELECT *
FROM mapped_transactions
ORDER BY remapped_at ASC NULLS FIRST LIMIT 10000;
                                                                                     QUERY PLAN                                                                                      
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.56..260.24 rows=10000 width=4) (actual time=0.069..4.308 rows=10000 loops=1)
   ->  Index Only Scan using mapped_transactions_remapped_at_idx on mapped_transactions  (cost=0.56..1038716.81 rows=40000016 width=4) (actual time=0.067..2.740 rows=10000 loops=1)
         Heap Fetches: 0
 Planning time: 0.232 ms
 Execution time: 5.017 ms
(5 rows)

DESC NULLS LAST

EXPLAIN ANALYZE
SELECT * FROM mapped_transactions
ORDER BY remapped_at DESC NULLS LAST LIMIT 10000;
                                                                                          QUERY PLAN                                                                                          
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.56..260.24 rows=10000 width=4) (actual time=0.073..4.429 rows=10000 loops=1)
   ->  Index Only Scan Backward using mapped_transactions_remapped_at_idx on mapped_transactions  (cost=0.56..1038716.81 rows=40000016 width=4) (actual time=0.071..2.865 rows=10000 loops=1)
         Heap Fetches: 0
 Planning time: 0.114 ms
 Execution time: 5.137 ms
(5 rows)

テストケースを作成する必要があるかもしれません。何が発生しているかは明らかではありません。

1
Evan Carroll