MSSQL Server RML Utilities Tool

RML Utilities (ReadTrace Multi-Threaded Log Utilities), Microsoft tarafından geliştirilen ve SQL Server performans analizi için tasarlanmış ücretsiz bir araç setidir. Özellikle SQL Trace veya Extended Events dosyalarını analiz ederek detaylı performans raporları oluşturur. SQL Trace dosyalarını (.trc) okur ve analiz eder. Ham trace verisini işlenebilir formata dönüştürür. Performans metrikleri çıkarır. OStress yapısı ile Database iş yükü simülasyonu yapar. T-SQL batch’lerini veya trace dosyalarını çalıştırır.

Yukarıdaki tanımlamalardan sonra Arama motoruna RML Utilities Tool yazarsanız Microsoftun indirme ekranına gelirsiniz.

İlgili Tools indirildikten sonra Sunucu üzerine kopyalanıp çalıştırılır. Bu işlemler sunucular ilk tahsis edildiğinde performans testleri için kullanılmaktadır.

Gelen ekranda Next denilir.

Aşağıdaki checkbox yapısını seçtikten sonra Next denilip bir sonraki ekrana gelinir.

Aşağıdaki resimde hangi dizin altında ilgili programın kurulacağı ve Everyone seçeneği ile herkesin kullanmasını sağlıyoruz.

Aşağıdaki ekranda Next deyip işlemlerimi bitiriyorum.

Aşağıdaki uzantıda RML Cmd Prompt‘un uzantısını görebiliriz.

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\RML Utilities for SQL Server

İlgili bölüme çift tıkladıktan sonra RML Cmd Prompt ekranı karşımıza çıkmaktadır.

Yukarıda kurulum işlemlerini yaptıktan sonra şimdi sunucumuz üzerinden test işlemlerini yapmış olacağız. Bunun için içerisinde verilerimizin olacağı sql server 2022 veritabanı üzerinden işlem yapmış olacağım.

Microsoft’un sayfasından belirtilen linkte sql server sürümünüzle uyumlu veritabanı bak uzantısını indirebilirsiniz.

Şimdi uygulamalı bir şekilde işlemlerimizi yapmış olalım. Aşağıdaki komutu high_workload.sql olarak kaydediyoruz. Bu komut aynı anda okuma yazma güncelleme insert işlemi yapmaktadır. Amaç sisteme yük bindirmektedir.

-- OKUMA: Büyük tablo taramaları
SELECT * FROM Sales.SalesOrderDetail ORDER BY ModifiedDate DESC;

-- YAZMA: Büyük INSERT işlemleri

INSERT INTO Production.TransactionHistory3
SELECT 
    1,
    ProductID,
    ReferenceOrderID,
    ReferenceOrderLineID,
    TransactionDate,
    TransactionType,
    Quantity,
    ActualCost,
    GETDATE()
FROM Production.TransactionHistory 
WHERE TransactionDate > '2013-01-01';



-- GÜNCELLEME: Yoğun UPDATE işlemleri
UPDATE Sales.SalesOrderDetail 
SET UnitPrice = UnitPrice * 1.1, 
    ModifiedDate = GETDATE()
WHERE ProductID IN (
    SELECT TOP 100 ProductID 
    FROM Production.Product 
    ORDER BY ProductID
);

-- COMPLEX QUERY: TempDB kullanımını zorlayan sorgular
SELECT 
    p.ProductID,
    p.Name,
    sod.SalesOrderID,
    soh.OrderDate,
    soh.CustomerID,
    SUM(sod.OrderQty) OVER (PARTITION BY p.ProductID) as TotalQty,
    AVG(sod.UnitPrice) OVER (PARTITION BY soh.CustomerID) as AvgCustomerSpend,
    COUNT(*) OVER (PARTITION BY YEAR(soh.OrderDate)) as YearlyOrderCount
FROM Production.Product p
INNER JOIN Sales.SalesOrderDetail sod ON p.ProductID = sod.ProductID
INNER JOIN Sales.SalesOrderHeader soh ON sod.SalesOrderID = soh.SalesOrderID
WHERE soh.OrderDate BETWEEN '2011-01-01' AND '2014-12-31'
ORDER BY p.ProductID, soh.OrderDate;

-- SORT işlemleri (TempDB baskısı)
SELECT * FROM Production.Product 
ORDER BY Name, ProductNumber, ListPrice DESC;

-- GROUP BY with HAVING (TempDB kullanır)
SELECT 
    CustomerID,
    COUNT(*) as OrderCount,
    AVG(TotalDue) as AvgOrderValue,
    SUM(TotalDue) as TotalSpent
FROM Sales.SalesOrderHeader
GROUP BY CustomerID
HAVING COUNT(*) > 5 AND SUM(TotalDue) > 10000
ORDER BY TotalSpent DESC;

Yukarıdaki komutu kaydettikten sonra aşağıdaki komut ile sisteme yük bindirtip Task Managerden işlemin getirdiği yükü görmüş olacağız.

Ostress.exe -S"XXXSQL23\XXX2022" -Udba –P1 –iC:\high_workload.sql –n4000 –r1000

–n4000: İşlemin kaç tread ile çalışması gerektiğini belirliyoruz. 4000 tread ile çalışmaktadır.

-r1000: İşlemin toplamda 100 defa çalışacağı belirtilmektedir.

iC:\high_workload.sql kaydettiğimiz uzantıda çalıştıracağımız sql komutu

U ve P kısımlarında kullanıcı adı ve şifresi girilmektedir.

Çalıştırılmadan önce sistem üzerinde toplam yük incelendiğinde 0-1 bandında cpu yüzdesi görülmektedir.

İlgili komut RML üzerinde çalıştırılması için ilgili komut, komut satırına eklenir.

CPU değerinin 1’lerden 64’lere çıktığı görülmektedir.

Tempdb üzerinde yük oluşturmak için aşağıdaki komut kullanılır. Bu komutta kaydedilip RML üzerinden çalıştırılır.

-- Büyük geçici tablolar oluşturan sorgular
WITH LargeCTE AS (
    SELECT 
        t1.*,
        t2.SalesOrderID,
        t2.OrderDate,
        t2.TotalDue,
        ROW_NUMBER() OVER (ORDER BY t1.ProductID) as RowNum,
        NTILE(100) OVER (ORDER BY t1.ListPrice) as PriceGroup
    FROM Production.Product t1
    CROSS JOIN Sales.SalesOrderHeader t2
    WHERE t2.OrderDate > '2013-01-01'
)
SELECT 
    ProductID,
    COUNT(*) as TotalOrders,
    AVG(TotalDue) as AvgOrderValue
FROM LargeCTE
GROUP BY ProductID
HAVING COUNT(*) > 100
ORDER BY TotalOrders DESC;

-- Complex JOIN with ORDER BY (TempDB spill)
SELECT 
    p1.ProductID,
    p1.Name,
    p2.ProductModelID,
    pm.Name as ModelName,
    COUNT(*) as RelatedProducts
FROM Production.Product p1
INNER JOIN Production.Product p2 ON p1.ProductModelID = p2.ProductModelID
INNER JOIN Production.ProductModel pm ON p1.ProductModelID = pm.ProductModelID
WHERE p1.ProductID <> p2.ProductID
GROUP BY p1.ProductID, p1.Name, p2.ProductModelID, pm.Name
ORDER BY RelatedProducts DESC, p1.Name;

-- Window functions with large datasets
SELECT 
    SalesOrderID,
    SalesOrderDetailID,
    ProductID,
    OrderQty,
    UnitPrice,
    LineTotal,
    SUM(LineTotal) OVER (PARTITION BY ProductID ORDER BY SalesOrderID) as RunningTotal,
    AVG(UnitPrice) OVER (PARTITION BY ProductID) as AvgProductPrice,
    COUNT(*) OVER (PARTITION BY ProductID) as ProductOrderCount
FROM Sales.SalesOrderDetail
ORDER BY ProductID, SalesOrderID;

RML üzerinden aşağıdaki komut çalıştırılır.

Ostress.exe -S"XXXSQL23\XXX2022"-Udba –P1 –iC:\tempdb_stress.sql –n1500 –r1000

Tempdb üzerinde yoğunluk oluşturulduğunda CPU değerinin 100’lere dayandığı görülmektedir.

Bir başka stress testi yapmak için kullanacağımız komut: Bu komut sorguların paralel çalışmasını sağlayarak sisteme yük getirmiş olacaktır.

-- Maksimum CPU ve bellek kullanımı
SELECT 
    p.ProductID,
    p.Name,
    pc.Name as CategoryName,
    ps.Name as SubcategoryName,
    SUM(sod.OrderQty) as TotalSold,
    AVG(sod.UnitPrice) as AvgPrice,
    COUNT(DISTINCT soh.CustomerID) as UniqueCustomers,
    (SELECT COUNT(*) FROM Sales.SalesOrderDetail sod2 
     WHERE sod2.ProductID = p.ProductID) as TotalOrderLines,
    (SELECT SUM(LineTotal) FROM Sales.SalesOrderDetail sod3 
     WHERE sod3.ProductID = p.ProductID) as TotalRevenue
FROM Production.Product p
LEFT JOIN Production.ProductSubcategory ps ON p.ProductSubcategoryID = ps.ProductSubcategoryID
LEFT JOIN Production.ProductCategory pc ON ps.ProductCategoryID = pc.ProductCategoryID
LEFT JOIN Sales.SalesOrderDetail sod ON p.ProductID = sod.ProductID
LEFT JOIN Sales.SalesOrderHeader soh ON sod.SalesOrderID = soh.SalesOrderID
GROUP BY p.ProductID, p.Name, pc.Name, ps.Name
HAVING SUM(sod.OrderQty) > 100
ORDER BY TotalRevenue DESC;

-- Paralel execution için optimize edilmiş büyük sorgu
SELECT 
    soh.CustomerID,
    c.AccountNumber,
    p.FirstName + ' ' + p.LastName as CustomerName,
    COUNT(DISTINCT soh.SalesOrderID) as TotalOrders,
    SUM(soh.TotalDue) as LifetimeValue,
    AVG(soh.TotalDue) as AvgOrderValue,
    MAX(soh.OrderDate) as LastOrderDate,
    DATEDIFF(day, MIN(soh.OrderDate), MAX(soh.OrderDate)) as CustomerDurationDays
FROM Sales.SalesOrderHeader soh
INNER JOIN Sales.Customer c ON soh.CustomerID = c.CustomerID
INNER JOIN Person.Person p ON c.PersonID = p.BusinessEntityID
WHERE soh.OrderDate BETWEEN '2011-01-01' AND '2014-12-31'
GROUP BY soh.CustomerID, c.AccountNumber, p.FirstName, p.LastName
HAVING COUNT(DISTINCT soh.SalesOrderID) > 10
ORDER BY LifetimeValue DESC;

RML üzerinden ilgili komut çalıştırıldığında CPU üzerine tekrardan yük bindiğini görmüş oluyoruz.

Ostress.exe -S"XXXSQL23\XXX2022" -Udba –P1 –iC:\extreme_workload.sql –n2500 –r1000

Cpu değerinin yüzlere dayadığını görmekteyiz.

Yukarıdaki işlemleri manuel yapmakyıp bir job aracılığıyla yaparsak yükün sürekli binmesini sağlamış olacağız. Hatta perform monitor konfigürasyonu yapılarak belirli bir süre izlenebilir.

Job üzerinden nasıl yapıldığını görmüş olalım. Ayrıca hangi komutun job komut satırına yazılması gerektiğini belirleyelim.

"C:\Program Files\Microsoft Corporation\RMLUtils\Ostress.exe" -S"XXXSQL23\XXX2022" -Udba –P1 –iC:\high_workload.sql –n4000 –r1000 -oD:\stressoutput

Çıktının D dizini altındaki uzantıya atmaktadır. oD:\stressoutput

Oluşturulacak Job’ın resimde belirtildiği gibi oluşturulması gerekmektedir.

Yukarıda yapılan 3 işlem ayrı joblarda çalıştırılıp sistem üzerinde oluşacak yük gerçek anlamda bu şekilde incelenir.

Başka makalede görüşmek dileğiyle..

Onlar, yaptıkları dünyada ve ahirette boşa gitmiş olanlardır. Ve onların yardımcıları yoktur.

Al-i İmran Suresi, 22. Ayet

Author: Yunus YÜCEL

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir