Comment optimiser la requête postgres
-
21-12-2019 - |
Question
Je suis en cours d'exécution de la requête suivante:
SELECT fat.*
FROM Table1 fat
LEFT JOIN modo_captura mc ON mc.id = fat.modo_captura_id
INNER JOIN loja lj ON lj.id = fat.loja_id
INNER JOIN rede rd ON rd.id = fat.rede_id
INNER JOIN bandeira bd ON bd.id = fat.bandeira_id
INNER JOIN produto pd ON pd.id = fat.produto_id
INNER JOIN loja_extensao le ON le.id = fat.loja_extensao_id
INNER JOIN conta ct ON ct.id = fat.conta_id
INNER JOIN banco bc ON bc.id = ct.banco_id
LEFT JOIN conciliacao_vendas cv ON fat.empresa_id = cv.empresa_id AND cv.chavefato = fat.chavefato AND fat.rede_id = cv.rede_id
WHERE 1 = 1
AND cv.controle_upload_arquivo_id = 6906
AND fat.parcela = 1
ORDER BY fat.data_venda, fat.data_credito limit 20
Mais très lentement.Ici, le plan d'Expliquer: http://explain.depesz.com/s/DnXH
La solution
Essayez cette version réécrite:
SELECT fat.*
FROM Table1 fat
JOIN conciliacao_vendas cv USING (empresa_id, chavefato, rede_id)
JOIN loja lj ON lj.id = fat.loja_id
JOIN rede rd ON rd.id = fat.rede_id
JOIN bandeira bd ON bd.id = fat.bandeira_id
JOIN produto pd ON pd.id = fat.produto_id
JOIN loja_extensao le ON le.id = fat.loja_extensao_id
JOIN conta ct ON ct.id = fat.conta_id
JOIN banco bc ON bc.id = ct.banco_id
LEFT JOIN modo_captura mc ON mc.id = fat.modo_captura_id
WHERE cv.controle_upload_arquivo_id = 6906
AND fat.parcela = 1
ORDER BY fat.data_venda, fat.data_credito
LIMIT 20;
La syntaxe de JOINTURE et la séquence de la rejoint
En particulier, j'ai fixé la trompeuse LEFT JOIN
pour conciliacao_vendas
, qui est forcé d'agir comme une plaine [INNER] JOIN
par le plus tard WHERE
condition de toute façon.Cela devrait simplifier la requête de la planification et permettent d'éliminer les lignes plus tôt dans le processus, ce qui devrait rendre les choses beaucoup moins cher.Réponse similaire avec explication détaillée:
USING
est juste une syntaxe abrégée.
Car il y a beaucoup de tables impliquées dans la requête et de l'ordonnance de la requête réécrite joint des tables est optimal maintenant, vous pouvez affiner ce avec SET LOCAL join_collapse_limit = 1
pour enregistrer la planification de frais généraux et d'éviter inférieure plans de requête.Exécuter dans un seule transaction:
BEGIN;
SET LOCAL join_collapse_limit = 1;
SELECT ...; -- read data here
COMMIT; -- or ROOLBACK;
Plus à ce sujet:
- Exemple de Requête pour afficher l'estimation de Cardinalité d'erreur dans PostgreSQL
- L'amende manuel sur Le contrôle de l'agenda avec Clauses de JOINTURE Explicite
Index
Ajouter quelques indices sur les tables de recherche avec des lots ou des lignes (pas nécessaire pour seulement quelques dizaines), en particulier (prises à partir de votre plan de requête):
Seq Scan sur le public.conta ct ... rows=6771
Seq Scan sur le public.loja lj ... rows=1568
Seq Scan sur le public.loja_extensao le ... rows=16394
C'est particulièrement étrange, parce que ces colonnes ressembler colonnes de clé primaire et devrait déjà ont un indice ...
Donc:
CREATE INDEX conta_pkey_idx ON public.conta (id);
CREATE INDEX loja_pkey_idx ON public.loja (id);
CREATE INDEX loja_extensao_pkey_idx ON public.loja_extensao (id);
Pour faire ce vraiment fat, un index multicolonne serait d'un grand service:
CREATE INDEX foo ON Table1 (parcela, data_venda, data_credito);