SQL Server’da Kriz Yönetimi: Uygulamalı Performans Optimizasyonu (Bölüm 2)
Bir önceki yazımızda [SQL Server’da Performansın Anatomisi: Page Yapısından TempDB Çekişmesine Teknik Bir Yolculuk]…
SQL Server’da Kriz Yönetimi: Uygulamalı Performans Optimizasyonu (Bölüm 2)

Bir önceki yazımızda [SQL Server’da Performansın Anatomisi: Page Yapısından TempDB Çekişmesine Teknik Bir Yolculuk] https://medium.com/%40tugcedokgoz19/sql-serverda-performans%C4%B1n-anatomisi-page-yap%C4%B1s%C4%B1ndan-tempdb-%C3%A7eki%C5%9Fmesine-teknik-bir-yolculuk-a8beb9ef27b6 başlığıyla işin teorik mutfağına girmiştik. Şimdi o bilgileri kuşanıp, kilitlenen bir sistemi ayağa kaldıracağız.
Hazırsanız, SQL Server Management Studio (SSMS) ekranlarını açalım ve simülasyona başlayalım.
Senaryo: Büyük İndirim Günü ve Sistem Çöküşü
Şirketin mobil uygulaması üzerinden saniyede 10.000 kişi aynı anda “Sepete Ekle” butonuna basıyor. İlk 5 dakika her şey yolunda görünürken birden Dashboard kızıla boyanıyor. Müşteriler “Ödeme tamamlanamadı” hatası alıyor, raporlar çekilemiyor ve CPU kullanımı %100'de çakılı kalıyor.
Gelin bu kaosu adım adım simüle edelim ve çözelim.
- Sorun: Pages & Extents (Deponun İç Yapısı)
Müşteriler ürün aratırken disk kullanımı %100’e vuruyor. Çünkü indeksler düzgün değil ve SQL Server 850.750'nci kaydı bulmak için 1 milyon satırı tek tek okuyor.
1. Adım: Deney Alanını Hazırlama
Önce test yapacağımız veri tabanını ve “indekssiz” (yani deponun darmadağın olduğu) ana tablomuzu oluşturalım.
`-- 1. Temiz bir başlangıç
CREATE DATABASE ETicaretTest;
GO
USE ETicaretTest;
GO
-- 2. Katalogsuz (İndekssiz) Tablo Oluşturma
CREATE TABLE Satisler(
SatisId INT,
MusteriAd NVARCHAR(50),
UrunBarkod NVARCHAR(50),
IslemTarihi DATETIME
);
GO
-- 3. 1 Milyon Satır "Yük" Bindirme (Simülasyon)
SET NOCOUNT ON;
DECLARE @i INT = 1;
WHILE @i <= 1000000
BEGIN
INSERT INTO Satisler (SatisId, MusteriAd, UrunBarkod, IslemTarihi)
VALUES(@i, 'Musteri' + CAST(@i AS VARCHAR), 'BARKOD-' + CAST(@i AS VARCHAR), GETDATE());
SET @i = @i + 1;
END;
PRINT '1 Milyon satır başarı ile eklendi';
2. Adım: “Table Scan” Faciası ve Müdahale
Kriz: Bir müşteri 850.750 ID’li siparişini sorguluyor. Veri tabanı bu kaydı bulmak için tüm depoyu (1 milyon satırı) tek tek gezmek zorunda kalıyor.
Kodla Analiz Et:
`-- CTRL + M (Execution Plan) açarak çalıştırın
SELECT * FROM Satislar WHERE SatisID = 850750;
Sonuç: Artık SQL Server depoda nereye gideceğini biliyor. Okunan satır sayısı 1.000.000'dan 1'e düştü!
Gözlem: Execution Plan’da devasa bir “Table Scan” göreceksiniz. SQL Server, 1 satırı bulmak için 1 milyon satırı (binlerce 8KB’lık sayfayı) RAM’e çekti.
Uzman Müdahalesi (Çözüm): Sayfaları fiziksel olarak düzene sokalım.
`CREATE CLUSTERED INDEX IX_SatisID ON Satislar(SatisID);
Sonuç: Artık SQL Server depoda nereye gideceğini biliyor. Okunan satır sayısı 1.000.000'dan 1'e düştü!
3. Adım: Transaction Log (VLF) Kaosu
Kriz: Satışlar o kadar hızlı ki, log dosyasının otomatik büyüme ayarı (1 MB) sistemi kilitliyor. Her 1 MB’da bir SQL Server duruyor, işletim sisteminden yer istiyor ve binlerce minik VLF (sanal günlük) oluşturuyor.
Mevcut Durumu Gör:
`DBCC LOGINFO; -- VLF listesini döker. Eğer yüzlerce satır varsa, prangalar takılmıştır.
Uzman Müdahalesi (Çözüm): Log dosyasını temizleyip, tek seferde büyük ve sağlıklı bir blok olarak açıyoruz.
`-- Önce logu sıfırla (Shrink)
DBCC SHRINKFILE (N'ETicaretTest_log' , 0, TRUNCATEONLY);
GO
-- Şimdi profesyonelce büyüt (Örn: 1GB başlangıç, 512MB büyüme)
ALTER DATABASE ETicaretTest
MODIFY FILE ( NAME = N'ETicaretTest_log', SIZE = 1024MB , FILEGROWTH = 512MB );
GO
Sonuç: Yazma hızı 5 kat arttı çünkü artık binlerce küçük VLF yerine 10 tane büyük, düzenli VLF var.
4. Adım: TempDB Contention (Mutfaktaki Kavga)
Kriz: 16 çekirdekli canavar gibi bir sunucun var ama TempDB sadece tek bir dosyadan oluşuyor. 16 işlemci de aynı anda o tek dosyaya yazmak için PFS ve GAM sayfaları üzerinde kavga ediyor.
Mevcut Mutfak Tezgahlarını Gör:
`USE tempdb;
EXEC sp_helpfile;
Uzman Müdahalesi (Çözüm): İşlemci çekirdek sayısı kadar (altın kural: max 8) TempDB dosyası oluşturuyoruz.
`USE [master];
GO
ALTER DATABASE [tempdb] ADD FILE (
NAME = N'tempdev2',
FILENAME = N'C:\Program Files\...\tempdb_msi_2.ndf',
SIZE = 100MB ,
FILEGROWTH = 64MB
);
GO
Sonuç: Her çekirdeğin artık kendi “çalışma alanı” var. Kuyruk bitti, raporlar saniyeler içinde gelmeye başladı.
Savaşın Sonu: Ne Başardık?
Pages: İndeks kullanarak diske olan gereksiz “eğilip kalkma” (I/O) sayısını bitirdik.
VLF: Log yönetimini optimize ederek yazma hızındaki “darboğazı” ortadan kaldırdık.
TempDB: Çoklu dosya yapısıyla işlemci çekirdeklerini birbirine düşürmekten kurtardık.
Veri tabanı sadece veri saklamak değil, o veriye en verimli şekilde ulaşma sanatıdır. Bir sonraki yazıda görüşmek üzere!
메타데이터
- post_id
- 3cf67c8d3972
- slug
- sql-serverda-kriz-yönetimi-uygulamalı-performans-optimizasyonu-bölüm-2-3cf67c8d3972
- url
- https://medium.com/@tugcedokgoz/sql-serverda-kriz-y%C3%B6netimi-uygulamal%C4%B1-performans-optimizasyonu-b%C3%B6l%C3%BCm-2-3cf67c8d3972
- canonical_url
- https://medium.com/@tugcedokgoz/sql-serverda-kriz-y%C3%B6netimi-uygulamal%C4%B1-performans-optimizasyonu-b%C3%B6l%C3%BCm-2-3cf67c8d3972
- author_url
- https://medium.com/@tugcedokgoz
- status
- ok
- fetched_at
- 2026-07-14 19:34:30