Dica NOLOCK altera a ordem dos registros retornados


11

Há um índice em cluster em um Clientcampo da tabela LastName.

Quando simplesmente despejo todos os registros da tabela, eles aparecem em ordem alfabética, a menos que (nolock)seja usada uma dica como na consulta em questão. Essa dica altera a ordem dos registros. Deveria?. Tenho certeza de que nenhuma outra sessão tem uma transação aberta com as alterações nessa tabela (pelo menos sp_who2não está me mostrando nenhuma).

Como a diferença na ordem pode ser explicada?

Informações adicionais extraídas dos comentários:

  1. Não há ordem por. O índice não agrupado deve impor a ordem?

  2. As consultas ainda retornam ordem diferente, mesmo ao usar uma dica de índice que especifica um índice em cluster. Eles deveriam? Estou me perguntando por que nolockaltera a ordem dos registros retornados sem uma alteração visível dos planos.

  3. Eu fiz um WinDiff neles - o mesmo, exceto [a] (nolock)[dica de consulta].


21
A dica não alterar a ordem - porque não há uma ordem que poderia ser mudado
a_horse_with_no_name

Respostas:


47

A aparência de um conjunto de resultados ordenados, sem uma ORDER BYcláusula, geralmente resulta de uma varredura que recupera linhas na ordem do índice. Uma razão pela qual uma varredura por ordem de índice geralmente é escolhida no READ COMMITTEDnível de isolamento padrão é que reduz as chances de anomalias de simultaneidade indesejadas, como encontrar a mesma linha várias vezes ou ignorar algumas linhas por completo. Isso é detalhado em vários lugares, incluindo nesta série de artigos sobre níveis de isolamento.

Com uma NOLOCKdica de tabela, esse comportamento é relaxado e o acesso à tabela é realizado no READ UNCOMMITTEDnível de isolamento mais tolerante , que pode verificar os dados na ordem de alocação, em vez da ordem do índice. Conforme descrito nesse link, a decisão sobre o uso de uma varredura de ordem de alocação ou ordem de índice é deixada para o mecanismo de armazenamento. Essa opção pode mudar entre execuções sem uma alteração no plano de consulta .

Isso pode parecer muito abstrato, mas pode ser demonstrado com mais facilidade com algumas consultas usando funções não documentadas no banco de dados AdventureWorks2012 .

USE AdventureWorks2012;
GO
-- Appears to be ordered by BusinessEntityID
-- File:Page:Slot goes up and down several times
-- Show physical locations with sys.fn_PhysLocFormatter (undocumented)
SELECT
    P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P;

-- Same query with TABLOCK or NOLOCK
-- Allocation-order (IAM) scan
-- Now appears to be ordered by File:Page:Slot instead of BusinessEntityID
SELECT P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P WITH (NOLOCK);

Resultados da consulta

As consultas são emprestadas com uma leve modificação de Paul White .

Finalmente, só para esclarecer, esta resposta é sobre a aparência de um conjunto de resultados ordenados. Não há ordem de apresentação garantida sem um nível superior ORDER BY.

Uma varredura da ordem de alocação pode ocorrer em várias outras circunstâncias, como quando um bloqueio no nível da tabela é adquirido ou o banco de dados está no modo somente leitura. O paralelismo também pode influenciar a ordem em que os dados são retornados. O ponto principal é que ORDER BY, sem eles , os dados de ordem retornados podem variar ao longo do tempo por design.


7
Legal, muito mais específico do que minha tentativa não apreciada. O ponto crucial está em seus dois últimos parágrafos, é claro. "Por que" realmente não importa no final. Talvez você tenha mais sorte em tocar esse acorde do que eu.
Aaron Bertrand

12

Quando simplesmente despejo todos os registros da tabela

... então você não deve esperar nenhum pedido. De fato, a mesma consulta executada várias vezes pode voltar em uma ordem diferente sem aviso. O motivo é que suas duas consultas - que são "diferentes", provavelmente por causa do texto da consulta, não por causa da dica - têm planos de execução diferentes (e a diferença pode ser sutil, como um iterador com a mesma aparência em ambos os planos, mas possui ordered: trueapenas um ou um número muito diferente de linhas estimadas porque uma foi compilada antes de uma grande alteração de dados). Também pode ser que uma verificação de ordem de alocação esteja sendo realizada, como James descreveu corretamente em sua resposta.

De qualquer forma, como você está executando uma consulta sem ORDER BY, o SQL Server deduz que você não se importa com a ordem e, portanto, dispara e determina a maneira mais eficiente de retornar as linhas (não se importa com a ordem, se você não )

Deixe-me deixar isso bem claro:

Se você deseja ou espera um determinado pedido, adicione uma cláusula ORDER BY

Isso já ocorreu antes:

E eu escrevi sobre isso:

Aqui está uma citação deste último que reitera o que eu disse para abordar seu comentário sobre o uso de uma dica de índice em vez de uma ORDER BYcláusula:

Mesmo no caso de um índice sugerido, o índice será usado (se possível, senão um erro na maioria dos casos), mas apenas porque o índice é usado não significa que os resultados serão retornados classificados pela (s) chave (s) em esse índice. Você ainda precisa de um ORDER BYpara garantir a classificação pelas chaves de índice.

Conor Cunningham - um cara muito inteligente, diretamente responsável por muito do que o SQL Server faz quando processa uma consulta para você - também publicou um blog sobre isso aqui:

Faça algumas leituras e adicione uma ORDER BYcláusula às suas perguntas antes de reclamar sobre uma classificação diferente ou inesperada.


11

James explicou bem como isso funciona, mas eu gostaria de reiterar uma coisa: a menos que você use uma função de ordenação, a ordem das linhas no conjunto de resultados é indefinida . Se você precisar de uma determinada ordem, use uma order bycláusula explícita - se você não a especificar, estará basicamente dizendo "Não me importo com a ordem", e não "Ordená-la pelo índice de cluster".

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.