É REALMENTE possível que o pedido não seja garantido para esta tabela derivada redundante específica?

12

Eu me deparei com essa pergunta em uma conversa no Twitter com Lukas Eder .

Embora o comportamento correto seja aplicar a cláusula ORDER BY na consulta mais externa, porque, aqui, não estamos usando DISTINCT, GROUP BY, JOIN ou qualquer outra cláusula WHERE na consulta mais externa, por que um RDBMS não passaria o dados recebidos como foram classificados pela consulta interna?

SELECT * 
FROM (
    SELECT * FROM table ORDER BY time DESC
) AS t

Ao executar este exemplo no PostgreSQL, pelo menos, você obtém o mesmo Plano de Execução para a consulta interna e para o exemplo da tabela derivada, além do mesmo conjunto de resultados.

Portanto, suponho que o Planejador simplesmente descarte a consulta mais externa porque é redundante ou simplesmente passa pelos resultados da tabela interna.

Alguém acha que isso pode não ser o caso?

Vlad Mihalcea
fonte
4
Observe que sua consulta falhará no SQL Server porque uma ordem de não é permitida dentro de uma tabela derivada.
A_horse_with_no_name 23/08
Por que você é tão incrédulo? Por que você assumiria alguma coisa? Quando você escreve um programa que lhe deixa uma escolha, espera que os usuários esperem coisas sobre sua escolha? Leia sobre otimização / implementação de consultas lógicas e físicas.
precisa saber é o seguinte
2
"Eu diria que o planejador simplesmente descartará a consulta mais externa porque é redundante ou simplesmente passa pelos resultados da tabela interna". Você poderia facilmente assumir que o planejador descartará a cláusula de pedido na consulta interna porque não faz sentido no contexto.
Wildcard
MariaDB, sobre 2012, discute a questão. Falta doORDER BYleadinternopara otimização diferente para máx . Em grupo
Rick James
1
Na verdade, você está certo no Postgres.
Erwin Brandstetter

Respostas:

20

A maioria dos bancos de dados é bastante clara sobre o fato de que uma ORDER BYsubconsulta é:

  • Não permitido: por exemplo, SQL Server, Sybase SQL Anywhere (a menos que seja complementado com TOPou OFFSET .. FETCH)
  • Sem sentido: por exemplo, PostgreSQL, DB2 (novamente, a menos que seja complementado com OFFSET .. FETCHou LIMIT)

Aqui está um exemplo do manual do DB2 LUW (ênfase minha)

Uma cláusula ORDER BY em uma subseleção não afeta a ordem das linhas retornadas por uma consulta. Uma cláusula ORDER BY afeta apenas a ordem das linhas retornadas se for especificada na seleção completa mais externa.

A redação é bastante explícita, assim como no PostgreSQL :

Se a classificação não for escolhida, as linhas serão retornadas em uma ordem não especificada. A ordem real nesse caso dependerá dos tipos de plano de varredura e associação e da ordem no disco, mas não deve ser invocada . Uma ordem de saída específica só pode ser garantida se a etapa de classificação for escolhida explicitamente.

A partir dessa especificação, pode-se concluir que qualquer pedido resultante da ORDER BYcláusula em uma tabela derivada é meramente acidental e pode coincidir com o pedido esperado (o que ocorre na maioria dos bancos de dados em seu exemplo trivial), mas não seria prudente confiar em isto.

Nota lateral no DB2:

Em particular, o DB2 possui um recurso menos conhecido chamadoORDER BY ORDER OF <table-designator> , que pode ser usado da seguinte maneira:

SELECT C1 FROM
   (SELECT C1 FROM T1
      UNION
    SELECT C1 FROM T2
    ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE

Nesse caso em particular, a ordem da tabela derivada pode ser explicitamente reutilizada na classe SELECT mais externa.

Nota lateral no Oracle:

Durante anos, é uma prática do Oracle implementar a OFFSETpaginação usando ROWNUM, que só pode ser calculada razoavelmente após o pedido de uma tabela derivada:

SELECT *
FROM (
  SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
  FROM (
    SELECT * FROM table ORDER BY time DESC
  ) t
) t
WHERE rn BETWEEN 10 AND 20

Pode-se razoavelmente esperar que, pelo menos na presença de ROWNUMuma consulta, as futuras versões do Oracle não quebrem esse comportamento para não quebrar praticamente todo o Oracle SQL herdado, que ainda não migrou para o muito mais desejável e OFFSET .. FETCHsintaxe padrão legível do SQL :

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
Lukas Eder
fonte
Meaningless: E.g. PostgreSQLrealmente deve ser: 'confiável', porque ele faz significar alguma coisa. As linhas são classificadas na consulta interna e essa ordem é mantida em níveis de consulta externos, a menos que seja instruído de outra forma ou que seja reordenado oportuno para operações adicionais. Mesmo que seja apenas um detalhe de implementação, não faz sentido. Isso pode ser usado para entrada classificada para agregar funções. Os mesmo dicas manuais como muito: Alternatively, supplying the input values from a sorted subquery will usually work.
Erwin Brandstetter
A citação que você adicionou para o Postgres realmente se aplica a um caso diferente: consultas sem nenhuma ORDER BY.
Erwin Brandstetter
@ ErwinBrandstetter: fique à vontade para adicionar uma resposta com esses detalhes. Pessoalmente, não concordo que os detalhes da implementação sejam significativos. Ainda hoje, eu aprendi que, antigamente, as pessoas contavam com a Oracle sempre executando um grupo classificado por operação no Oracle 8i (acredito), quando, de repente, uma versão mais recente introduziu o hash group by, o que quebrou a suposição de que algumas implícitas a ordem poderia ser invocada. Em outras palavras: eu gosto de colocar em negrito. Sentido , em vez de oh se você sabe os detalhes intricados da versão xyz, você pode realmente ...
Lukas Eder
Eu já adicionei uma resposta. Se optamos por ignorar o comportamento fora do padrão ou que outro bom conselho que temos está fora de questão: a ordem é garantida para a consulta especificada? É para o Postgres. Não é (ou nem aplicável) para outros RDBMS. E isso se aplica a todas as versões existentes do Postgres, não apenas à versão xyz. É até documentado (com reservas). Sua cotação é enganosa. Se queremos ignorar o comportamento fora do padrão, podemos começar com o Oracle nos fazendo acreditar que NULL e a string vazia são iguais. Também ortogonal à pergunta.
Erwin Brandstetter
@ ErwinBrandstetter: Interessante, obrigado pela atualização. Esta garantia a que você está se referindo está documentada?
Lukas Eder
12

Sim. Sem uma ORDER BYcláusula, a ordem de saída é indefinida e o planejador de consultas está dentro do seu alcance para assumir que você sabe e entende isso.

Ele pode decidir que, como a consulta externa não especifica uma ordem, ela pode descartar a ordem na consulta interna para evitar uma operação de classificação, especialmente se não houver um índice clusterizado ou nenhum índice para dar suporte à ordem. Se não o fizer agora , poderá funcionar em versões futuras.

Nunca confie em comportamento indefinido. Se você precisar de um pedido específico, forneça uma ORDER BYcláusula no local apropriado.

David Spillett
fonte
Ao testá-lo no PostgreSQL, a classificação foi feita após uma varredura seqüencial, pois não havia nenhum índice na coluna usada pelo ORDER BY. Qual RDBMS você acha que ignorará a consulta interna ORDER BY?
Vlad Mihalcea
5
Não posso dizer que sei o que será , apenas que todos eles são perfeitamente livres para fazê-lo, se assim o desejarem - seria uma otimização perfeitamente aceitável de acordo com os padrões gerais e as especificações do produto. O SQL Server rejeitará a consulta totalmente (a menos que você inclua, TOP 100%para que a consulta atual não seja portátil, isso deve ser uma prioridade para o seu projeto. Como o Postgres obedece à ordem na consulta interna agora não significa que sempre será no futuro (ou que versões mais antigas, de fato), assim você deve evitar depender do comportamento apenas no caso.
David Spillett
1
@VladMihalcea um DBMS que "otimiza" o redundante ORDER BYé MariaDB: Por que ORDER BY em uma subconsulta FROM é ignorado?
precisa saber é o seguinte
6

É o mesmo problema de comportamento indefinido - funciona para você, funciona para mim, reformata o HDD em prod;)

Podemos dar um passo atrás e dizer que, em certo sentido, você está certo - não há razão terrena para que um RDBMS sano reorganize as linhas na seleção interna. Mas isso não é garantido - o que significa que, no futuro, pode haver uma razão, e os fornecedores são livres para fazê-lo. Significando que qualquer código que se baseia nesse comportamento está à mercê de uma alteração que um fornecedor poderia fazer e que não teria obrigação de divulgar, pois não é uma alteração de quebra de um API POV.

PaulJWilliams
fonte
2
A única razão pela qual ele pode otimizar o pedido é a velocidade. Retornar as linhas em uma ordem diferente pode ser mais eficiente.
TomTom
2
Em particular, o servidor pode explorar o paralelismo para ler a tabela. Se isso acontecer, e não há necessidade de impor um pedido, você receberá as linhas de volta, no entanto, as threads as lerão. (SQL Server realmente faz isso, de modo que um SELECTsem ORDER BYrealmente é não determinística, e não apenas na teoria ou porque os dados alterados.)
Jeroen Mostert
@JeroenMostert: O comportamento indefinido só piora. O que acontece se estiver fora de ordem e o delta foi usado para indexar em uma matriz?
27417 Joshua
2

É REALMENTE possível que o pedido não seja garantido para esta tabela derivada redundante específica?

A resposta para todas as versões existentes do Postgres (que você estava testando) é: Não - para esta consulta específica. A ordem de classificação é garantida.

O pessoal do servidor SQL ficará desconfortável com isso, pois a Microsoft nem permite ORDER BYsubconsultas. No entanto, a ordem de classificação é garantida para essa consulta simples no Postgres. ORDER BYé aplicado na subconsulta e a consulta externa não faz nada que possa alterar a ordem.

O manual até sugere isso no capítulo Funções agregadas :

Como alternativa, fornecer os valores de entrada de uma subconsulta classificada geralmente funcionará.

Observe que isso é verdade apenas enquanto os níveis de consulta externa não adicionam operações que podem alterar a ordem. Portanto, é apenas "garantido" para o caso simples, e isso não é suportado pelo padrão SQL. O Postgres pode reordenar se for oportuno para operações adicionais. Em caso de dúvida, adicione outro ORDER BYao exterior SELECT. (Nesse caso, o interior ORDER BYseria um ruído redundante para esta consulta simples.)

Erwin Brandstetter
fonte
É verdade quando "table"não é uma tabela base simples, mas uma visão complexa ou uma tabela particionada? É verdade quando o plano também tem execução paralela? Também é verdade no Postgres 10? (Eu só estou pedindo, eu não tenho certeza que a resposta de qualquer destas perguntas.)
ypercubeᵀᴹ
@ ypercubeᵀᴹ: Eu não testei o Postgres 10 para todos estes, mas tenho certeza de que é verdade em qualquer caso. A ordem é aplicada e não alterada na consulta externa para o caso simples.
Erwin Brandstetter