PostgreSQL Query Profiler: como combinar plan e consulta

Moitos que xa están a usar explicar.tensor.ru - É posible que o noso servizo de visualización do plan PostgreSQL non teña coñecemento dun dos seus superpoderes: converter unha peza difícil de ler do rexistro do servidor...

PostgreSQL Query Profiler: como combinar plan e consulta
... nunha consulta ben deseñada con suxestións contextuais para os nodos do plano correspondentes:

PostgreSQL Query Profiler: como combinar plan e consulta
Nesta transcrición da segunda parte da súa informe en PGConf.Russia 2020 Vouvos contar como conseguimos facelo.

A transcrición da primeira parte, dedicada aos problemas típicos de rendemento das consultas e as súas solucións, pódese atopar no artigo "Receitas para consultas SQL problemáticas".



En primeiro lugar, imos comezar a colorear - e xa non colorearemos o plano, xa o coloreamos, xa o temos bonito e comprensible, pero unha petición.

Pareceunos que cunha "folla" tan sen formato a solicitude tirada do rexistro parece moi fea e, polo tanto, incómoda.
PostgreSQL Query Profiler: como combinar plan e consulta

Especialmente cando os desenvolvedores "pegan" o corpo da solicitude no código (isto é, por suposto, un antipatrón, pero ocorre) nunha soa liña. Horrible!

Imos debuxar isto dalgún xeito máis fermoso.
PostgreSQL Query Profiler: como combinar plan e consulta

E se podemos debuxar isto moi ben, é dicir, desmontar e volver a montar o corpo da solicitude, entón podemos "anexar" unha pista a cada obxecto desta solicitude: o que pasou no punto correspondente do plano.

Árbore de sintaxe de consulta

Para iso, primeiro debe analizarse a solicitude.
PostgreSQL Query Profiler: como combinar plan e consulta

Porque temos o núcleo do sistema execútase en NodeJS, entón fixemos un módulo para iso, podes atopalo en GitHub. De feito, estes son "enlaces" estendidos aos internos do propio analizador PostgreSQL. É dicir, a gramática é simplemente compilada en binario e as ligazóns realízanse desde NodeJS. Tomamos como base os módulos doutras persoas: aquí non hai ningún gran segredo.

Alimentamos o corpo da solicitude como entrada para a nosa función; na saída obtemos unha árbore de sintaxe analizada en forma de obxecto JSON.
PostgreSQL Query Profiler: como combinar plan e consulta

Agora podemos percorrer esta árbore na dirección oposta e montar unha solicitude coas sangrías, cor e formato que queremos. Non, isto non é personalizable, pero pareceunos que sería conveniente.
PostgreSQL Query Profiler: como combinar plan e consulta

Consulta de mapas e nodos de planificación

Agora vexamos como podemos combinar o plan que analizamos no primeiro paso e a consulta que analizamos no segundo.

Poñamos un exemplo sinxelo: temos unha consulta que xera un CTE e o le dúas veces. El xera tal plan.
PostgreSQL Query Profiler: como combinar plan e consulta

CTE

Se o miras con atención, ata a versión 12 (ou empezando dela coa palabra clave MATERIALIZED) formación CTE é unha barreira absoluta para o planificador.
PostgreSQL Query Profiler: como combinar plan e consulta

Isto significa que se vemos unha xeración CTE nalgún lugar da solicitude e un nodo nalgún lugar do plan CTE, entón estes nós definitivamente "loitan" entre si, podemos combinalos inmediatamente.

Problema cun asterisco: os CTE pódense aniñar.
PostgreSQL Query Profiler: como combinar plan e consulta
Hainos moi mal aniñados, e incluso co mesmo nome. Por exemplo, podes dentro CTE A facer CTE X, e ao mesmo nivel no interior CTE B facelo de novo CTE X:

WITH A AS (
  WITH X AS (...)
  SELECT ...
)
, B AS (
  WITH X AS (...)
  SELECT ...
)
...

Ao comparar, debes entender isto. Entender isto "cos teus ollos" - mesmo ver o plan, mesmo ver o corpo da solicitude - é moi difícil. Se a túa xeración CTE é complexa, aniñada e as solicitudes son grandes, entón está completamente inconsciente.

UNIÓN

Se temos unha palabra clave na consulta UNION [ALL] (operador de unir dúas mostras), entón no plano correspóndese con ou ben un nodo Append, ou algúns Recursive Union.
PostgreSQL Query Profiler: como combinar plan e consulta

O que está "enriba" arriba UNION - este é o primeiro descendente do noso nodo, que está "abaixo" - o segundo. Se a través UNION temos varios bloques "pegados" á vez, entón Append-aínda haberá só un nodo, pero non terá dous, senón moitos fillos - na orde na que van, respectivamente:

  (...) -- #1
UNION ALL
  (...) -- #2
UNION ALL
  (...) -- #3

Append
  -> ... #1
  -> ... #2
  -> ... #3

Problema cun asterisco: xeración de mostraxe recursiva dentro (WITH RECURSIVE) tamén pode ser máis dun UNION. Pero só o último bloque despois do último é sempre recursivo UNION. Todo o anterior é un, pero diferente UNION:

WITH RECURSIVE T AS(
  (...) -- #1
UNION ALL
  (...) -- #2, тут кончается генерация стартового состояния рекурсии
UNION ALL
  (...) -- #3, только этот блок рекурсивный и может содержать обращение к T
)
...

Tamén cómpre ser capaz de "salir" tales exemplos. Neste exemplo vemos que UNION-había 3 segmentos na nosa solicitude. En consecuencia, un UNION corresponde a Append-nodo, e ao outro - Recursive Union.
PostgreSQL Query Profiler: como combinar plan e consulta

Datos de lectura-escritura

Todo está disposto, agora sabemos que parte da solicitude corresponde a que parte do plan. E nestas pezas podemos atopar de xeito sinxelo e natural aqueles obxectos que son "lexibles".

Dende o punto de vista da consulta, non sabemos se é unha táboa ou un CTE, pero están designados polo mesmo nodo RangeVar. E en termos de "lexibilidade", este tamén é un conxunto bastante limitado de nós:

  • Seq Scan on [tbl]
  • Bitmap Heap Scan on [tbl]
  • Index [Only] Scan [Backward] using [idx] on [tbl]
  • CTE Scan on [cte]
  • Insert/Update/Delete on [tbl]

Coñecemos a estrutura do plano e a consulta, coñecemos a correspondencia dos bloques, coñecemos os nomes dos obxectos -facemos unha comparación un a un.
PostgreSQL Query Profiler: como combinar plan e consulta

De novo tarefa "cun asterisco". Tomamos a solicitude, executámola, non temos ningún alias; só lemos dúas veces desde o mesmo CTE.
PostgreSQL Query Profiler: como combinar plan e consulta

Miramos o plan: cal é o problema? Por que tiñamos un alias? Non o pedimos. De onde saca ese "número de número"?

PostgreSQL engádeo por si mesmo. Só tes que entender iso só ese alias para nós, a efectos de comparación co plan, non ten ningún sentido, simplemente engádese aquí. Non lle fagamos caso.

O segundo tarefa "cun asterisco": se estamos lendo desde unha táboa particionada, entón teremos un nodo Append ou Merge Append, que estará formado por un gran número de "nenos", e cada un dos cales será dalgún xeito Scan'om da sección da táboa: Seq Scan, Bitmap Heap Scan ou Index Scan. Pero, en calquera caso, estes "nenos" non serán consultas complexas; así é como se poden distinguir estes nós de Append en UNION.
PostgreSQL Query Profiler: como combinar plan e consulta

Tamén entendemos tales nós, recólleos "nunha pila" e dicimos: "todo o que le de megatable está aquí e abaixo da árbore".

Nodos de recepción de datos "simples".

PostgreSQL Query Profiler: como combinar plan e consulta

Values Scan corresponde no plano VALUES na solicitude.

Result é unha solicitude sen FROM como SELECT 1. Ou cando tes unha expresión deliberadamente falsa WHERE-block (aparece entón o atributo One-Time Filter):

EXPLAIN ANALYZE
SELECT * FROM pg_class WHERE FALSE; -- или 0 = 1

Result  (cost=0.00..0.00 rows=0 width=230) (actual time=0.000..0.000 rows=0 loops=1)
  One-Time Filter: false

Function Scan "mapa" aos SRF do mesmo nome.

Pero coas consultas aniñadas todo é máis complicado; por desgraza, non sempre se converten InitPlan/SubPlan. Ás veces convértense en ... Join ou ... Anti Join, sobre todo cando escribes algo así WHERE NOT EXISTS .... E aquí non sempre é posible combinalos: no texto do plan non hai operadores correspondentes aos nodos do plan.

De novo tarefa "cun asterisco": algunhas VALUES na solicitude. Neste caso e no plano obterás varios nodos Values Scan.
PostgreSQL Query Profiler: como combinar plan e consulta

Os sufixos "numerados" axudarán a distinguilos entre si - engádense exactamente na orde na que se atopan os correspondentes. VALUES-bloques ao longo da solicitude de arriba a abaixo.

Tratamento de datos

Parece que se solucionou todo a nosa solicitude; só queda Limit.
PostgreSQL Query Profiler: como combinar plan e consulta

Pero aquí todo é sinxelo - tales nodos como Limit, Sort, Aggregate, WindowAgg, Unique “mapa” un a un aos operadores correspondentes na solicitude, se están alí. Non hai "estrelas" nin dificultades aquí.
PostgreSQL Query Profiler: como combinar plan e consulta

Rexístrese se

As dificultades xorden cando queremos combinar JOIN entre eles. Isto non sempre é posible, pero é posible.
PostgreSQL Query Profiler: como combinar plan e consulta

Desde o punto de vista do analizador de consultas, temos un nodo JoinExpr, que ten exactamente dous fillos: esquerda e dereita. Isto, polo tanto, é o que está "enriba" do teu JOIN e o que está escrito "debaixo" na solicitude.

E dende o punto de vista do plan, trátase de dous descendentes dalgúns * Loop/* Join-nodo. Nested Loop, Hash Anti Join,... - algo así.

Usemos unha lóxica sinxela: se temos táboas A e B que "se unen" entre si no plano, na solicitude poderían situarse ou A-JOIN-BOu B-JOIN-A. Tentemos combinar deste xeito, intentemos combinar ao revés, e así ata quedar sen este tipo de parellas.

Collemos a nosa árbore de sintaxe, collemos o noso plan, miralos... non se parecen!
PostgreSQL Query Profiler: como combinar plan e consulta

Redebuxámolo en forma de gráficos, xa parece algo!
PostgreSQL Query Profiler: como combinar plan e consulta

Teñamos en conta que temos nós que teñen fillos B e C ao mesmo tempo; non nos importa en que orde. Combinámolos e dámoslle voltas á imaxe do nodo.
PostgreSQL Query Profiler: como combinar plan e consulta

Vexamos de novo. Agora temos nós con fillos A e pares (B + C), compatibles tamén con eles.
PostgreSQL Query Profiler: como combinar plan e consulta

Genial! Resulta que somos estes dous JOIN a partir da solicitude cos nodos do plan combináronse con éxito.

Por desgraza, este problema non sempre se soluciona.
PostgreSQL Query Profiler: como combinar plan e consulta

Por exemplo, se nunha solicitude A JOIN B JOIN C, e no plano, en primeiro lugar, conectáronse os nodos "exteriores" A e C. Pero non hai tal operador na solicitude, non temos nada que destacar, nada ao que engadir unha suxestión. Pasa o mesmo coa "coma" cando escribes A, B.

Pero, na maioría dos casos, case todos os nodos pódense "desatar" e podes obter este tipo de perfiles á esquerda a tempo, literalmente, como en Google Chrome cando analizas o código JavaScript. Podes ver canto tempo tardou cada liña e cada instrución en "executar".
PostgreSQL Query Profiler: como combinar plan e consulta

E para que che sexa máis cómodo usar todo isto, fixemos almacenamento Arquivo, onde podes gardar e máis tarde atopar os teus plans xunto coas solicitudes asociadas ou compartir a ligazón con alguén.

Se só precisa traer unha consulta ilexible nunha forma adecuada, use o noso "normalizador".

PostgreSQL Query Profiler: como combinar plan e consulta

Fonte: www.habr.com

Engadir un comentario