Database
 sql >> Base de Dados >  >> RDS >> Database

SQL ORDER BY:os 5 prós e contras para classificar dados como um profissional


Feio. É assim que os dados não classificados se parecem. Tornamos os dados fáceis para os olhos, classificando-os. E é para isso que serve o SQL ORDER BY. Use uma ou mais colunas ou expressões como base para classificar os dados. Em seguida, adicione ASC ou DESC para classificar em ordem crescente ou decrescente.

A sintaxe SQL ORDER BY:
ORDER BY <order_by_expression> [ASC | DESC]


A expressão ORDER BY pode ser tão simples quanto uma lista de colunas ou expressões. Também pode ser condicional usando um bloco CASE WHEN.

É muito flexível.

Você também pode usar a paginação por meio de OFFSET e FETCH. Especifique o número de linhas a serem ignoradas e as linhas a serem exibidas.

Mas aqui está a má notícia.

Adicionar ORDER BY às suas consultas pode deixá-las mais lentas. E algumas outras advertências podem fazer ORDER BY “não funcionar”. Você não pode usá-los sempre que quiser, pois pode haver penalidades. Então, o que fazemos?

Neste artigo, examinaremos os prós e contras ao usar ORDER BY. Cada item lidará com um problema e uma solução se seguirá.

Preparar?

O que fazer no SQL ORDER BY

1. Indexe a(s) coluna(s) SQL ORDER BY


Índices são sobre pesquisas rápidas. E ter um nas colunas que você usa na cláusula ORDER BY pode acelerar sua consulta.

Vamos começar a usar ORDER BY em uma coluna sem índice. Usaremos o AdventureWorks banco de dados de exemplo. Antes de executar a consulta abaixo, desative o IX_SalesOrderDetail_ProductID índice no SalesOrderDetail tabela. Em seguida, pressione Ctrl-M e executá-lo.

-- Get order details by product and sort them by ProductID

USE AdventureWorks
GO

SET STATISTICS IO ON
GO

SELECT
 ProductID
,OrderQty
,UnitPrice
,LineTotal
FROM Sales.SalesOrderDetail
ORDER BY ProductID

SET STATISTICS IO OFF
GO

ANÁLISE


O código acima produzirá as estatísticas de E/S na guia Mensagens do SQL Server Management Studio. Você verá o plano de execução em outra guia.
SEM UM ÍNDICE

Primeiro, vamos obter as leituras lógicas do STATISTICS IO. Confira a Figura 1.

Figura 1 . Lê lógicas usando ORDER BY de uma coluna não indexada. (Formatado usando statisticsparser.com )

Sem o índice, a consulta usou 1.313 leituras lógicas. E essa WorkTable ? Isso significa que o SQL Server usou TempDB para processar a classificação.

Mas o que aconteceu nos bastidores? Vamos inspecionar o plano de execução na Figura 2.

Figura 2 . Plano de execução de uma consulta usando ORDER BY de uma coluna não indexada.

Você viu o operador Paralelismo (Gather Streams)? Isso significa que o SQL Server usou mais de 1 processador para processar essa consulta. A consulta era pesada o suficiente para exigir mais CPUs.

Então, e se o SQL Server usasse TempDB e mais processadores? É ruim para uma consulta simples.
COM UM ÍNDICE

Como será se o índice for reativado? Vamos descobrir. Reconstrua o índice IX_SalesOrderDetail_ProductID . Em seguida, execute novamente a consulta acima.

Verifique as novas leituras lógicas na Figura 3.

Figura 3 . Novas leituras lógicas após a reconstrução do índice.

Isto é muito melhor. Reduzimos o número de leituras lógicas quase pela metade. Isso significa que o índice fez com que consumisse menos recursos. E a Tabela de Trabalho ? Foi-se! Não há necessidade de usar TempDB .

E o plano de execução? Consulte a Figura 4.

Figura 4 . O novo plano de execução é mais simples quando o índice foi reconstruído.

Ver? O plano é mais simples. Não há necessidade de CPUs extras para classificar as mesmas 121.317 linhas.

Portanto, a conclusão é:Certifique-se de que as colunas que você usa para ORDER BY estejam indexadas .

MAS E SE ADICIONAR UM ÍNDICE IMPACTAR O DESEMPENHO DE ESCRITA?

Boa pergunta.

Se esse for o problema, você pode despejar uma parte da tabela de origem em uma tabela temporária ou tabela com otimização de memória . Em seguida, indexe essa tabela. Use o mesmo se mais tabelas estiverem envolvidas. Em seguida, avalie o desempenho da consulta da opção escolhida. A opção mais rápida será a vencedora.

2. Limite os resultados com WHERE e OFFSET/FETCH


Vamos usar uma consulta diferente. Digamos que você precise exibir informações do produto com fotos em um aplicativo. As imagens podem tornar as consultas ainda mais pesadas. Portanto, não apenas verificamos leituras lógicas, mas também lob leituras lógicas.

Aqui está o código.
SET STATISTICS IO ON
GO

SELECT
 a.ProductID
,a.Name AS ProductName
,a.ListPrice
,a.Color
,b.Name AS ProductSubcategory
,d.ThumbNailPhoto
,d.LargePhoto
FROM Production.Product a
INNER JOIN Production.ProductSubcategory b ON a.ProductSubcategoryID = b.ProductSubcategoryID
INNER JOIN Production.ProductProductPhoto c ON a.ProductID = c.ProductID
INNER JOIN Production.ProductPhoto d ON c.ProductPhotoID = d.ProductPhotoID
WHERE b.ProductCategoryID = 1 -- Bikes
ORDER BY ProductSubcategory, ProductName, a.Color

SET STATISTICS IO OFF
GO


Isso produzirá 97 bicicletas com fotos. Eles são muito difíceis de navegar em um dispositivo móvel.

ANÁLISE

USANDO A CONDIÇÃO MÍNIMA SEM DESLOCAMENTO/BUSCA

Veja quantas leituras lógicas são necessárias para recuperar 97 produtos com fotos. Consulte a Figura 5.

Figura 5 . As leituras lógicas e as leituras lógicas de lob ao usar ORDER BY sem OFFSET/FETCH e com condição WHERE mínima . (Observação:statisticsparser.com não mostrou as leituras lógicas do lob. A captura de tela é editado com base no resultado no SSMS)

667 leituras lógicas de lob apareceram devido à recuperação de imagens em 2 colunas. Enquanto isso, 590 leituras lógicas foram usadas para o restante.

Aqui está o plano de execução na Figura 6 para que possamos compará-lo mais tarde com o plano melhor.

Figura 6 . Plano de execução usando ORDER BY sem OFFSET/FETCH e com condição WHERE mínima.

Não há muito mais a dizer até vermos o outro plano de execução.
USANDO CONDIÇÃO DE ONDE ADICIONAL E DESLOCAMENTO/BUSCA POR ORDEM POR

Agora, vamos ajustar a consulta para garantir que os dados mínimos sejam retornados. Aqui está o que vamos fazer:
  • Adicione uma condição na subcategoria do produto. No aplicativo de chamada, podemos imaginar deixar o usuário escolher a subcategoria também.
  • Em seguida, remova a subcategoria do produto na lista de colunas SELECT e na lista de colunas ORDER BY.
  • Finalmente, adicione OFFSET/FETCH em ORDER BY. Apenas 10 produtos serão devolvidos e exibidos no aplicativo de chamada.

Aqui está o código editado.
DECLARE @pageNumber TINYINT = 1
DECLARE @noOfRows TINYINT =  10 -- each page will display 10 products at a time

SELECT
 a.ProductID
,a.Name AS ProductName
,a.ListPrice
,a.Color
,d.ThumbNailPhoto
FROM Production.Product a
INNER JOIN Production.ProductSubcategory b ON a.ProductSubcategoryID = b.ProductSubcategoryID
INNER JOIN Production.ProductProductPhoto c ON a.ProductID = c.ProductID
INNER JOIN Production.ProductPhoto d ON c.ProductPhotoID = d.ProductPhotoID
WHERE b.ProductCategoryID = 1 -- Bikes
AND a.ProductSubcategoryID = 2 -- Road Bikes
ORDER BY ProductName, a.Color
OFFSET (@pageNumber-1)*@noOfRows ROWS FETCH NEXT @noOfRows ROWS ONLY


Esse código melhorará ainda mais se você o transformar em um procedimento armazenado. Ele também terá parâmetros como número de página e número de linhas. O número da página indica qual página o usuário está visualizando no momento. Melhore ainda mais isso tornando o número de linhas flexível dependendo da resolução da tela. Mas isso é outra história.

Agora, vamos ver as leituras lógicas na Figura 7.

Figura 7 . Menos leituras lógicas após simplificar a consulta. OFFSET/FETCH também é usado em ORDER BY.

Em seguida, compare a Figura 7 com a Figura 5. As leituras lógicas do lob desapareceram. Além disso, as leituras lógicas tiveram uma diminuição notável, pois o conjunto de resultados também foi reduzido de 97 para 10.

Mas o que o SQL Server fez nos bastidores? Confira o plano de execução na Figura 8.

Figura 8 . Um plano de execução mais simples após simplificar a consulta e adicionar OFFSET/FETCH em ORDER BY.

Em seguida, compare a Figura 8 com a Figura 6. Sem examinar cada operador, podemos ver que este novo plano é mais simples que o anterior.

A lição? Simplifique sua consulta. Use OFFSET/FETCH sempre que possível.

O que não fazer no SQL ORDER BY


Concluímos o que precisamos fazer ao usar ORDER BY. Desta vez, vamos nos concentrar no que devemos evitar.

3. Não use ORDER BY ao classificar pela chave de índice clusterizado


Porque é inútil.

Vamos mostrar com um exemplo.
SET STATISTICS IO ON
GO

-- Using ORDER BY with BusinessEntityID - the primary key
SELECT TOP 100 * FROM Person.Person
ORDER BY BusinessEntityID;

-- Without using ORDER BY at all
SELECT TOP 100 * FROM Person.Person;

SET STATISTICS IO OFF
GO


Então, vamos verificar as leituras lógicas de ambas as instruções SELECT na Figura 9.

Figura 9 . 2 consultas na tabela Person mostram as mesmas leituras lógicas. Um é com ORDER BY, outro sem.

Ambos têm 17 leituras lógicas. Isso é lógico por causa das mesmas 100 linhas retornadas. Mas eles têm o mesmo plano? Confira a Figura 10.

Figura 10 . O mesmo plano se ORDER BY é usado ou não ao classificar pela chave de índice clusterizado.

Observe os mesmos operadores e o mesmo custo de consulta.

Mas por que? Ao indexar uma ou mais colunas em um índice clusterizado, a tabela será classificada fisicamente pela chave de índice clusterizado. Portanto, mesmo que você não classifique por essa chave, o resultado ainda será classificado.

Linha inferior? Perdoe-se por não usar a chave de índice clusterizado em casos semelhantes usando ORDER BY . Economize sua energia com menos teclas.

4. Não use ORDER BY quando uma coluna de string contém números


Se você classificar por uma coluna de string contendo números, não espere a ordem de classificação como os tipos de números reais. Caso contrário, você terá uma grande surpresa.

Aqui está um exemplo.

SELECT 
 NationalIDNumber
,JobTitle
,HireDate
FROM HumanResources.Employee
ORDER BY NationalIDNumber;


Verifique a saída na Figura 11.

Figura 11 . Ordem de classificação de uma coluna de string contendo números. O valor numérico não é seguido.

Na Figura 11, a ordem de classificação lexicográfica é seguida. Então, para corrigir isso, use um CAST para um inteiro.

SELECT 
 NationalIDNumber
,JobTitle
,HireDate
FROM HumanResources.Employee
ORDER BY CAST(NationalIDNumber AS INT)


Confira a Figura 12 para a saída fixa.

Figura 12 . CAST para INT corrigiu a classificação de uma coluna de string contendo números.

Portanto, em vez de ORDER BY , use ORDER BY CAST( AS INT).

5. Não use SELECT INTO #TempTable com ORDER BY


A ordem de classificação desejada não será garantida na tabela temporária de destino. Consulte a documentação oficial .

Vamos ter um código modificado do exemplo anterior.

SELECT 
 NationalIDNumber
,JobTitle
,HireDate
INTO #temp
FROM HumanResources.Employee
ORDER BY CAST(NationalIDNumber AS INT);

SELECT * FROM #temp;


A única diferença do exemplo anterior é a cláusula INTO. A saída será a mesma da Figura 11. Voltamos ao quadrado 1, mesmo que CAST a coluna para INT.

Você precisa criar uma tabela temporária usando CREATE TABLE. Mas inclua uma coluna de identidade extra e torne-a uma chave primária. Em seguida, INSERT na tabela temporária.

Aqui está o código fixo.

CREATE TABLE #temp2
(
	id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
	NationalIDNumber  NVARCHAR(15) NOT NULL,
	JobTitle NVARCHAR(50) NOT NULL,
	HireDate DATE NOT NULL
)
GO

INSERT INTO #temp2 
(NationalIDNumber, JobTitle, HireDate)
SELECT 
 NationalIDNumber
,JobTitle
,HireDate
FROM HumanResources.Employee
ORDER BY CAST(NationalIDNumber AS INT);


SELECT 
 NationalIDNumber
,JobTitle
,HireDate
FROM #Temp2;


E a saída será a mesma da Figura 12. Funciona!

Apreciações no uso do SQL ORDER BY


Cobrimos as armadilhas comuns no uso do SQL ORDER BY. Aqui está um resumo:

O que fazer :
  • Indexar as colunas ORDER BY,
  • Limite os resultados com WHERE e OFFSET/FETCH,

Não fazer :
  • Não use ORDER BY ao classificar pela chave de índice clusterizado,
  • Não use ORDER BY quando uma coluna de string contém números. Em vez disso, faça CAST da coluna de string para INT primeiro.
  • Não use SELECT INTO #TempTable com ORDER BY. Em vez disso, crie a tabela temporária primeiro com uma coluna de identidade extra.

Quais são suas dicas e truques para usar ORDER BY? Deixe-nos saber na seção de comentários abaixo. E se você gostou deste post, compartilhe-o em suas redes sociais favoritas.