martes, 3 de diciembre de 2013

Índices y memoria



Habitualmente se piensa que el resultado positivo de un índice sólo se traduce en una lectura más rápida de datos. En esta entrada demostraré que también nos ayudan a reducir el uso de memoria al cargar menos páginas en el buffer de SQL Server.

Recordemos que SQL Server coloca en memoria los datos antes de poder despacharlos, esto se hace de esa forma para que la futura lectura de los datos sea mucho más rápida y no tenga que ir hasta los dispositivos de almacenamiento para recuperar la información.

Quiero hacer un ejercicio muy sencillo pero significativo con la base de datos AdventureWorks. El objetivo es obtener el total de ventas de los productos de color rojo. Analizaremos la cantidad de páginas que se cargan en memoria para poder despachar el resultado.

Nuestro query queda de la siguiente manera:
SELECT SUM(SOD.LineTotal) AS Total FROM Sales.SalesOrderDetail SOD INNER JOIN Production.Product P ON SOD.ProductID = P.ProductID WHERE P.Color = 'Red'

Para obtener la cantidad de páginas que está utilizando nuestra base de datos AdventureWorks en memoria, podemos conectarnos a ella y ejecutar el siguiente query:
SELECT COUNT(*) AS paginas_usadas FROM sys.dm_os_buffer_descriptors WHERE database_id = DB_ID()

Comenzaremos limpiando la memoria y verificando que no se estén usando páginas por parte de la base de datos AdventureWorks:
USE AdventureWorks GO CHECKPOINT DBCC DROPCLEANBUFFERS GO SELECT COUNT(*) AS paginas_usadas FROM sys.dm_os_buffer_descriptors WHERE database_id = DB_ID()

Vamos a ejecutar el query que obtiene el total de ventas de los productos de color rojo y verificamos de nueva cuenta la cantidad de páginas utilizadas por la base de datos AdventureWorks:
SELECT SUM(SOD.LineTotal) AS Total FROM Sales.SalesOrderDetail SOD INNER JOIN Production.Product P ON SOD.ProductID = P.ProductID WHERE P.Color = 'Red' GO SELECT COUNT(*) AS paginas_usadas FROM sys.dm_os_buffer_descriptors WHERE database_id = DB_ID()
En mi caso la cantidad de páginas usadas es de 772

Ahora vamos a crear un índice que nos ayude a optimizar el query, éste será creado sobre la columna ProductID e incluirá las columnas UnitPrice, UnitPriceDiscount y OrderQty las cuales son utilizadas para calcular LineTotal. Nuestro código queda de la siguiente manera:
CREATE INDEX ixSProductID ON Sales.SalesOrderDetail (ProductId) INCLUDE (UnitPrice, UnitPriceDiscount, OrderQty)

Volvemos a limpiar la memoria, ejecutamos nuestro query y verificamos la cantidad de páginas utilizadas por la base de datos AdventureWorks:
CHECKPOINT DBCC DROPCLEANBUFFERS GO SELECT SUM(SOD.LineTotal) AS Total FROM Sales.SalesOrderDetail SOD INNER JOIN Production.Product P ON SOD.ProductID = P.ProductID WHERE P.Color = 'Red' GO SELECT COUNT(*) AS paginas_usadas FROM sys.dm_os_buffer_descriptors WHERE database_id = DB_ID()
En mi caso la cantidad de páginas usadas es de 251

Notemos que la memoria necesaria para despachar el query se redujo en un 67.48%. ¿Qué debemos notar?, que los índices no sólo reducen el tiempo que tarda un query en ejecutarse sino también la cantidad de páginas que SQL Server necesita colocar en memoria para despachar el resultado.

Espero les haya resultado de utilidad esta entrada, nos vemos en la siguente.

No hay comentarios.:

Publicar un comentario