USING construir na cláusula JOIN pode introduzir barreiras de otimização em certos casos?

35

Fui informado de que a USINGconstrução (em vez de ON) na FROMcláusula de SELECTconsultas pode introduzir barreiras de otimização em certos casos.

Quero dizer esta palavra-chave:

SELECT *
A partir de um
JUNTE-SE A USAR (a_id)

Apenas em casos mais complexos.

Contexto: este comentário a esta pergunta .

Eu uso muito isso e nunca notei nada até agora. Eu ficaria muito interessado em um caso de teste demonstrando o efeito ou quaisquer links para mais informações. Meus esforços de pesquisa ficaram vazios.

A resposta perfeita seria um caso de teste para mostrar USING (a_id)com desempenho inferior quando comparado à cláusula de junção alternativa ON a.a_id = b.a_id- se isso realmente acontecer.

Erwin Brandstetter
fonte
2
@kgrittn: É o que eu geralmente esperava até agora: isso USINGé um pouco mais rápido - pois resulta em uma coluna a menos na matriz de resultados. Suas descobertas datam de 2005 e 2008. Suponho que todos os problemas foram corrigidos até agora. No entanto , vejo uma possível limitação: JOINs com USINGpode ter que ser aplicado em ordem , pois a coluna de junção resultante é um produto conjunto. Assim, potencialmente limitando opções na reordenação de JOINs.
precisa saber é o seguinte
1
Eu encontrei este tópico que pode ter algo a ver com me impedir de usá-lo tantas vezes quanto eu, porque uma VIEW com uma condição USING em uma junção pode causar problemas no dump / restore: archives.postgresql.org/pgsql- bugs / 2011-06 / msg00030.php Eu ainda tenho uma sensação incômoda de que havia outro thread relacionado a problemas de desempenho com USING, onde a solução alternativa era usar ON, mas eu vou desistir de encontrá-lo, eu acho. Provavelmente é seguro usá-lo fora dos modos de exibição e lembre-se de tentar ON como uma etapa de diagnóstico, se a consulta for lenta.
kgrittn
1
Parece que "using" torna o código um pouco legível, mas acho que os dois campos precisam do mesmo nome. Eu não acho que o uso tenha um desempenho melhor do que um "on", porque o DB precisa fazer a correspondência de qualquer maneira, é como se um select tivesse o mesmo desempenho que uma junção (me corrija se eu estiver errado), o A diferença é que o Join é mais limpo e fácil de manter.
Jcho360 # 8/12
2
@HLGEM: É apenas um nome simbólico e, com apenas duas tabelas, como no meu exemplo, não há espaço para confusão. Ainda assim, eu alterei a pergunta. Não gostaria de incentivar o uso infeliz de idcomo nome da coluna.
Erwin Brandstetter
2
@ChristiaanWesterbeek: Eu discordo. O "local ideal" para a resposta mais profunda do Postgres é (ainda) a correspondência. Apenas muito poucos desenvolvedores do Postgres estão ativos no SO, mas todos os desenvolvedores e especialistas do Postgres leem a lista de discussão
a_horse_with_no_name

Respostas:

12

Erwin: Concordo com a idéia de que USAR causando pedidos rígidos poderia criar muitos casos extremos onde os planos ideais seriam descartados. Recentemente, ajudei alguém que tinha algo parecido com isso em sua consulta:

LEFT JOIN ( 
     a 
     JOIN b ON a.id = b.a_id
     JOIN c ON b.c_id = c.id
) ON a.id = something.a_id
LEFT JOIN (
     table1 t1
     JOIN table2 t2 ON t1.some_field = t2.other_field
     JOIN talbe3 t3 ON t2.yafield = t3.something_else
) ON ....
repeat a few more times

No caso dele, o pior desses blocos de junção estava causando uma junção de loop aninhada por cerca de 200 mil linhas, cerca de 20 mil vezes (faça as contas) e, como as chaves não podiam ser pressionadas para os índices, era uma varredura seqüencial. Isso significava que a consulta geral levou cerca de 3 horas para ser executada devido a alterações no plano em cascata. Ao distribuir a junção esquerda, as teclas podem ser pressionadas e a consulta é executada em questão de segundos. É claro que isso não é exatamente equivalente, e é por isso que o planejador não pode tratá-los como equivalentes e, por isso, ficou imaginando esse plano como uma junção de hash e depois fazendo um loop aninhado, o que era dolorosamente lento.

Sempre que você força rigidamente as junções a serem executadas em uma determinada ordem, você introduz casos em que as principais informações do filtro ainda não estão disponíveis na execução do plano e, portanto, o que pode ser possível fazer posteriormente em uma rápida verificação de índice / junção de hash pode ser necessário ser muito mais lento em uma varredura aninhada / loop aninhada e, embora o fragmento acima não seja imediatamente equivalente, ele mostra o mesmo problema.

Chris Travers
fonte