У меня есть таблица с именем «meta» с 2,2 миллионами записей. Эта таблица содержит 3 столбца: productId, ключ и значение. Ключ и значение - это два столбца, содержащие мета-описание продукта.Postgres два подзапроса низкой производительности [модель EAV]
Следующий запрос занимает 2,6 секунды и возвращает 676 результатов (PostgreSQL 8.4.13, CentOS 6.4 64-бит). Этот запрос используется для извлечения всех возможных мета-описаний из определенного фильтра (размера), где пользователь уже фильтрует два других фильтра (год и источник).
Я попробовал решение массив из этой темы, но это только хуже: PostgreSQL IN operator with subquery poor performance
Два подзапросов довольно быстро (75 мс и 178ms), но комбинируя их вызывает проблемы с производительностью. Есть ли способ переписать запрос?
Это текущий запрос:
SELECT DISTINCT ON(value) key, value
FROM "meta"
WHERE key = 'size'
AND "productId" IN (SELECT "productId"
FROM "meta"
WHERE "value" = 'ibm'
AND "key" = 'source')
AND "productId" IN (SELECT "productId"
FROM "meta"
WHERE "value" >= '1920'
AND "value" <= '2010'
AND "key" = 'year')
ORDER BY value
Со следующими EXPLAIN ANALYZE:
Unique (cost=38829.46..38843.19 rows=564 width=15) (actual time=2674.474..2690.856 rows=676 loops=1)
-> Sort (cost=38829.46..38836.32 rows=2745 width=15) (actual time=2674.471..2681.333 rows=66939 loops=1)
Sort Key: public."meta".value
Sort Method: quicksort Memory: 8302kB
-> Hash Join (cost=32075.86..38672.69 rows=2745 width=15) (actual time=472.158..2472.002 rows=66939 loops=1)
Hash Cond: (public."meta"."originalId" = public."meta"."productId")
-> Nested Loop (cost=15079.41..21563.33 rows=13109 width=23) (actual time=113.873..1013.113 rows=104307 loops=1)
-> HashAggregate (cost=15079.41..15089.21 rows=980 width=4) (actual time=113.802..163.805 rows=105204 loops=1)
-> Bitmap Heap Scan on "meta" (cost=315.39..15051.42 rows=11196 width=4) (actual time=24.540..68.237 rows=105204 loops=1)
Recheck Cond: (((key)::text = 'source'::text) AND ((value)::text = 'KADASTER_WOII_RAF_USAAF'::text))
-> Bitmap Index Scan on "productMetadataKeyValueIndex" (cost=0.00..312.60 rows=11196 width=0) (actual time=23.506..23.506 rows=105204 loops=1)
Index Cond: (((key)::text = 'source'::text) AND ((value)::text = 'ibm'::text))
-> Index Scan using "idx_productId" on "meta" (cost=0.00..6.59 rows=1 width=19) (actual time=0.006..0.008 rows=1 loops=105204)
Index Cond: (public."meta"."productId" = public."meta"."productId")
Filter: ((public."meta".key)::text = 'size'::text)
-> Hash (cost=16954.58..16954.58 rows=3350 width=4) (actual time=358.214..358.214 rows=184571 loops=1)
-> HashAggregate (cost=16921.08..16954.58 rows=3350 width=4) (actual time=258.149..319.154 rows=184571 loops=1)
-> Bitmap Heap Scan on "meta" (cost=1172.62..16825.39 rows=38273 width=4) (actual time=86.725..167.110 rows=184571 loops=1)
Recheck Cond: (((key)::text = 'year'::text) AND ((value)::text >= '1920'::text) AND ((value)::text <= '2010'::text))
-> Bitmap Index Scan on "productMetadataKeyIndex" (cost=0.00..1163.05 rows=38273 width=0) (actual time=83.992..83.992 rows=184571 loops=1)
Index Cond: (((key)::text = 'year'::text) AND ((value)::text >= '1920'::text) AND ((value)::text <= '2010'::text))
Total runtime: 2696.276 ms
Defined индексов:
idx_productId CREATE INDEX "idx_productId" ON "meta" USING btree ("productId")
productMetaUnique_id CREATE UNIQUE INDEX "productMetaUnique_id" ON "meta" USING btree ("productId", key)
productMetadataKeyIndex CREATE INDEX "productMetadataKeyIndex" ON "meta" USING btree (key)
productMetadataKeyValueIndex CREATE INDEX "productMetadataKeyValueIndex" ON "meta" USING btree (key, value)
Пожалуйста, покажите, какие индексы вы определили. – mvp
Хороший пример проблем, созданных страшной моделью EAV. Вы пытались объединить два подвыбора в один, используя «UNION ALL»? –
@horse Да, я пытался объединить их с UNION, но он создаст инструкцию OR. Результаты должны быть в BOTH-подзапросах, а не только в одном. –