简体   繁体   English

如何优化查询Postgres

[英]How to optimize query postgres

I am running the following query: 我正在运行以下查询:

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

But very slowly. 但是非常缓慢。 Here the Explain plan: http://explain.depesz.com/s/DnXH 这里是解释计划: http : //explain.depesz.com/s/DnXH

Try this rewritten version: 尝试以下重写版本:

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 syntax and sequence of joins JOIN语法和连接顺序

In particular I fixed the misleading LEFT JOIN to conciliacao_vendas , which is forced to act as a plain [INNER] JOIN by the later WHERE condition anyways. 特别是,我将误导性的LEFT JOIN修复为conciliacao_vendas ,无论如何,后者在后来的WHERE条件下都被迫充当普通的[INNER] JOIN This should simplify query planning and allow to eliminate rows earlier in the process, which should make everything a lot cheaper. 这将简化查询计划,并允许在过程的早期消除行,这将使所有内容便宜很多。 Related answer with detailed explanation: 相关答案及详细说明:

USING is just a syntactical shorthand. USING只是语法上的缩写。

Since there are many tables involved in the query and the order the rewritten query joins tables is optimal now, you can fine-tune this with SET LOCAL join_collapse_limit = 1 to save planning overhead and avoid inferior query plans. 由于查询中涉及许多表,并且重写查询联接表的顺序现在是最佳的,因此可以使用SET LOCAL join_collapse_limit = 1对其进行微调,以节省计划开销并避免劣等查询计划。 Run in a single transaction : 单个事务中运行:

BEGIN;
SET LOCAL join_collapse_limit = 1;
SELECT ...;  -- read data here
COMMIT;      -- or ROOLBACK;

More about that: 有关更多信息:

Index 指数

Add some indexes on lookup tables with lots or rows (not necessary for just a couple of dozens), in particular (taken from your query plan): 在具有很多行的查询表上添加一些索引(不需要几十个),特别是(从查询计划中获取):

Seq Scan on public.conta ct ... rows=6771 在public.conta ct上进行序列扫描... 行= 6771
Seq Scan on public.loja lj ... rows=1568 对public.loja lj进行Seq扫描... 行= 1568
Seq Scan on public.loja_extensao le ... rows=16394 在public.loja_extensao le上进行序列扫描... 行= 16394

That's particularly odd, because those columns look like primary key columns and should already have an index ... 这特别奇怪,因为这些列看起来像主键列 ,应该已经一个索引...

So: 所以:

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);

To make this really fat, a multicolumn index would be of great service: 为了使它真正发胖, 多列索引将很有用:

CREATE INDEX foo ON Table1 (parcela, data_venda, data_credito);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM