2016-12-09 14 views
2

私は、電子メールメッセージを格納するデータベースで2つのクエリを高速化できるかどうかを判断しようとしています。ここでは、テーブルの:遅いPostgres 9.3クエリ

shared_buffers = 1536MB 
effective_cache_size = 4608MB 
work_mem = 7864kB 
maintenance_work_mem = 384MB 

ここでの出力を分析し説明している:SELECT relname, relpages, reltuples::numeric, pg_size_pretty(pg_table_size(oid)) FROM pg_class WHERE oid='messages'::regclass;

から

\d messages; 
          Table "public.messages" 
    Column  | Type |      Modifiers 
----------------+---------+------------------------------------------------------- 
id    | bigint | not null default nextval('messages_id_seq'::regclass) 
created  | bigint | 
updated  | bigint | 
version  | bigint | 
threadid  | bigint | 
userid   | bigint | 
groupid  | bigint | 
messageid  | text | 
date   | bigint | 
num   | bigint | 
hasattachments | boolean | 
placeholder | boolean | 
compressedmsg | bytea | 
revcount  | bigint | 
subject  | text | 
isreply  | boolean | 
likes   | bytea | 
isspecial  | boolean | 
pollid   | bigint | 
username  | text | 
fullname  | text | 
Indexes: 
    "messages_pkey" PRIMARY KEY, btree (id) 
    "idx_unique_message_messageid" UNIQUE, btree (groupid, messageid) 
    "idx_unique_message_num" UNIQUE, btree (groupid, num) 
    "idx_group_id" btree (groupid) 
    "idx_message_id" btree (messageid) 
    "idx_thread_id" btree (threadid) 
    "idx_user_id" btree (userid) 

出力は

relname | relpages | reltuples | pg_size_pretty 
----------+----------+-----------+---------------- 
messages | 1584913 | 7337880 | 32 GB 

設定値は、いくつかの関連する可能性はpostgresです

explain analyze SELECT * FROM messages WHERE groupid=1886 ORDER BY id ASC LIMIT 20 offset 4440; 
                     QUERY PLAN 
------------------------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=479243.63..481402.39 rows=20 width=747) (actual time=14167.374..14167.408 rows=20 loops=1) 
    -> Index Scan using messages_pkey on messages (cost=0.43..19589605.98 rows=181490 width=747) (actual time=14105.172..14167.188 rows=4460 loops=1) 
     Filter: (groupid = 1886) 
     Rows Removed by Filter: 2364949 
Total runtime: 14167.455 ms 
(5 rows) 

2のクエリ:

explain analyze SELECT * FROM messages WHERE groupid=1886 ORDER BY created ASC LIMIT 20 offset 4440; 
                     QUERY PLAN 
---------------------------------------------------------------------------------------------------------------------------------------------------------- 
Limit (cost=538650.72..538650.77 rows=20 width=747) (actual time=671.983..671.992 rows=20 loops=1) 
    -> Sort (cost=538639.62..539093.34 rows=181490 width=747) (actual time=670.680..671.829 rows=4460 loops=1) 
     Sort Key: created 
     Sort Method: top-N heapsort Memory: 7078kB 
     -> Bitmap Heap Scan on messages (cost=7299.11..526731.31 rows=181490 width=747) (actual time=84.975..512.969 rows=200561 loops=1) 
       Recheck Cond: (groupid = 1886) 
       -> Bitmap Index Scan on idx_unique_message_num (cost=0.00..7253.73 rows=181490 width=0) (actual time=57.239..57.239 rows=203423 loops=1) 
        Index Cond: (groupid = 1886) 
Total runtime: 672.787 ms 
(9 rows) 

これはSSD、8ギガバイトラムインスタンスで、負荷の平均は約通常0.15です。

私は間違いなく専門家です。これはディスク全体に広がっているデータのケースですか? CLUSTERを使用する私の唯一のソリューションですか?

私が理解できない1つの理由は、idx_unique_message_numを2番目のクエリのインデックスとして使用している理由です。なぜIDで注文するのがずっと遅いのですか?

+1

'groupid = 1886'のレコード数はいくつですか?おそらく '(groupid、id)'と '(groupid、created) 'にインデックスを追加すると助けになるでしょう。 –

+0

groupid = 1886には200,563行あります。 –

+1

コメントにインデックスを追加しようとすると、postgresはこれらの200,000レコードをソートしなければならないので、遅いです。 'OFFSET'のないクエリは速くなりますが、インデックスは問題をソートする必要があります。 –

答えて

3

groupid=1886(コメントから:200,563)のレコードが多数ある場合、ソートされた行のサブセットのオフセットでレコードを取得するには、ソート(または同等のヒープアルゴリズム)が遅い必要があります。

これはインデックスを追加することで解決できます。この場合、1つは(groupid,id)にあり、もう1つは(groupid,created)にあります。

コメントから:これは本当に助けになり、ランタイムを5ms~10msに短縮しました。