4. Estructura de las Tablas e Indices
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 4 / 59
5. Estructuras
SQL Server almacena datos en tablas e ı́ndices.
Heap Tables
Clustered Indexes
Nonclustered Indexes
Columnstore
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 5 / 59
6. Heap vs Clustered
Una tabla se puede organizar de una de dos maneras: como un heap o
como un árbol B (B-Tree). Técnicamente, la tabla se organiza como
un árbol B cuando tiene un clustered index definido y como un heap
cuando no.
Cuando agrega una restricción de Primary Key a una tabla, SQL
Server la aplicará utilizando un clustered index a menos que
especifique explı́citamente la palabra clave NONCLUSTERED o ya
exista un clustered index en la tabla.
Cuando agrega una restricción única a una tabla, SQL Server la
aplicará utilizando un nonclustered index a menos que especifique la
palabra clave CLUSTERED
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 6 / 59
7. Páginas
El área de almacenamiento más básica es una
página.
Cada página ocupa 8KB.
Cuando SQL Server interactúa con los archivos
de la base de datos, la unidad más pequeña en
la que puede ocurrir una operación de E / S
está en el nivel de página
Las páginas se agrupan de ocho en ocho en
estructuras llamadas extents.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 7 / 59
8. Páginas
Diferentes tipos de páginas
File header page
Boot page
Page Free Space (PFS) page
Global Allocation Map (GAM) page
Shared Global Allocation Map (SGAM) page
Differential Changed Map (DCM) page
Bulk Changed Map (BCM) page
Index Allocation Map (IAM) page
Data page
Index page
Large object (Text and Image) page
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 8 / 59
11. Clustered Indexes
1 Un clustered index dicta el orden fı́sco de los datos en una tabla
2 Una tabla puede tener sólo un clustered index definido
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 11 / 59
12. Clustered Indexes
1 El nivel intermedio almacena una fila por cada página del nivel de hoja.
2 Alamacena: dirección fı́sica de la página y el valor mı́nimo de la clave del ı́ndice de
la hoja referenciada, con exceçpción del primera fila de la primer página donde
almacena NULL (optimización para insertar una fila con clave mas baja en la tabla)
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 12 / 59
13. Clustered Indexes
Siempre hay un nivel hoja, cero o mas niveles intermedios y un nivel raı́z.
Excepto cuando la tabla entra en una única página, en este caso solo hay
una página con los datos.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 13 / 59
15. Clustered Indexes - buscando entre 925 y 3025
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 15 / 59
16. Non Clustered Indexes
1 Non clustered indexes definen un orden que es almacenado en una
estructura separada de los datos.
2 Es similar al clustered index en su estructura, pero las páginas del
nivel de hoja incluyen el valor de la clave y un rowid
3 El rowid
Para heap tables el rowid representa la locación fı́sica de la página
Para tablas con clustered index representa el clustered index key de la
fila.
4 Los nodos intermedios almacenan las dirección fı́sica del página y el
valor mı́nimo de la clave. Para el caso de ı́ndices no únicos también se
almacena el rowid
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 16 / 59
17. NonClusterd Indexes
SELECT * FROM dbo.Customers WHERE Name = ’Boris ’
Figura: 1er Paso
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 17 / 59
22. Ejecución de Consultas
Cada nodo en un plan de ejecución implementa al menos tres métodos
Open(): se inicializa el operador y se configuran las estructuras de datos requeridas
GetRow() : Requiere una fila del operador
Close() : finaliza el operador limpiando estructuras y datos que sean necesarios.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 22 / 59
23. Operadores de Acceso a Datos
Estructura Scan Seek
Heap Table Scan
Clustered Index Clustered Index Scan Clustered Index Seek
Nonclustered Index Index Scan Index Seek
bookmark lookup: RID lookup or Keylookup
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 23 / 59
24. Table Scan
La tabla Databaselog no tiene ı́ndice clustered.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 24 / 59
25. Comparemos el uso de ı́ndices
1 SELECT * FROM Person.Address ORDER BY AddressID;
2 SELECT AddressID , City , StateProvinceID FROM Person.
Address ORDER by AddressID;
3 SELECT AddressID , City , StateProvinceID FROM Person.
Address;
4 SELECT AddressID , City , StateProvinceID FROM Person.
Address ORDER by City;
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 25 / 59
26. Operadores de Agregación
SQL Server utiliza dos operadores:
1 Stream aggregate
2 Hash aggregate
Se usan para implementar agregados (SUM, AVG, MAX, etc) y para
GROUP BY y DISTINCT.
Para algunos operadores se requiere que los datos vengan ordenados,
el Query Optimizer puede usar un ı́nidice existente o puede introducir
un Sort Operator explicitamente.
Tanto el hashing como el sort usan memoria, pero si no encuentran espacio sufi-
ciente pueden usar tempdb database.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 26 / 59
27. Stream Aggregate
Consultas que usan un agregado y no tienen una clausula GROUP BY
(scalar aggregates) siempre se implementan con Stream Aggregate. En
caso de usar GROUP BY los datos deben venir ordenados.
SELECT AVG(ListPrice) FROM Production.Product
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 27 / 59
28. Stream Aggregate
SELECT ProductLine , COUNT (*) FROM Production.Product
GROUP BY ProductLine
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 28 / 59
29. Stream Aggregate
SELECT ProductLine , COUNT (*) FROM Production.Product
GROUP BY ProductLine
SELECT SalesOrderID , SUM(LineTotal)FROM Sales.
SalesOrderDetail GROUP BY SalesOrderID
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 28 / 59
30. Hash Aggregate
Hash Match
El Hash Aggregate cómo el Hash Join se implementa con el operador fı́sico
Hash Match
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 29 / 59
31. Hash Aggregate
Hash Match
El Hash Aggregate cómo el Hash Join se implementa con el operador fı́sico
Hash Match
SELECT City , COUNT(City) AS CityCount
FROM Person.Address
GROUP BY City
El optimizador de consultas puede seleccionar un Hash Aggregate para tablas
grandes donde los datos no están ordenados, no es necesario ordenarlos y su
cardinalidad se estima en solo unos pocos grupos.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 29 / 59
32. Hash Aggregate
Hash Match
El Hash Aggregate cómo el Hash Join se implementa con el operador fı́sico
Hash Match
SELECT City , COUNT(City) AS CityCount
FROM Person.Address
GROUP BY City
El optimizador de consultas puede seleccionar un Hash Aggregate para tablas
grandes donde los datos no están ordenados, no es necesario ordenarlos y su
cardinalidad se estima en solo unos pocos grupos.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 29 / 59
35. Hash vs Stream Aggregate
Hash Aggregate ayuda cuando los datos no están ordenados. Si se
crea un ı́ndice que pueda proporcionar datos ordenados, entonces el
optimizador de consultas puede seleccionar un Stream Aggregate.
Si la entrada no está ordenada pero se pide el orden explı́citamente en
una consulta, el optimizador de consultas puede introducir un Sort
operator y un Stream Aggregate o puede decidir usar un Hash
Aggregate y luego ordenar los resultados
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 31 / 59
36. Distinct Sort
Una consulta que usa la palabra clave DISTINCT puede ser imple-
mentada por Stream Aggregate, Hash Aggregate o por un operador
Distinct Sort.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 32 / 59
37. Distinct Sort
Una consulta que usa la palabra clave DISTINCT puede ser imple-
mentada por Stream Aggregate, Hash Aggregate o por un operador
Distinct Sort.
SELECT DISTINCT(JobTitle) FROM HumanResources .Employee;
SELECT JobTitle FROM HumanResources .Employee
GROUP BY JobTitle;
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 32 / 59
39. El optimizador de consultas debe tomar dos decisiones importantes con
respecto a las juntas:
la selección de un orden de las juntas
la selección del algoritmo de junta
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 34 / 59
41. Nested Loop Join
SELECT e. BusinessEntityID FROM HumanResources .Employee AS e
INNER JOIN Sales.SalesPerson AS s ON
e. BusinessEntityID = s. BusinessEntityID
Es muy efectivo si el outer input es suficientemente pequeña y el inner
input es grande pero indexada.
Merge Join y Hash Join requieren que la junta tenga al menos un predicado de
junta basado sobre un operador de igualdad (ej. equi join)
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 36 / 59
42. Merge Join
SELECT p.ProductID , v. BusinessEntityID
FROM Production.Product AS p
JOIN Purchasing.ProductVendor AS v
ON (p.ProductID = v.ProductID);
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 37 / 59
43. Hash Join
SELECT pv.ProductID , v.BusinessEntityID , v.Name
FROM Purchasing.ProductVendor pv JOIN Purchasing.Vendor v
ON (pv. BusinessEntityID = v. BusinessEntityID )
WHERE StandardPrice > 10
Hash Join
El optimizador lo usa para procesar entradas largas, no ordenadas, no
indexadas eficientemente.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 38 / 59
48. Compute Scalar
SELECT COUNT (*) cRows
FROM HumanResources .Shift;
SELECT COUNT_BIG (*) cRows
FROM HumanResources .Shift;
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 42 / 59
49. Filter
SELECT City , COUNT(City) AS CityCount
FROM Person.Address
GROUP BY City
HAVING COUNT(City) > 1
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 43 / 59
50. UNION - Concat
OPERADORES
Hay varios operadores que el optimizador utiliza para resolver la unión:
merge, hash, concat
select Suffix from Person.Person
UNION
select Suffix from Person.Person
¿Que es más costoso UNION o UNION ALL?
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 44 / 59
51. Integridad Referencial
SELECT a.AddressID , sp. StateProvinceID
FROM Person.Address AS a
JOIN Person.StateProvince AS sp
ON a. StateProvinceID = sp.StateProvinceID
WHERE a.AddressID = 27234;
SELECT a.AddressID , a. StateProvinceID
FROM Person.Address AS a
JOIN Person.StateProvince AS sp
ON a. StateProvinceID = sp.StateProvinceID
WHERE a.AddressID = 27234;
ALTER TABLE Person.Address
DROP CONSTRAINT FK_Address_StateProvince_StateProvinceID ;
ALTER TABLE Person.Address WITH CHECK
ADD CONSTRAINT FK_Address_StateProvince_StateProvinceID
FOREIGN KEY( StateProvinceID )
REFERENCES Person.StateProvince ( StateProvinceID );
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 45 / 59
52. Hints
SELECT ...
OPTION (<hint >,<hint >...)
HASH GROUP / ORDER GROUP
MERGE —HASH —CONCAT UNION
LOOP—MERGE—HASH JOIN
FAST N
FORCE ORDER
RECOMPILE
FROM TableName WITH (INDEX ([IndexName]))
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 46 / 59
53. Parameter Sniffing / OPTIMIZE FOR
SELECT * FROM Person.Address
WHERE City = ’Mentor ’;
SELECT * FROM Person.Address
WHERE City = ’London ’;
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 47 / 59
54. Parameter Sniffing / OPTIMIZE FOR
SELECT * FROM Person.Address
WHERE City = ’Mentor ’;
SELECT * FROM Person.Address
WHERE City = ’London ’;
DECLARE @City NVARCHAR (30)
SET @City = ’Mentor ’
SELECT * FROM Person.Address
WHERE City = @City
SET @City = ’London ’
SELECT * FROM Person.Address
WHERE City = @City;
OPTION( OPTIMIZE FOR (@City = ’Mentor ’) )
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 47 / 59
59. Comparar
SELECT sod.*
FROM Sales. SalesOrderDetail AS sod
WHERE sod.SalesOrderID IN ( 51825 , 51826 , 51827 , 51828 );
SELECT sod.*
FROM Sales. SalesOrderDetail AS sod
WHERE sod.SalesOrderID BETWEEN 51825 AND 51828 ;
SELECT sod.*
FROM Sales. SalesOrderDetail AS sod
WHERE sod.SalesOrderID = 51825
OR sod.SalesOrderID = 51826
OR sod.SalesOrderID = 51827
OR sod.SalesOrderID = 51828;
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 52 / 59
60. Composite Indexes: SARGable
La SARGability de un ı́ndice compuesto depende de la SARGability del
predicado sobre la primer columna del ı́ndice.
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 53 / 59
61. SARGability
SELECT *
FROM Purchasing. PurchaseOrderHeader AS poh
WHERE poh. PurchaseOrderID * 2 = 3400;
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 54 / 59
62. SARGability
SELECT *
FROM Purchasing. PurchaseOrderHeader AS poh
WHERE poh. PurchaseOrderID * 2 = 3400;
SELECT *
FROM Purchasing. PurchaseOrderHeader AS poh
WHERE poh. PurchaseOrderID = 3400/2;
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 54 / 59
63. Cobertura Indice
SELECT a.PostalCode
FROM Person.Address AS a
WHERE a. StateProvinceID = 42;
CREATE NONCLUSTERED INDEX IX_Address_StateProvinceID
ON Person.Address(StateProvinceID ASC)
INCLUDE(PostalCode)
WITH (DROP_EXISTING = ON);
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 55 / 59
64. Indice con filtros
SELECT soh.PurchaseOrderNumber ,
soh.OrderDate ,
soh.ShipDate ,
soh.SalesPersonID
FROM Sales. SalesOrderHeader AS soh
WHERE PurchaseOrderNumber LIKE ’PO5 %’
AND soh.SalesPersonID IS NOT NULL;
CREATE NONCLUSTERED INDEX IX_Test
ON Sales. SalesOrderHeader (PurchaseOrderNumber ,SalesPersonID)
INCLUDE(OrderDate ,ShipDate)
CREATE NONCLUSTERED INDEX IX_Test
ON Sales. SalesOrderHeader (PurchaseOrderNumber ,SalesPersonID)
INCLUDE(OrderDate ,ShipDate)
WHERE PurchaseOrderNumber IS NOT NULL
AND SalesPersonID IS NOT NULL
WITH (DROP_EXISTING = ON);
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 56 / 59
65. Bibliografı́a
Grant Fritchey. SQL Server 2017 Query Performance Tuning
Troubleshoot and Optimize Query Performance (Fifth Edition).
Apress, Berkely, CA, USA.
Jason Strate and Grant Fritchey. 2015. Expert Performance
Indexing in SQL Server (2nd ed.). Apress, Berkely, CA, USA.
Benjamin Nevarez Inside the SQL Server Query Optimizer
Grant Fritchey 2012 SQL Server Execution Plans -Second Edition
Simple Talk Publishing September
Dr. Gerardo Rossel (DC - UBA) Optimización 2023 57 / 59