Здесь немного проигрыш. Прежде всего, я не dba, и у меня нет опыта работы с Postgres, за исключением того, что я делаю сейчас.
Postgres кажется задыхается, когда вы хотите вернуть jsonb документы вообще на что-нибудь больше пары сотен строк. Когда вы пытаетесь вернуть тысячи, производительность запроса становится ужасной. Если вы go еще дальше и попытаетесь вернуть несколько документов jsonb после различных объединений таблиц, забудьте об этом.
Вот мой сценарий с некоторым кодом:
У меня есть 3 таблицы - все таблицы имеют jsonb, все сложные модели и 2 из которых имеют размер (от 8 до 12 КБ без сжатия). В этой конкретной операции мне нужно разложить массив элементов jsonb, чтобы затем проработать его - это дает мне примерно 12k записей.
Каждая запись затем содержит идентификатор, который я использую для присоединения к другой важной таблице - мне нужно получить jsonb do c из этой таблицы. Оттуда мне нужно присоединить эту таблицу к другой (гораздо меньшей) таблице, а также вытащить оттуда do c на основе другого ключа.
Таким образом, на выходе получается несколько столбцов + 3 документа jsonb в диапазоне от Размер от <1 КБ до примерно 12 КБ без сжатия. </p>
Получение данных запроса фактически бессмысленно - я еще не видел данных, возвращаемых запросом. Как только я убираю столбцы json do c, естественно, скорость запроса увеличивается до секунд или меньше. 1 документ jsonb увеличивает время извлечения до 40 секунд в моем случае, добавление второй занимает у нас 2 минуты, а добавление третьего намного дольше.
Что я делаю не так? Есть ли способ получить документы jsonb эффективным способом?
SELECT x.id,
a.doc1,
b.doc2,
c.doc3
FROM ( SELECT id,
(elements.elem ->> 'a'::text)::integer AS a,
(elements.elem ->> 'b'::text)::integer AS b,
(elements.elem ->> 'c'::text)::integer AS c,
(elements.elem ->> 'd'::text)::integer AS d,
(elements.elem ->> 'e'::text)::integer AS e
FROM tab
CROSS JOIN LATERAL jsonb_array_elements(tab.doc -> 'arrayList'::text) WITH ORDINALITY elements(elem, ordinality)) x
LEFT JOIN table2 a ON x.id = a.id
LEFT JOIN table3 b ON a.other_id = b.id
LEFT JOIN table4 c ON b.other_id = c.id;
Сами таблицы довольно стандартные:
CREATE TABLE a (
id (primary key),
other_id (foreign key),
doc jsonb
)
Ничего особенного в этих таблицах, это идентификаторы и jsonb документы
Примечание - мы используем Postgres по нескольким причинам, нам действительно нужны реляционные аспекты PG, но в то же время нам нужно документировать возможность хранения и извлечения документов для дальнейшего использования в нашем рабочем процессе.
Извините, если я не предоставил здесь достаточно данных, я могу попытаться добавить еще несколько на основе любых комментариев
EDIT: добавлено объяснение:
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Hash Left Join (cost=465.79..96225.93 rows=11300 width=1843)
Hash Cond: (pr.table_3_id = br.id)
-> Hash Left Join (cost=451.25..95756.86 rows=11300 width=1149)
Hash Cond: (((p.doc ->> 'secondary_id'::text))::integer = pr.id)
-> Nested Loop Left Join (cost=0.44..95272.14 rows=11300 width=1029)
-> Nested Loop (cost=0.01..239.13 rows=11300 width=40)
-> Seq Scan on table_3 (cost=0.00..13.13 rows=113 width=710)
-> Function Scan on jsonb_array_elements elements (cost=0.01..1.00 rows=100 width=32)
-> Index Scan using table_1_pkey on table_1 p (cost=0.43..8.41 rows=1 width=993)
Index Cond: (((elements.elem ->> 'field_id'::text))::integer = id)
-> Hash (cost=325.36..325.36 rows=10036 width=124)
-> Seq Scan on table_2 pr (cost=0.00..325.36 rows=10036 width=124)
-> Hash (cost=13.13..13.13 rows=113 width=710)
-> Seq Scan on table_3 br (cost=0.00..13.13 rows=113 width=710)
(14 rows)
EDIT2: Извините, было мега занято - я постараюсь более подробно рассказать о go - во-первых, полностью объяснить план (я не знал о дополнительных параметрах) - оставлю в реальных таблицах (я не был уверен, разрешено ли мне):
Hash Left Join (cost=465.79..96225.93 rows=11300 width=1726) (actual time=4.669..278.781 rows=12522 loops=1)
Hash Cond: (pr.brand_id = br.id)
Buffers: shared hit=64813
-> Hash Left Join (cost=451.25..95756.86 rows=11300 width=1032) (actual time=4.537..265.749 rows=12522 loops=1)
Hash Cond: (((p.doc ->> 'productId'::text))::integer = pr.id)
Buffers: shared hit=64801
-> Nested Loop Left Join (cost=0.44..95272.14 rows=11300 width=912) (actual time=0.240..39.480 rows=12522 loops=1)
Buffers: shared hit=49964
-> Nested Loop (cost=0.01..239.13 rows=11300 width=40) (actual time=0.230..8.177 rows=12522 loops=1)
Buffers: shared hit=163
-> Seq Scan on brand (cost=0.00..13.13 rows=113 width=710) (actual time=0.003..0.038 rows=113 loops=1)
Buffers: shared hit=12
-> Function Scan on jsonb_array_elements elements (cost=0.01..1.00 rows=100 width=32) (actual time=0.045..0.057 rows=111 loops=113)
Buffers: shared hit=151
-> Index Scan using product_variant_pkey on product_variant p (cost=0.43..8.41 rows=1 width=876) (actual time=0.002..0.002 rows=1 loops=12522)
Index Cond: (((elements.elem ->> 'productVariantId'::text))::integer = id)
Buffers: shared hit=49801
-> Hash (cost=325.36..325.36 rows=10036 width=124) (actual time=4.174..4.174 rows=10036 loops=1)
Buckets: 16384 Batches: 1 Memory Usage: 1684kB
Buffers: shared hit=225
-> Seq Scan on product pr (cost=0.00..325.36 rows=10036 width=124) (actual time=0.003..1.836 rows=10036 loops=1)
Buffers: shared hit=225
-> Hash (cost=13.13..13.13 rows=113 width=710) (actual time=0.114..0.114 rows=113 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 90kB
Buffers: shared hit=12
-> Seq Scan on brand br (cost=0.00..13.13 rows=113 width=710) (actual time=0.003..0.043 rows=113 loops=1)
Buffers: shared hit=12
Planning Time: 0.731 ms
Execution Time: 279.952 ms
(29 rows)