PostgreSQL Antipatterns: Π²Ρ€Π΅Π΄Π½Ρ‹Π΅ JOIN ΠΈ OR

Π‘ΠΎΠΉΡ‚Π΅ΡΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ, buffers приносящих…
На ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ нСбольшого запроса рассмотрим Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡƒΠ½ΠΈΠ²Π΅Ρ€ΡΠ°Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄Ρ‹ ΠΊ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·Π°Ρ†ΠΈΠΈ запросов Π½Π° PostgreSQL. ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΠΈΠΌΠΈ ΠΈΠ»ΠΈ Π½Π΅Ρ‚ β€” Π²Ρ‹Π±ΠΈΡ€Π°Ρ‚ΡŒ Π²Π°ΠΌ, Π½ΠΎ Π·Π½Π°Ρ‚ΡŒ ΠΎ Π½ΠΈΡ… стоит.

Π’ ΠΊΠ°ΠΊΠΈΡ…-Ρ‚ΠΎ ΠΏΠΎΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… вСрсиях PG ситуация ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒΡΡ с Β«ΠΏΠΎΡƒΠΌΠ½Π΅Π½ΠΈΠ΅ΠΌΒ» ΠΏΠ»Π°Π½ΠΈΡ€ΠΎΠ²Ρ‰ΠΈΠΊΠ°, Π½ΠΎ для 9.4/9.6 ΠΎΠ½Π° выглядит ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎ, ΠΊΠ°ΠΊ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Ρ‚ΡƒΡ‚.

Π’ΠΎΠ·ΡŒΠΌΡƒ Π²ΠΏΠΎΠ»Π½Π΅ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹ΠΉ запрос:

SELECT
  TRUE
FROM
  "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" d
INNER JOIN
  "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅" doc_ex
    USING("@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚")
INNER JOIN
  "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" t_doc ON
    t_doc."@Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = d."Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
WHERE
  (d."Π›ΠΈΡ†ΠΎ3" = 19091 or d."Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊ" = 19091) AND
  d."$Π§Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ" IS NULL AND
  d."Π£Π΄Π°Π»Π΅Π½" IS NOT TRUE AND
  doc_ex."БостояниС"[1] IS TRUE AND
  t_doc."Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = 'ΠŸΠ»Π°Π½Π Π°Π±ΠΎΡ‚'
LIMIT 1;

ΠΏΡ€ΠΎ ΠΈΠΌΠ΅Π½Π° Ρ‚Π°Π±Π»ΠΈΡ† ΠΈ полСйК «русским» названиям ΠΏΠΎΠ»Π΅ΠΉ ΠΈ Ρ‚Π°Π±Π»ΠΈΡ† ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚ΡŒΡΡ ΠΏΠΎ-Ρ€Π°Π·Π½ΠΎΠΌΡƒ, Π½ΠΎ это Π΄Π΅Π»ΠΎ вкуса. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρƒ нас Π² Β«Π’Π΅Π½Π·ΠΎΡ€Π΅Β» Π½Π΅Ρ‚ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ²-иностранцСв, Π° PostgreSQL позволяСт Π½Π°ΠΌ Π΄Π°Π²Π°Ρ‚ΡŒ названия Ρ…ΠΎΡ‚ΡŒ ΠΈΠ΅Ρ€ΠΎΠ³Π»ΠΈΡ„Π°ΠΌΠΈ, Ссли ΠΎΠ½ΠΈ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½Ρ‹ Π² ΠΊΠ°Π²Ρ‹Ρ‡ΠΊΠΈ, Ρ‚ΠΎ ΠΌΡ‹ ΠΏΡ€Π΅Π΄ΠΏΠΎΡ‡ΠΈΡ‚Π°Π΅ΠΌ ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΎΠ΄Π½ΠΎΠ·Π½Π°Ρ‡Π½ΠΎ-понятно, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π»ΠΎ Ρ€Π°Π·Π½ΠΎΡ‡Ρ‚Π΅Π½ΠΈΠΉ.
ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΠΌ Π½Π° ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ²ΡˆΠΈΠΉΡΡ ΠΏΠ»Π°Π½:
PostgreSQL Antipatterns: Π²Ρ€Π΅Π΄Π½Ρ‹Π΅ JOIN ΠΈ OR
[ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° explain.tensor.ru]

144ms ΠΈ ΠΏΠΎΡ‡Ρ‚ΠΈ 53K buffers β€” Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ большС 400MB Π΄Π°Π½Π½Ρ‹Ρ…! И Π½Π°ΠΌ ΠΏΠΎΠ²Π΅Π·Π΅Ρ‚, Ссли всС ΠΎΠ½ΠΈ окаТутся Π² кэшС ΠΊ ΠΌΠΎΠΌΠ΅Π½Ρ‚Ρƒ нашСго запроса, ΠΈΠ½Π°Ρ‡Π΅ ΠΎΠ½ станСт Π² Ρ€Π°Π·Ρ‹ дольшС ΠΏΡ€ΠΈ Π²Ρ‹Ρ‡ΠΈΡ‚Ρ‹Π²Π°Π½ΠΈΠΈ с диска.

Алгоритм Π²Π°ΠΆΠ½Π΅Π΅ всСго!

Π§Ρ‚ΠΎΠ±Ρ‹ ΠΊΠ°ΠΊ-Ρ‚ΠΎ ΠΎΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ любой запрос, Π½Π°Π΄ΠΎ сначала ΠΏΠΎΠ½ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ ΠΆΠ΅ ΠΎΠ½ Π²ΠΎΠΎΠ±Ρ‰Π΅ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π΄Π΅Π»Π°Ρ‚ΡŒ.
ΠžΡΡ‚Π°Π²ΠΈΠΌ ΠΏΠΎΠΊΠ° Π·Π° Ρ€Π°ΠΌΠΊΠ°ΠΌΠΈ этой ΡΡ‚Π°Ρ‚ΡŒΠΈ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ самой структуры Π‘Π”, ΠΈ договоримся, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ «дСшСво» ΠΏΠ΅Ρ€Π΅ΠΏΠΈΡΠ°Ρ‚ΡŒ запрос ΠΈ/ΠΈΠ»ΠΈ Π½Π°ΠΊΠ°Ρ‚ΠΈΡ‚ΡŒ Π½Π° Π±Π°Π·Ρƒ ΠΊΠ°ΠΊΠΈΠ΅-Ρ‚ΠΎ Π½ΡƒΠΆΠ½Ρ‹Π΅ Π½Π°ΠΌ индСксы.

Π˜Ρ‚Π°ΠΊ, запрос:
β€” провСряСт сущСствованиС Ρ…ΠΎΡ‚ΡŒ ΠΊΠ°ΠΊΠΎΠ³ΠΎ-Ρ‚ΠΎ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°
β€” Π² Π½ΡƒΠΆΠ½ΠΎΠΌ Π½Π°ΠΌ состоянии ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°
β€” Π³Π΄Π΅ Π°Π²Ρ‚ΠΎΡ€ΠΎΠΌ ΠΈΠ»ΠΈ исполнитСлСм являСтся Π½ΡƒΠΆΠ½Ρ‹ΠΉ Π½Π°ΠΌ сотрудник

JOIN + LIMIT 1

Достаточно часто Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΡƒ ΠΏΡ€ΠΎΡ‰Π΅ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ запрос, Π³Π΄Π΅ сначала дСлаСтся соСдинСниС большого количСства Ρ‚Π°Π±Π»ΠΈΡ†, Π° ΠΏΠΎΡ‚ΠΎΠΌ ΠΈΠ· всСго этого мноТСства остаСтся ΠΎΠ΄Π½Π°-СдинствСнная запись. Но ΠΏΡ€ΠΎΡ‰Π΅ для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° β€” Π½Π΅ Π·Π½Π°Ρ‡ΠΈΡ‚ эффСктивнСС для Π‘Π”.
Π’ нашСм случаС Ρ‚Π°Π±Π»ΠΈΡ† Π±Ρ‹Π»ΠΎ всСго 3 β€” Π° ΠΊΠ°ΠΊΠΎΠΉ эффСкт…

Π”Π°Π²Π°ΠΉΡ‚Π΅ для Π½Π°Ρ‡Π°Π»Π° избавимся ΠΎΡ‚ соСдинСния с Ρ‚Π°Π±Π»ΠΈΡ†Π΅ΠΉ Β«Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Β», Π° Π·Π°ΠΎΠ΄Π½ΠΎ подскаТСм Π±Π°Π·Π΅, Ρ‡Ρ‚ΠΎ Ρƒ запись Ρ‚ΠΈΠΏΠ° Ρƒ нас ΡƒΠ½ΠΈΠΊΠ°Π»ΡŒΠ½Π° (ΠΌΡ‹-Ρ‚ΠΎ это Π·Π½Π°Π΅ΠΌ, Π° Π²ΠΎΡ‚ ΠΏΠ»Π°Π½ΠΈΡ€ΠΎΠ²Ρ‰ΠΈΠΊ ΠΏΠΎΠΊΠ° Π½Π΅ догадываСтся):

WITH T AS (
  SELECT
    "@Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
  FROM
    "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
  WHERE
    "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = 'ΠŸΠ»Π°Π½Π Π°Π±ΠΎΡ‚'
  LIMIT 1
)
...
WHERE
  d."Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = (TABLE T)
...

Π”Π°, Ссли Ρ‚Π°Π±Π»ΠΈΡ†Π°/CTE состоит ΠΈΠ· СдинствСнного поля СдинствСнной ΠΆΠ΅ записи, Ρ‚ΠΎ Π² PG ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΈΡΠ°Ρ‚ΡŒ Π΄Π°ΠΆΠ΅ Ρ‚Π°ΠΊ, вмСсто

d."Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = (SELECT "@Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" FROM T LIMIT 1)

Β«Π›Π΅Π½ΠΈΠ²Ρ‹Π΅Β» вычислСния Π² запросах PostgreSQL

BitmapOr vs UNION

Π’ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… случаях Bitmap Heap Scan Π±ΡƒΠ΄Π΅Ρ‚ ΡΡ‚ΠΎΠΈΡ‚ΡŒ Π½Π°ΠΌ ΠΎΡ‡Π΅Π½ΡŒ Π΄ΠΎΡ€ΠΎΠ³ΠΎ β€” Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π² нашСй ситуации, ΠΊΠΎΠ³Π΄Π° достаточно ΠΌΠ½ΠΎΠ³ΠΎ записСй ΠΏΠΎΠ΄ΠΏΠ°Π΄Π°Π΅Ρ‚ ΠΏΠΎΠ΄ Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΠΎΠ΅ условиС. ΠŸΠΎΠ»ΡƒΡ‡ΠΈΠ»ΠΈ ΠΌΡ‹ Π΅Π³ΠΎ ΠΈΠ·-Π·Π° OR-условия, ΠΏΡ€Π΅Π²Ρ€Π°Ρ‚ΠΈΠ²ΡˆΠ΅Π³ΠΎΡΡ Π² BitmapOr-ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ Π² ΠΏΠ»Π°Π½Π΅.
ВСрнСмся ΠΊ исходной Π·Π°Π΄Π°Ρ‡Π΅ β€” Π½Π°Π΄ΠΎ Π½Π°ΠΉΡ‚ΠΈ запись, ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΡƒΡŽ Π»ΡŽΠ±ΠΎΠΌΡƒ ΠΈΠ· условий β€” Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ Π½Π΅Π·Π°Ρ‡Π΅ΠΌ ΠΈΡΠΊΠ°Ρ‚ΡŒ всС 59K записСй ΠΏΠΎ ΠΎΠ±ΠΎΠΈΠΌ условиям. Π•ΡΡ‚ΡŒ способ ΠΎΡ‚Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ ΠΎΠ΄Π½ΠΎ условиС, Π° ΠΊΠΎ Π²Ρ‚ΠΎΡ€ΠΎΠΌΡƒ ΠΏΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊΠΎΠ³Π΄Π° ΠΏΠΎ ΠΏΠ΅Ρ€Π²ΠΎΠΌΡƒ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ нашлось. Нам ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ такая конструкция:

(
  SELECT
    ...
  LIMIT 1
)
UNION ALL
(
  SELECT
    ...
  LIMIT 1
)
LIMIT 1

Β«Π’Π½Π΅ΡˆΠ½ΠΈΠΉΒ» LIMIT 1 Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ поиск Π·Π°Π²Π΅Ρ€ΡˆΠΈΡ‚ΡΡ ΠΏΡ€ΠΈ Π½Π°Ρ…ΠΎΠΆΠ΄Π΅Π½ΠΈΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠΉ ΠΆΠ΅ записи. И Ссли ΠΎΠ½Π° найдСтся ΡƒΠΆΠ΅ Π² ΠΏΠ΅Ρ€Π²ΠΎΠΌ Π±Π»ΠΎΠΊΠ΅, Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π²Ρ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΎΡΡƒΡ‰Π΅ΡΡ‚Π²Π»ΡΡ‚ΡŒΡΡ Π½Π΅ Π±ΡƒΠ΄Π΅Ρ‚ (never executed Π² ΠΏΠ»Π°Π½Π΅).

Β«ΠŸΡ€ΡΡ‡Π΅ΠΌ ΠΏΠΎΠ΄ CASEΒ» слоТныС условия

Π’ исходном запросС Π΅ΡΡ‚ΡŒ ΠΊΡ€Π°ΠΉΠ½Π΅ Π½Π΅ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ β€” ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° состояния ΠΏΠΎ связанной Ρ‚Π°Π±Π»ΠΈΡ†Π΅ Β«Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅Β». НСзависимо ΠΎΡ‚ истинности ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Ρ… условий Π² Π²Ρ‹Ρ€Π°ΠΆΠ΅Π½ΠΈΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, d.Β«Π£Π΄Π°Π»Π΅Π½Β» IS NOT TRUE), это соСдинСниС выполняСтся всСгда ΠΈ «стоит рСсурсов». Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΈΠ»ΠΈ мСньшС ΠΈΡ… Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΡ‚Ρ€Π°Ρ‡Π΅Π½ΠΎ β€” зависит ΠΎΡ‚ объСма этой Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹.
Но ΠΌΠΎΠΆΠ½ΠΎ ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ запрос Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ поиск связанной записи происходил Π±Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊΠΎΠ³Π΄Π° это Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ:

SELECT
  ...
FROM
  "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" d
WHERE
  ... /*index cond*/ AND
  CASE
    WHEN "$Π§Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ" IS NULL AND "Π£Π΄Π°Π»Π΅Π½" IS NOT TRUE THEN (
      SELECT
        "БостояниС"[1] IS TRUE
      FROM
        "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅"
      WHERE
        "@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" = d."@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚"
    )
  END

Π Π°Π· ΠΈΠ· связываСмой Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹ Π½Π°ΠΌ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ для Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π° Π½ΠΈ ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΠΏΠΎΠ»Π΅ΠΉ, Ρ‚ΠΎ ΠΌΡ‹ ΠΈΠΌΠ΅Π΅ΠΌ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΠΏΡ€Π΅Π²Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ JOIN Π² условиС ΠΏΠΎ подзапросу.
ΠžΡΡ‚Π°Π²ΠΈΠΌ индСксируСмыС поля Β«Π·Π° скобками» CASE, простыС условия ΠΎΡ‚ записи вносим Π² WHEN-Π±Π»ΠΎΠΊ β€” ΠΈ Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ «тяТСлый» запрос выполняСтся Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΏΡ€ΠΈ ΠΏΠ΅Ρ€Π΅Ρ…ΠΎΠ΄Π΅ Π² THEN.

Моя фамилия Β«Π˜Ρ‚ΠΎΠ³ΠΎΒ»

Π‘ΠΎΠ±ΠΈΡ€Π°Π΅ΠΌ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚ΠΈΡ€ΡƒΡŽΡ‰ΠΈΠΉ запрос со всСми описанными Π²Ρ‹ΡˆΠ΅ ΠΌΠ΅Ρ…Π°Π½ΠΈΠΊΠ°ΠΌΠΈ:

WITH T AS (
  SELECT
    "@Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
  FROM
    "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°"
  WHERE
    "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°" = 'ΠŸΠ»Π°Π½Π Π°Π±ΠΎΡ‚'
)
  (
    SELECT
      TRUE
    FROM
      "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" d
    WHERE
      ("Π›ΠΈΡ†ΠΎ3", "Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°") = (19091, (TABLE T)) AND
      CASE
        WHEN "$Π§Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ" IS NULL AND "Π£Π΄Π°Π»Π΅Π½" IS NOT TRUE THEN (
          SELECT
            "БостояниС"[1] IS TRUE
          FROM
            "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅"
          WHERE
            "@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" = d."@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚"
        )
      END
    LIMIT 1
  )
UNION ALL
  (
    SELECT
      TRUE
    FROM
      "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" d
    WHERE
      ("Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°", "Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊ") = ((TABLE T), 19091) AND
      CASE
        WHEN "$Π§Π΅Ρ€Π½ΠΎΠ²ΠΈΠΊ" IS NULL AND "Π£Π΄Π°Π»Π΅Π½" IS NOT TRUE THEN (
          SELECT
            "БостояниС"[1] IS TRUE
          FROM
            "Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π Π°ΡΡˆΠΈΡ€Π΅Π½ΠΈΠ΅"
          WHERE
            "@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚" = d."@Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚"
        )
      END
    LIMIT 1
  )
LIMIT 1;

ПодгоняСм [ΠΏΠΎΠ΄] индСксы

НамСтанный Π³Π»Π°Π· Π·Π°ΠΌΠ΅Ρ‚ΠΈΠ», Ρ‡Ρ‚ΠΎ индСксируСмыС условия Π² ΠΏΠΎΠ΄Π±Π»ΠΎΠΊΠ°Ρ… UNION Ρ‡ΡƒΡ‚ΡŒ разнятся β€” это ΠΏΠΎΡ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎ Ρƒ нас ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ подходящиС индСксы Π½Π° Ρ‚Π°Π±Π»ΠΈΡ†Π΅. А Ссли Π±Ρ‹ ΠΈΡ… Π½Π΅ Π±Ρ‹Π»ΠΎ β€” Ρ‚ΠΎ стоило Π±Ρ‹ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ: Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚(Π›ΠΈΡ†ΠΎ3, Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°) ΠΈ Π”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚(Π’ΠΈΠΏΠ”ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°, Π‘ΠΎΡ‚Ρ€ΡƒΠ΄Π½ΠΈΠΊ).
ΠΎ порядкС ΠΏΠΎΠ»Π΅ΠΉ Π² ROW-условияхБ Ρ‚ΠΎΡ‡ΠΊΠΈ зрСния ΠΏΠ»Π°Π½ΠΈΡ€ΠΎΠ²Ρ‰ΠΈΠΊΠ°, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, ΠΌΠΎΠΆΠ½ΠΎ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΈ (A, B) = (constA, constB), ΠΈ (B, A) = (constB, constA). Но ΠΏΡ€ΠΈ записи Π² порядкС слСдования ΠΏΠΎΠ»Π΅ΠΉ Π² индСксС, Ρ‚Π°ΠΊΠΎΠΉ запрос просто ΡƒΠ΄ΠΎΠ±Π½Π΅Π΅ ΠΏΠΎΡ‚ΠΎΠΌ ΠΎΡ‚Π»Π°ΠΆΠΈΠ²Π°Ρ‚ΡŒ.
Π§Ρ‚ΠΎ Π² ΠΏΠ»Π°Π½Π΅?
PostgreSQL Antipatterns: Π²Ρ€Π΅Π΄Π½Ρ‹Π΅ JOIN ΠΈ OR
[ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Π½Π° explain.tensor.ru]

К соТалСнию, Π½Π°ΠΌ Π½Π΅ ΠΏΠΎΠ²Π΅Π·Π»ΠΎ, ΠΈ Π² ΠΏΠ΅Ρ€Π²ΠΎΠΌ UNION-Π±Π»ΠΎΠΊΠ΅ Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ нашлось, поэтому Π²Ρ‚ΠΎΡ€ΠΎΠΉ всС-Ρ‚Π°ΠΊΠΈ пошСл Π½Π° Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅. Но Π΄Π°ΠΆΠ΅ ΠΏΡ€ΠΈ этом β€” всСго 0.037ms ΠΈ 11 buffers!
ΠœΡ‹ ускорили запрос ΠΈ сократили Β«ΠΏΡ€ΠΎΠΊΠ°Ρ‡ΠΊΡƒΒ» Π΄Π°Π½Π½Ρ‹Ρ… Π² памяти Π² нСсколько тысяч Ρ€Π°Π·, воспользовавшись достаточно простыми ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΈΠΊΠ°ΠΌΠΈ β€” Π½Π΅ΠΏΠ»ΠΎΡ…ΠΎΠΉ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ ΠΏΡ€ΠΈ нСбольшой копипастС. πŸ™‚

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com