Ordem de armazenamento versus ordem de resultado

8

Esta é uma pergunta derivada da ordem de classificação especificada na chave primária, mas a classificação é executada em SELECT .

@Catcall diz isso sobre o assunto da ordem de armazenamento (índice clusterizado) e da ordem de saída

Muitas pessoas acreditam que um índice em cluster garante uma ordem de classificação na saída. Mas não é isso que faz; garante uma ordem de armazenamento em disco. Veja, por exemplo, esta postagem no blog .

Eu li o post de Hugo Kornelis e entendo que um índice não garante que o servidor sql leia os registros em uma ordem específica. No entanto, tenho dificuldade em aceitar que não posso assumir isso para o meu cenário?

CREATE TABLE [dbo].[SensorValues](
  [DeviceId] [int] NOT NULL,
  [SensorId] [int] NOT NULL,
  [SensorValue] [int] NOT NULL,
  [Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED 
(
  [DeviceId] ASC,
  [SensorId] ASC,
  [Date] DESC
) WITH (
    FILLFACTOR=75,
    DATA_COMPRESSION = PAGE,
    PAD_INDEX = OFF,
    STATISTICS_NORECOMPUTE = OFF,
    SORT_IN_TEMPDB = OFF,
    IGNORE_DUP_KEY = OFF,
    ONLINE = OFF,
    ALLOW_ROW_LOCKS = ON,
    ALLOW_PAGE_LOCKS = ON)
  ON [MyPartitioningScheme]([Date])

Minha consulta original foi esta:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC

Mas sugiro que eu também possa usar este (leia abaixo para minha explicação):

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010

Como você pode ver, minhas linhas da tabela são pequenas (16 bytes) e eu tenho apenas um índice, um cluster. No meu cenário, a tabela consiste em 100.000.000 registros neste momento (e isso provavelmente aumentará dez vezes).

Quando o servidor de banco de dados consulta essa tabela, ele tem duas maneiras de encontrar minhas linhas: ele procura a chave primária e, assim, lê e retorna meus valores em desc. Data ou deve fazer uma verificação completa da tabela. Minha conclusão é que uma verificação completa da tabela em todos esses registros será muito lenta e, portanto, o servidor de banco de dados sempre buscará a tabela por meio de sua chave primária, retornando os valores classificados porDate DESC

m__
fonte
2
Por que você quer confiar tanto nessa suposição? Por que você simplesmente não coloca um ORDER BYlá, então você sabe que pode confiar nele. Veja o # 3 aqui
Aaron Bertrand
Por 2 razões, curiosidade e porque a ORDER BYcláusula é um grande desempenho para mim (leia a outra pergunta para obter mais informações). Eu tenho uma solução que funciona por enquanto, mas ela não funciona quando e se meu tráfego aumentar.
m__
11
ORDER BY não deve ser um sucesso de desempenho se você confiar na ordem que está vendo sem a ordem de - isso não faz sentido para mim.
Aaron Bertrand
4
A única coisa que garante a ordem do conjunto de resultados é uma ORDER BYcláusula na sua consulta. Isso é verdade para SQL Server , Oracle , MySQL e qualquer outro RDBMS que você possa imaginar. Tente qualquer outra coisa e você está se preparando para um copo surpresa de FAIL.
Nick Chammas

Respostas:

15

Deixe-me tentar explicar por que você não deve fazer isso, por que você nunca deve assumir que um produto SQL retornará um conjunto de resultados em uma ordem específica, a menos que você o especifique, quaisquer que sejam os índices - em cluster ou não em cluster, árvores B ou Árvores R ou árvores Kd ou árvores fractal ou quaisquer outros índices exóticos que um DBMS esteja usando.


Sua consulta original informa ao DBMS para pesquisar na SensorValuestabela, encontrar linhas que correspondam às 3 condições, ordenar essas linhas por Datedescida, manter apenas a primeira linha daquelas e - finalmente - selecionar e retornar apenas a SensorValuecoluna.

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date DESC ;

Essas são ordens muito específicas que você forneceu ao DBMS e o resultado provavelmente será o mesmo sempre que você executar a consulta (há uma chance de que não ocorra, se você tiver mais de uma linha que corresponda às condições e as mesmas máximo, Datemas diferente, SensorValuemas vamos supor, durante o restante da conversa, que essas linhas não existam na sua tabela).

O DBMS precisa fazer isso, para executar esta consulta, da maneira exata como a descrevi acima? Não, claro que não, e você sabe disso. Pode não ler a tabela, mas ler de um índice. Ou pode usar dois índices se achar melhor (mais rápido). Ou três. Ou pode usar um resultado em cache (não o SQL Server, mas outros resultados da consulta ao cache do DBMS). Ou pode usar a execução paralela uma vez e não na próxima vez em que é executada. Ou ... (adicione qualquer outro recurso que afeta a execução e os planos de execução).

O que é garantido é que ele retornará exatamente o mesmo resultado, toda vez que você o executar - desde que nenhuma linha seja inserida, excluída ou atualizada.


Agora vamos ver o que sua sugestão diz:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010 ;

Essa consulta informa ao DBMS para pesquisar na SensorValuestabela, encontrar linhas que correspondam às 3 condições, ordená-las por Datedescendente, não se importar com o pedido, manter apenas uma linha e, finalmente, selecionar e retornar apenas a SensorValuecoluna.

Portanto, basicamente diz o mesmo que o primeiro, exceto que diz que você deseja apenas um resultado que corresponda às condições e não se importa com qual deles .

Agora, podemos supor que ele sempre dará o mesmo resultado por causa do índice clusterizado?
- Se ele usar esse índice clusterizado toda vez, sim.

Mas será que vai usá-lo?
- Não.

Por que não?
- Porque pode. O otimizador de consulta é livre para escolher um caminho de execução sempre que executar uma instrução. Qualquer que seja o caminho que achar adequado naquele momento para essa afirmação.

Mas o uso do índice clusterizado não é a melhor / mais rápida maneira de obter resultados?
- Não, nem sempre. Pode ser a primeira vez que você executa a consulta. Na segunda vez, ele pode usar um resultado em cache (se o DBMS tiver esse recurso, não o SQL Server * ). A milésima vez que o resultado pode ter sido removido do cache e outro resultado pode existir lá. Digamos que você executou esta consulta imediatamente antes:

SELECT TOP 1 SensorValue
  FROM SensorValues
  WHERE SensorId = 53
    AND DeviceId = 3819
    AND Date < 1339225010
  ORDER BY Date ASC ;         --- Notice the `ASC` here

e o resultado em cache (da consulta acima) é outro, diferente, que ainda corresponde às suas condições, mas não é o primeiro em seu pedido (desejado). E você disse ao DBMS para não se importar com o pedido.

OK, então apenas o cache pode afetar isso?
- Não, muitas outras coisas também.

  • outros índices foram considerados, na época, pelo DBMS como melhores para esta consulta.
  • um desenvolvedor alterou ou removeu completamente esse índice em cluster que você tinha.
  • você ou algum outro desenvolvedor adicionou outro índice que o otimizador decidiu que é mais eficiente usar do que o IC.
  • você atualizou para uma nova versão e o novo otimizador apresenta um bug menor ou uma alteração na forma como classifica e escolhe os planos de execução.
  • as estatísticas foram atualizadas.
  • execução paralela foi escolhida.

*: O SQL Server não armazena em cache os resultados da consulta, mas o Enterprise Edition possui um recurso de Verificação avançada , que é semelhante à medida que você pode obter resultados diferentes devido a consultas simultâneas. Não tenho certeza exatamente quando isso entra em ação. (thnx @Martin Smith pela dica.)


Espero que você esteja convencido de que nunca deve confiar que uma consulta SQL retornará resultados em uma ordem específica, a menos que você o especifique. E nunca use TOP (n)sem ORDER BY, a menos que você queira apenas n linhas no resultado e não se importe com quais são retornadas.

ypercubeᵀᴹ
fonte
2
O SQL Server Enterprise Edition possui um recurso de Verificação avançada , que é semelhante, pois você pode obter resultados diferentes devido a consultas simultâneas. Não tenho certeza exatamente quando isso entra em ação.
Martin Smith
11
Outra coisa que potencialmente "randomiza" a ordem do conjunto de resultados (mesmo que a consulta seja aparentemente orientada por um índice ordenado) é o paralelismo. Vi um aplicativo que estava executando o SQL quebrado com êxito e começou a se comportar mal após ativar o paralelismo automático (não o SQL Server, mas acho que isso também pode ser aplicado).
Mat