Estou com um problema no planejamento de consultas do PostgreSQL 9.6. Minha consulta é assim:
SET role plain_user;
SELECT properties.*
FROM properties
JOIN entries_properties
ON properties.id = entries_properties.property_id
JOIN structures
ON structures.id = entries_properties.entry_id
WHERE structures."STRUKTURBERICHT" != ''
AND properties."COMPOSITION" LIKE 'Mo%'
AND (
properties."NAME" LIKE '%VASP-ase-preopt%'
OR properties."CALCULATOR_ID" IN (7,22,25)
)
AND properties."TYPE_ID" IN (6)
Eu tenho a segurança em nível de linha ativada para as tabelas usadas acima.
com
set enable_nestloop = True
, o planejador de consultas executa a junção de loop aninhado com um tempo total de execução de aproximadamente 37 segundos: https://explain.depesz.com/s/59BRcom
set enable_nestloop = False
, o método Hash Join é usado e o tempo de consulta é de cerca de 0,3 segundos: https://explain.depesz.com/s/PG8E
Eu fiz VACUUM ANALYZE
antes de executar as consultas, mas não ajudou.
Sei que não é uma boa prática set enable_nestloop = False
e outras opções semelhantes para o planejador. Mas como "convencer" o planejador a usar junções de hash sem desativar os loops aninhados?
Reescrever a consulta é uma opção.
Se eu executar a mesma consulta em uma função que ignora o RLS, ela será executada muito rapidamente. A política de segurança em nível de linha é semelhante a esta:
CREATE POLICY properties_select
ON properties
FOR SELECT
USING (
(
properties.ouid = get_current_user_id()
AND properties.ur
)
OR (
properties.ogid in (select get_current_groups_id())
AND properties.gr
)
OR properties.ar
);
Todas as idéias ou sugestões serão muito apreciadas.
fonte
AND properties."TYPE_ID" IN (6);
e não= 6;
?Respostas:
O que está acontecendo aqui é que o Nested Loop está muito distante de um lado. Loops aninhados funcionam muito bem quando um lado é muito pequeno, como retornar uma linha. Na sua consulta, o planejador se atrapalha aqui e estima que uma Hash Join retornará apenas uma linha. Em vez disso, essa Hash Join (property_id = id) retorna 1.338 linhas. Isso força 1.338 loops a serem executados no outro lado do loop aninhado, que já possui 3.444 linhas. Isso é demais quando você está esperando apenas um (o que não é nem um "loop"). Enfim ..
Um exame mais aprofundado à medida que avançamos mostra que o Hash Join é realmente influenciado pelas estimativas decorrentes disso,
O PostgreSQL espera que retorne uma linha. Mas isso não acontece. E esse é realmente o seu problema. Portanto, algumas opções aqui, que não envolvem tirar uma marreta e desativar
nested_loop
Você pode adicionar um índice ou dois para
properties
ajudá-lo a ignorar a verificação seq, ou estimar melhor o retorno.Como alternativa, você pode mover o material das propriedades para um CTE ou subselecionar com o
OFFSET 0
qual cria uma cerca.fonte