Professional Documents
Culture Documents
Objetivo
Temas
1.1 Pasos
Para poder simular una carga de trabajo pesada en SQL Server, se usan sentencias que
contienen una combinación de malas prácticas.
USE AdventureWorks2008R2;
GO
CREATE PROCEDURE dbo.spr_ShoppingCart
@ShoppingCartId VARCHAR(50)
AS
SELECT sci.Quantity,
p.ListPrice,
p.ListPrice * sci.Quantity AS LineTotal,
p.[Name]
FROM Sales.ShoppingCartItem AS sci
JOIN Production.Product AS p
ON sci.ProductID = p.ProductID
WHERE sci.ShoppingCartID = @ShoppingCartId ;
GO
SELECT p.BusinessEntityID,
p.Title,
p.LastName,
p.FirstName,
p.PersonType
FROM Person.Person AS p
WHERE p.FirstName = @FirstName ;
GO
CREATE PROCEDURE dbo.spr_ProductTransactionsSinceDate
@LatestDate DATETIME,
@ProductName NVARCHAR(50)
AS
SELECT p.Name,
th.ReferenceOrderID,
th.ReferenceOrderLineID,
th.TransactionType,
th.Quantity
FROM Production.Product AS p
JOIN Production.TransactionHistory AS th
ON p.ProductID = th.ProductID AND
th.TransactionID = (SELECT TOP (1)
th2.TransactionID
FROM Production.TransactionHistory th2
WHERE th2.ProductID = p.ProductID
ORDER BY th2.TransactionID DESC
)
WHERE th.TransactionDate > @LatestDate AND
p.Name LIKE @ProductName ;
GO
CREATE PROCEDURE dbo.spr_PurchaseOrderBySalesPersonName @LastName
NVARCHAR(50)
AS
SELECT poh.PurchaseOrderID,
poh.OrderDate,
pod.LineTotal,
p.[Name] AS ProductName,
e.JobTitle,
per.LastName + ', ' + per.FirstName AS SalesPerson
FROM Purchasing.PurchaseOrderHeader AS poh
JOIN Purchasing.PurchaseOrderDetail AS pod
ON poh.PurchaseOrderID = pod.PurchaseOrderID
JOIN Production.Product AS p
ON pod.ProductID = p.ProductID
JOIN HumanResources.Employee AS e
ON poh.EmployeeID = e.BusinessEntityID
JOIN Person.Person AS per
ON e.BusinessEntityID = per.BusinessEntityID
WHERE per.LastName LIKE @LastName
ORDER BY per.LastName,
per.FirstName ;
GO
EXEC dbo.spr_ShoppingCart
'20621' ;
EXEC dbo.spr_ProductBySalesOrder
43867 ;
EXEC dbo.spr_PersonByFirstName
'Gretchen' ;
EXEC dbo.spr_ProductTransactionsSinceDate
@LatestDate = '9/1/2004',
@ProductName = 'Hex Nut%' ;
EXEC dbo.spr_PurchaseOrderBySalesPersonName
@LastName = 'Hill%' ;
Categoría: Execution
Event: rpc Completed
sql_batch_completed
EXEC dbo.spr_ShoppingCart
'20621' ;
EXEC dbo.spr_ProductBySalesOrder
43867 ;
EXEC dbo.spr_PersonByFirstName
'Gretchen' ;
EXEC dbo.spr_ProductTransactionsSinceDate
@LatestDate = '9/1/2004',
@ProductName = 'Hex Nut%' ;
EXEC dbo.spr_PurchaseOrderBySalesPersonName
@LastName = 'Hill%' ;
c:\traces\WorkLoadTrace.trc
Realizar los ordenamientos respectivos para conocer los queries con mayor
duración, para ello, ordenar la sentencia anterior:
SELECT ee.BatchText,
SUM(Duration) AS SumDuration,AVG(Duration) AS AvgDuration,
COUNT(Duration) AS CountDuration
::fn_trace_gettable('c:\traces\WorkLoadTrace.trc', 1) as ee
GROUP BY ee.BatchText ;
1.2.3 Identificar los queries más costosos y que demoran más en ejecutarse.
Para esto, ordenar los queries de la carga de trabajo por CPU, Reads, Writes y
Duration, para identificar los queries más costosos.
CPU: cuánto tiempo el CPU fue utilizado por un query (en ms)
Se puede disgregar el uso de recursos del punto anterior para poder ubicar al
cuello de botella, para lo cual se debe obtener información más detallada para
determinar qué acceso a tabla es más problemática.
Ejecutar lo siguiente:
DBCC FREEPROCCACHE() ;
DBCC DROPCLEANBUFFERS ;
GO
SET STATISTICS TIME ON ;
GO
SET STATISTICS IO ON ;
GO
EXEC dbo.spr_PurchaseOrderBySalesPersonName
@LastName = 'Hill%' ;
GO
SET STATISTICS TIME OFF ;
GO
SET STATISTICS IO OFF ;
GO
A nivel de Statistics IO
Las estadísticas son una de las principales piezas clave para que el Query Optimizer
pueda generar un plan de ejecución más adecuado.
Se puede revisar la información estadística de una tabla y sus índices con DBCC
SHOW_STATISTICS, por ejemplo, para la tabla Purchasing.PurchaseOrderHeader
DBCC SHOW_STATISTICS('Purchasing.PurchaseOrderHeader',
'PK_PurchaseOrderHeader_PurchaseOrderID') ;
Repetir los mismos pasos para cada una de las tablas involucradas.
sys.dm_db_index_physical_stats
SELECT s.avg_fragmentation_in_percent,
s.fragment_count,
s.page_count,
s.avg_page_space_used_in_percent,
s.record_count,
s.avg_record_size_in_bytes,
s.index_id
FROM sys.dm_db_index_physical_stats(DB_ID('AdventureWorks2008R2'),
OBJECT_ID(N'Purchasing.PurchaseOrderHeader'),
NULL, NULL, 'Sampled') AS s
WHERE s.record_count > 0
ORDER BY s.index_id ;
Ejecutar el query anterior para las otras tablas; observar que una reindexación puede
ayudar, para lo cual, se utiliza un script para realizar la reindexación de manera
automatizada:
sys.dm_db_index_ physicalstats
Para cada query identificado, se debe analizar su plan de ejecución asociado, dar clic
en el botón “Show Actual Execution Plan” y ejecutar el procedimiento almacenado.
EXEC dbo.spr_PurchaseOrderBySalesPersonName
@LastName = 'Hill%' ;
Una vez analizado el plan de ejecución del query, el próximo paso es identificar los
operadores más costosos, por ejemplo en el paso anterior, se encuentran los siguientes
operadores más costosos:
1.2.10 Analizar los efectos de los cambios en la carga de trabajo de la base de datos.
Una vez aplicados los ajustes a los operadores más costosos, se tiene que evaluar si los
cambios han sido beneficiosos para la carga de trabajo, para esto volver a capturar la
información con el Profiler y utilizar los siguientes eventos:
Categoría: Execution
Event: rpc Completed
sql_batch_completed
EXEC dbo.spr_ShoppingCart
'20621' ;
EXEC dbo.spr_ProductBySalesOrder
43867 ;
EXEC dbo.spr_PersonByFirstName
'Gretchen' ;
EXEC dbo.spr_ProductTransactionsSinceDate
@LatestDate = '9/1/2004',
@ProductName = 'Hex Nut%' ;
EXEC dbo.spr_PurchaseOrderBySalesPersonName
@LastName = 'Hill%' ;
c:\traces\WorkLoadTrace2.trc
Se categorizan en:
• Affinity mask.
• Opciones de configuración de memoria.
• Max Degree of Parallelism.
• Emplear resource governor.
• Emplear fill factor.
• Compresion de base de datos.