如何优化 postgres 查询
-
21-12-2019 - |
题
我正在运行以下查询:
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
但非常缓慢。这里是解释计划: http://explain.depesz.com/s/DnXH
解决方案
尝试这个重写版本:
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;
JOIN 语法和连接顺序
特别是我修复了 误导性的 LEFT JOIN
到 conciliacao_vendas
, ,它被迫充当普通 [INNER] JOIN
由后来的 WHERE
无论如何条件。这应该会简化查询规划,并允许在过程的早期消除行,这将使一切变得更便宜。相关答案及详细解释:
USING
只是语法简写。
由于查询涉及很多表,并且重写的查询连接表的顺序现在是最佳的,因此您可以使用以下命令对此进行微调 SET LOCAL join_collapse_limit = 1
以节省计划开销并避免较差的查询计划。运行在一个 单笔交易:
BEGIN;
SET LOCAL join_collapse_limit = 1;
SELECT ...; -- read data here
COMMIT; -- or ROOLBACK;
更多相关内容:
指数
在包含大量或行的查找表上添加一些索引(对于几十行来说不需要),特别是(取自查询计划):
对 public.conta ct 进行顺序扫描 ... 行=6771
对 public.loja lj 进行序列扫描 ... 行=1568
对 public.loja_extensao 文件进行 Seq 扫描 ... 行=16394
这特别奇怪,因为这些列看起来像 主键列 并且应该已经 有 一个索引...
所以:
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);
为了让这个真的很胖, 多列索引 会有很大的服务:
CREATE INDEX foo ON Table1 (parcela, data_venda, data_credito);
不隶属于 StackOverflow