Com o Postgres 9.4, estou fazendo a seguinte consulta com bastante frequência:
SELECT DISTINCT ON(recipient) * FROM messages
LEFT JOIN identities ON messages.recipient = identities.name
WHERE timestamp BETWEEN timeA AND timeB
ORDER BY recipient, timestamp DESC;
Então resolvi criar uma view:
CREATE VIEW myView AS SELECT DISTINCT ON(recipient) * FROM messages
LEFT JOIN identities ON messages.recipient = identities.name
ORDER BY recipient, timestamp DESC;
Acabei de perceber que, se consultar minha visão SELECT * FROM myView WHERE timestamp BETWEEN timeA AND timeB
, obterei um desempenho significativamente pior.
Fazendo EXPLAIN ANALYZE
em ambas as consultas, descobri que o motivo é que o banco de dados no segundo caso traz todos os registros, faz a junção à esquerda e aplica a WHERE
cláusula. Em outras palavras, a WHERE
cláusula não é inserida na consulta da exibição. Também tentei remover o ORDER BY
da exibição, mas ainda assim o banco de dados executa os LEFT JOIN
dados completos em vez do conjunto filtrado.
Qual é a razão deste comportamento? Existe uma maneira de obter um desempenho comparável ao usar a visualização?
Esta consulta:
diz:
Esta consulta (que você obteria se usasse a visualização):
diz:
Como resultado, a primeira consulta mostrará as mensagens que estão entre o horário A e B e a segunda consulta não mostrará (porque pode haver uma ou mais mensagens para o mesmo destinatário, posteriores ao horário B).
Portanto, as consultas são logicamente diferentes e a condição não pode (e não deve) ser pressionada para sua exibição.
Se você deseja que os parâmetros sejam passados para sua exibição, consulte as duas respostas (por @a_horse_with_no_name e @Erwin Brandstetter ) nesta pergunta para saber como usar uma função de retorno definida : Passar os parâmetros “WHERE” para a exibição do PostgreSQL?
Você pode criar uma função como esta;
Então você pode usar a função como uma tabela