Zaawansowane indeksowanie obejmujące warunki OR-ed (pgsql)
Zaczynam rozumieć indeksowanie PostgreSQL, ale mam problem z warunkiem OR, gdzie nie wiem, jak optymalizować moje indeksy, aby uzyskać szybsze zapytanie.
Mam 6 warunków, które uruchamiane indywidualnie wydają się mieć niewielki koszt. Oto przykład przyciętych zapytań, w tym obliczony plan zapytań.
(UWAGA: Poniżej nie przedstawiłem rzeczywistych planów kwerend dla tych zapytań ze względu na zmniejszenie złożoności, ale wszystkie one korzystająnested loop left joins
iindex scans
jak oczekiwałbym z właściwym indeksowaniem. Jeśli to konieczne, mogę dołączyć plany kwerend w celu uzyskania bardziej znaczącej odpowiedzi.)
EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions1)
LIMIT 10;
QUERY PLAN
-------------------------------------------------------------------------------------
Limit (cost=0.25..46.69 rows=1 width=171) (actual time=0.031..0.031 rows=0 loops=1)
EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions2)
LIMIT 10;
QUERY PLAN
-------------------------------------------------------------------------------------
Limit (cost=0.76..18.97 rows=1 width=171) (actual time=14.764..14.764 rows=0 loops=1)
/* snip */
EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions6)
LIMIT 10;
QUERY PLAN
-------------------------------------------------------------------------------------
Limit (cost=0.51..24.48 rows=1 width=171) (actual time=0.252..5.332 rows=10 loops=1)
Mój problem polega na tym, że chcę połączyć te 6 warunków razem z operatorami OR, dzięki czemu każdy warunek jest możliwy. Moje połączone zapytanie wygląda bardziej tak:
EXPLAIN ANALYZE SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions1 OR conditions2 OR conditions3 OR conditions4 OR conditions5 OR conditions 6)
LIMIT 10;
Niestety, skutkuje to MASYWNYM wzrostem planu kwerend, który wydaje się nie używać moich indeksów (zamiast tego wybieramhash left join
zamiast anested loop left join
i wykonując różnesequence scans
ponad poprzednio używaneindex scans
).
Limit (cost=142.62..510755.78 rows=1 width=171) (actual time=30.591..30.986 rows=10 loops=1)
Czy jest coś specjalnego, co powinienem wiedzieć o indeksowaniu w odniesieniu do warunków OR-ed, które poprawiłyby moje ostateczne zapytanie?
AKTUALIZACJA: Jeśli używam UNION dla każdego pojedynczego SELECT, wydaje się, że przyspiesza to zapytanie. Czy to jednak uniemożliwi mi zamawianie wyników, jeśli zdecyduję się w przyszłości? Oto co zrobiłem, aby przyspieszyć zapytanie za pośrednictwem UNION:
EXPLAIN ANALYZE
SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions1)
UNION
SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions2)
UNION
SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions3)
UNION
SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions4)
UNION
SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions5)
UNION
SELECT t1.*, t2.*, t3.*
FROM t1 LEFT JOIN t2 on t2.id = t1.t2_id LEFT JOIN t3 ON t3.id = t1.t3_id
WHERE (conditions6)
LIMIT 10;
QUERY PLAN
-------------------------------------------------------------------------------------
Limit (cost=219.14..219.49 rows=6 width=171) (actual time=125.579..125.653 rows=10 loops=1)