2016-12-09 3 views
2

Я пытаюсь выяснить, могу ли я ускорить два запроса в базе данных, хранящей сообщения электронной почты. Вот таблица:Slow Postgres 9,3 запросов

\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) 

Выход из SELECT relname, relpages, reltuples::numeric, pg_size_pretty(pg_table_size(oid)) FROM pg_class WHERE oid='messages'::regclass;

является

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

Некоторые, возможно, соответствующие значения Postgres конфигурации:

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

Вот объясняющие анализировать результаты:

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) 

Второй запрос:

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, экземпляр 8GB Ram, средняя нагрузка обычно составляет около 0,15.

Я определенно не эксперт. Это случай, когда данные распространяются по всему диску? Мое единственное решение для использования CLUSTER?

Одна вещь, которую я не понимаю, почему она использует idx_unique_message_num в качестве индекса для второго запроса. И почему заказ по ID намного медленнее?

+1

Сколько записей имеет 'groupid = 1886'? Возможно, добавление индекса на '(groupid, id)' и на '(groupid, created)' помогло бы –

+0

Есть 200 563 строки для groupid = 1886. –

+1

Попробуйте добавить индексы в комментарий, так как теперь postgres должен (сортировать) сортировать эти 200 000 записей, что происходит медленно. Запросы без «OFFSET» будут быстрее, но с ними индексы должны сортировать проблему. –

ответ

3

Если есть много записей с groupid=1886 (из комментариев: есть 200,563), чтобы получить записи в СМЕЩЕНИИ отсортированного подмножества строк, потребуется сортировка (или эквивалентный алгоритм кучи), который является медленным.

Это можно решить, добавив индекс. В этом случае один на (groupid,id) и другой на (groupid,created).

Из комментария: Это действительно помогло, сократив время работы до 5 мс-10 мс.