Добавление индекса GIN в столбец JSONB замедляет мой запрос - PullRequest
1 голос
/ 17 февраля 2020

Я пришел из Mysql и не sql базы данных, и я новичок в Postgress db. Я использую Postgres 11,6 на Авроре AWS.

Я пытаюсь создать таблицы, состоящие из двух столбцов, ключа и значения jsonb.

Каждое значение выглядит следующим образом:

{"game": "game6",
   "username": "Djobi",   
   (bunch of fields)
   "permissions": ["permission3", "permission1", "permission5"]}

Я пытаюсь добавить разные индексы, чтобы увидеть, каковы возможности БД. Один из них, это найти пользователя по имени. Другой способ - найти пользователей с указанным разрешением c.

 account_index   | account_index_username    | CREATE INDEX account_index_username ON public.account_index USING btree (((value -> 'username'::text)))
 account_index   | account_index_permissions | CREATE INDEX account_index_permissions ON public.account_index USING gin (((value -> 'permissions'::text)))
 account_index   | account_global_gin        | CREATE INDEX accountgin ON public.account_index USING gin (value)

У меня есть две таблицы с точно такими же данными. Каждая таблица имеет около 30 миллионов строк. Один с индексом, один без. Я выполняю следующие запросы для проверки производительности:

SELECT 1 
FROM account_noindex 
WHERE value @> '{"permissions": ["permission1"]}' limit 10;

Я пытаюсь найти пользователя, имеющего разрешение1. (примечание: пока не уверен, как спросить, как получить конкретное разрешение1 по сравнению с любым разрешением, включая разрешение1). При выполнении моего запроса в моих индексных таблицах я получаю время ответа 5000 мс. При выполнении моего запроса в моих неиндексных таблицах время ответа составляет 50 мс.

Таким образом, неиндексная таблица в 100 раз быстрее индексной, что, я должен сказать, смущает меня. Если я попытаюсь выполнить объяснение двух запросов, я получу следующие результаты:

Таблица индексов:

Limit  (cost=430.49..468.31 rows=10 width=32)
   ->  Bitmap Heap Scan on account_index  (cost=430.49..144146.44 rows=37999 width=32)
         Recheck Cond: (value @> '{"permissions": ["permission1"]}'::jsonb)
         ->  Bitmap Index Scan on accountgin  (cost=0.00..420.99 rows=37999 width=0)
               Index Cond: (value @> '{"permissions": ["permission1"]}'::jsonb)
(5 rows)

Таблица не индексов

Limit  (cost=0.00..1935.23 rows=10 width=4)
   ->  Seq Scan on account_noindex  (cost=0.00..7360637.42 rows=38035 width=4)
         Filter: (value @> '{"permissions": ["permission1"]}'::jsonb)

Если я попытаюсь на go глубже в смещении (выше 100k) разница менее очевидна, но неиндексная таблица все еще быстрее.

[править] Здесь полный буфер анализа для индексированной таблицы:

EXPLAIN (ANALYZE, BUFFERS) SELECT value->'permissions' FROM account_index WHERE value @> '{"permissions": ["permission1"]}' limit 12;
                                                                QUERY PLAN                                                                 
-------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=430.49..475.88 rows=12 width=32) (actual time=1926.289..1926.365 rows=12 loops=1)
   Buffers: shared hit=24398
   ->  Bitmap Heap Scan on account_index  (cost=430.49..144146.44 rows=37999 width=32) (actual time=1926.287..1926.361 rows=12 loops=1)
         Recheck Cond: (value @> '{"permissions": ["permission1"]}'::jsonb)
         Rows Removed by Index Recheck: 30
         Heap Blocks: lossy=8
         Buffers: shared hit=24398
         ->  Bitmap Index Scan on accountgin  (cost=0.00..420.99 rows=37999 width=0) (actual time=1916.655..1916.656 rows=8386144 loops=1)
               Index Cond: (value @> '{"permissions": ["permission1"]}'::jsonb)
               Buffers: shared hit=24390
 Planning Time: 0.073 ms
 Execution Time: 1927.143 ms

Так чего мне здесь не хватает? Я неправильно создал свой индекс GIN? Или я неправильно выполняю запрос?

Обратите внимание, что у меня та же проблема с индексом в моем имени пользователя. Когда я делаю запрос на поиск пользователя с указанным c именем пользователя без какого-либо LIMIT, я получаю полное сканирование таблицы с индексом GIN или без него. Когда я добавляю индекс BTREE, тогда не возникает никаких проблем и не требуется никаких ограничений.

1 Ответ

1 голос
/ 17 февраля 2020

В столбцах JSONB нет полезной статистики, собранной по ним. Эта база данных должна делать общие предположения c о том, сколько строк она найдет, которые соответствуют @>, и они часто ошибочны. При выборе абсолютного наилучшего способа выполнения запроса LIMIT важно иметь более точную статистику. Общее предположение c состоит в том, что @> будет соответствовать 0,1% таблицы. Если это в корне неверно для вашего случая, вы, скорее всего, получите плохие планы.

Хотя разница между планами кажется огромной. Без видимого EXPLAIN (ANALYZE, BUFFERS) трудно сказать что-либо конкретное c об этом.

Обратите внимание, что у меня та же проблема с индексом на моем имени пользователя. Если у меня просто есть индекс GIN, я получаю действительно странный результат. Когда я добавляю индекс BTREE, тогда не возникает никаких проблем.

Я понятия не имею, какими могут быть "странные" результаты. Вам нужно будет привести примеры.

...