sql >> Base de Datos >  >> RDS >> Database

ORDEN SQL POR:Las 5 cosas que se deben y no se deben hacer para ordenar los datos como un profesional

Feo. Así es como se ven los datos sin ordenar. Hacemos que los datos sean fáciles de ver al clasificarlos. Y para eso está SQL ORDER BY. Utilice una o más columnas o expresiones como base para ordenar los datos. Luego, agregue ASC o DESC para ordenar de forma ascendente o descendente.

La sintaxis SQL ORDER BY:

ORDER BY <order_by_expression> [ASC | DESC]


La expresión ORDER BY puede ser tan simple como una lista de columnas o expresiones. También puede ser condicional usando un bloque CASE WHEN.

Es muy flexible.

También puede usar la paginación a través de OFFSET y FETCH. Especifique el número de filas para omitir y las filas para mostrar.

Pero estas son las malas noticias.

Agregar ORDER BY a sus consultas puede ralentizarlas. Y algunas otras advertencias pueden hacer que ORDEN POR "no funcione". No puede usarlos en cualquier momento que desee, ya que puede haber sanciones. Entonces, ¿qué hacemos?

En este artículo, examinaremos lo que se debe y lo que no se debe hacer al usar ORDER BY. Cada elemento se ocupará de un problema y seguirá una solución.

¿Listo?

Qué hacer en SQL ORDER BY

1. Indexe la(s) columna(s) SQL ORDER BY

Los índices tienen que ver con búsquedas rápidas. Y tener uno en las columnas que usa en la cláusula ORDER BY puede acelerar su consulta.

Empecemos a usar ORDER BY en una columna sin índice. Usaremos el AdventureWorks base de datos de muestra. Antes de ejecutar la consulta a continuación, deshabilite el IX_SalesOrderDetail_ProductID índice en SalesOrderDetail mesa. Luego, presione Ctrl-M y ejecutarlo.


-- 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ÁLISIS

El código anterior generará las estadísticas de E/S en la pestaña Mensajes de SQL Server Management Studio. Verás el plan de ejecución en otra pestaña.

SIN ÍNDICE

Primero, obtengamos las lecturas lógicas de STATISTICS IO. Mira la Figura 1.

Figura 1 . Lecturas lógicas usando ORDER BY de una columna no indexada. (Formateado usando estadísticasparser.com )

Sin el índice, la consulta utilizó 1313 lecturas lógicas. Y esa Mesa de Trabajo ? Significa que SQL Server usó TempDB para procesar la clasificación.

Pero, ¿qué pasó detrás de escena? Inspeccionemos el plan de ejecución en la Figura 2.

Figura 2 . Plan de ejecución de una consulta usando ORDER BY de una columna no indexada.

¿Viste ese operador de Parallelism (Gather Streams)? Significa que SQL Server usó más de 1 procesador para procesar esta consulta. La consulta era lo suficientemente pesada como para requerir más CPU.

Entonces, ¿qué pasaría si SQL Server usara TempDB ? y mas procesadores? Es malo para una consulta simple.

CON ÍNDICE

¿Cómo le irá si el índice se vuelve a habilitar? Vamos a averiguar. Reconstruir el índice IX_SalesOrderDetail_ProductID . Luego, vuelva a ejecutar la consulta anterior.

Compruebe las nuevas lecturas lógicas en la Figura 3.

Figura 3 . Nuevas lecturas lógicas después de reconstruir el índice.

Esto es mucho mejor. Reducimos el número de lecturas lógicas a casi la mitad. Eso significa que el índice hizo que consumiera menos recursos. Y la mesa de trabajo ? ¡Se fue! No es necesario usar TempDB .

¿Y el plan de ejecución? Consulte la figura 4.

Figura 4 . El nuevo plan de ejecución es más simple cuando se reconstruyó el índice.

¿Ver? El plan es más simple. No se necesitan CPU adicionales para clasificar las mismas 121 317 filas.

Entonces, la conclusión es:Asegúrese de que las columnas que usa para ORDER BY estén indexadas .

PERO, ¿Y SI AÑADIR UN ÍNDICE IMPACTA EL RENDIMIENTO DE ESCRITURA?

Buena pregunta.

Si ese es el problema, puede volcar una parte de la tabla de origen en una tabla temporal o en una tabla optimizada para memoria. . Luego, indexe esa tabla. Use lo mismo si hay más tablas involucradas. Luego, evalúe el rendimiento de la consulta de la opción que eligió. La opción más rápida será la ganadora.

2. Limite los resultados con WHERE y OFFSET/FETCH

Usemos una consulta diferente. Supongamos que necesita mostrar información del producto con imágenes en una aplicación. Las imágenes pueden hacer que las consultas sean aún más pesadas. Por lo tanto, no solo comprobaremos las lecturas lógicas, sino también las lecturas lógicas.

Aquí está el 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


Esto generará 97 bicicletas con imágenes. Son muy difíciles de navegar en un dispositivo móvil.

ANÁLISIS

USO DE LA CONDICIÓN WHERE MÍNIMA SIN COMPENSACIÓN/FETCH

Esta es la cantidad de lecturas lógicas que se necesitan para recuperar 97 productos con imágenes. Consulte la figura 5.

Figura 5 . Las lecturas lógicas y las lecturas lógicas de lob cuando se usa ORDER BY sin OFFSET/FETCH y con la condición WHERE mínima . (Nota:statisticsparser.com no mostró las lecturas lógicas de lob. La captura de pantalla se edita en función del resultado en SSMS)

Aparecieron 667 lecturas lógicas de lob debido a la recuperación de imágenes en 2 columnas. Mientras tanto, se utilizaron 590 lecturas lógicas para el resto.

Aquí está el plan de ejecución en la Figura 6 para que podamos compararlo más tarde con el mejor plan.

Figura 6 . Plan de ejecución usando ORDER BY sin OFFSET/FETCH y con condición mínima WHERE.

No hay mucho más que decir hasta que veamos el otro plan de ejecución.

USO DE CONDICIONES WHERE ADICIONALES Y DESPLAZAMIENTO/FETCH EN ORDEN POR

Ahora, ajustemos la consulta para asegurarnos de que se devuelvan datos mínimos. Esto es lo que vamos a hacer:

  • Agregue una condición en la subcategoría del producto. En la aplicación de llamadas, podemos imaginar que el usuario también puede elegir la subcategoría.
  • Luego, elimine la subcategoría del producto en la lista de columnas SELECCIONAR y en la lista de columnas ORDENAR POR.
  • Finalmente, agregue OFFSET/FETCH en ORDER BY. Solo se devolverán 10 productos y se mostrarán en la aplicación de llamadas.

Aquí está el 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


Este código mejorará aún más si lo convierte en un procedimiento almacenado. También tendrá parámetros como el número de página y el número de filas. El número de página indica qué página está viendo actualmente el usuario. Mejore esto aún más haciendo que el número de filas sea flexible según la resolución de la pantalla. Pero esa es otra historia.

Ahora, veamos las lecturas lógicas en la Figura 7.

Figura 7 . Menos lecturas lógicas después de simplificar la consulta. OFFSET/FETCH también se usa en ORDER BY.

Luego, compare la Figura 7 con la Figura 5. Las lecturas lógicas de lob se han ido. Además, las lecturas lógicas tienen una disminución notable ya que el conjunto de resultados también se redujo de 97 a 10.

Pero, ¿qué hizo SQL Server entre bastidores? Consulte el plan de ejecución en la Figura 8.

Figura 8 . Un plan de ejecución más simple después de simplificar la consulta y agregar OFFSET/FETCH en ORDER BY.

Luego, compare la Figura 8 con la Figura 6. Sin examinar cada operador, podemos ver que este nuevo plan es más simple que el anterior.

¿La leccion? Simplifique su consulta. Utilice COMPENSACIÓN/FETCH siempre que sea posible.

No hacer en SQL ORDER BY

Hemos terminado con lo que necesitamos hacer cuando usamos ORDER BY. Esta vez, centrémonos en lo que debemos evitar.

3. No use ORDER BY al ordenar por la clave de índice agrupado

Porque es inútil.

Mostrémoslo con un ejemplo.

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


Luego, verifiquemos las lecturas lógicas de ambas instrucciones SELECT en la Figura 9.

Figura 9 . 2 consultas en la tabla Person muestran las mismas lecturas lógicas. Uno es con ORDER BY, otro sin.

Ambos tienen 17 lecturas lógicas. Esto es lógico debido a que se devolvieron las mismas 100 filas. ¿Pero tienen el mismo plan? Mira la Figura 10.

Figura 10 . El mismo plan, ya sea que se use ORDER BY o no al ordenar por la clave de índice agrupado.

Observe los mismos operadores y el mismo costo de consulta.

¿Pero por qué? Al indexar una o más columnas en un índice agrupado, la tabla se ordenará físicamente por la clave de índice agrupado. Por lo tanto, incluso si no ordena por esa clave, el resultado aún se ordenará.

¿Línea de fondo? Perdónese por no usar la clave de índice agrupado en casos similares usando ORDER BY . Ahorre energía con menos pulsaciones de teclas.

4. No use ORDER BY cuando una columna de cadena contiene números

Si ordena por una columna de cadena que contiene números, no espere el orden de clasificación como los tipos de números reales. De lo contrario, te espera una gran sorpresa.

He aquí un ejemplo.


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


Verifique la salida en la Figura 11.

Figura 11 . Orden de clasificación de una columna de cadena que contiene números. No se sigue el valor numérico.

En la Figura 11, se sigue el orden de clasificación lexicográfico. Entonces, para arreglar esto, usa CAST a un número entero.


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


Consulte la Figura 12 para ver la salida fija.

Figura 12 . CAST to INT corrigió la clasificación de una columna de cadena que contenía números.

Entonces, en lugar de ORDER BY , use ORDER BY CAST( AS INT).

5. No use SELECT INTO #TempTable con ORDER BY

Su orden de clasificación deseado no estará garantizado en la tabla temporal de destino. Ver la documentación oficial .

Tengamos un código modificado del ejemplo anterior.


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

SELECT * FROM #temp;


La única diferencia con el ejemplo anterior es la cláusula INTO. El resultado será el mismo que en la Figura 11. Estamos de vuelta en el cuadro 1 incluso si CAST la columna a INT.

Debe crear una tabla temporal usando CREATE TABLE. Pero incluya una columna de identidad adicional y conviértala en una clave principal. Luego, INSERTAR en la tabla temporal.

Aquí está el código fijo.


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;


Y el resultado será el mismo que en la Figura 12. ¡Funciona!

Conclusiones sobre el uso de SQL ORDER BY

Hemos cubierto las trampas comunes al usar SQL ORDER BY. He aquí un resumen:

Qué hacer :

  • Indexar las columnas ORDENAR POR,
  • Limite los resultados con WHERE y OFFSET/FETCH,

No hacer :

  • No utilice ORDER BY al ordenar por clave de índice agrupado,
  • No utilice ORDER BY cuando una columna de cadena contiene números. En su lugar, CAST la columna de cadena a INT primero.
  • No utilice SELECT INTO #TempTable con ORDER BY. En su lugar, cree primero la tabla temporal con una columna de identidad adicional.

¿Cuáles son sus consejos y trucos para usar ORDER BY? Háganos saber en la sección de comentarios. Y si te gusta esta publicación, compártela en tus plataformas de redes sociales favoritas.