• 30.10.2026 03:21:32
  • İbrahim Gökyar

OLTP iş yüklerinde veritabanı optimizasyonu için index tasarımı, write amplification ölçümü ve profilleme adımları. Hem SQL/NoSQL örnekleriyle veritabanı performans ayarlama ve database indexleme pratikleri sunulur.

Veritabanı optimizasyonu: OLTP index stratejileri, write amplification ve ölçüm

OLTP için index seçimi ve write amplification ölçümü

OLTP tablolarında her ek indeks yazma maliyetini arttırır; bunu somut olarak ölçmek için PostgreSQL'de LSN farkını kullanın: önce LSN alıp workload çalıştırıp sonra tekrar ölçün. Komutlar:

SELECT pg_current_wal_lsn() AS lsn_before;
-- iş yükünü çalıştır (ör. pgbench)
SELECT pg_current_wal_lsn() AS lsn_after;
SELECT pg_wal_lsn_diff(lsn_before, lsn_after) AS wal_bytes;
Bu ölçüm size indeks eklemenin WAL üzerinden yazma amplifikasyonunu bayt bazında verir; neden: her ek indeks için ek B-tree güncellemesi WAL'a yazılır, dolayısıyla wal_bytes doğrudan yazma maliyetini yansıtır.

İndeksleri azaltma ya da kapsamlı (covering) indekslerle sorgu cevap süresini düşürürken write amplification'ı kontrol edin. Örnek: PostgreSQL'de sık kullanılan sorguya yönelik covering indeks oluşturmak için INCLUDE kullanabilirsiniz:

CREATE INDEX ix_orders_user_status ON orders (user_id, created_at) INCLUDE (status);
EXPLAIN (ANALYZE, BUFFERS) SELECT status FROM orders WHERE user_id = 123 ORDER BY created_at DESC LIMIT 10;
Neden: INCLUDE ile sık okunan sütunları index'te tutarak heap erişimlerini engellersiniz; maliyet mekanizması: okuma maliyeti düşerken index boyutu artar, bu da WAL ve page-splitting üzerinde etkili olur.

Deneysel adım: aynı workload'u 'önce' indeksi varken, 'sonra' indeksi silip yeniden ölçün. Örnek pgbench komutu ve ölçüm akışı:

pgbench -c 20 -j 4 -T 60 -f myscript.sql mydb
-- ölçüm öncesi LSN
SELECT pg_current_wal_lsn();
-- ölçüm sonrası LSN ve wal farkı
SELECT pg_wal_lsn_diff(lsn_before, lsn_after);
Bu before/after karşılaştırması ile indeksin yazma maliyetine etkisini yüzdelik olarak hesaplayabilirsiniz: (wal_after - wal_before) / wal_before * 100.

Sorgu profilleme: EXPLAIN, pg_stat_statements ve sistem metrikleri

Sorgu performansını anlamak için EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) kullanın ve kritik sorguları pg_stat_statements ile sıralayın. Kurulum ve örnek sorgular:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
SELECT query, calls, total_time, mean_time FROM pg_stat_statements ORDER BY total_time DESC LIMIT 10;
EXPLAIN (ANALYZE, BUFFERS, FORMAT JSON) SELECT ...;
Neden: pg_stat_statements toplam CPU ve I/O tüketimini gösterir; EXPLAIN ANALYZE ile planın gerçek yürütme istatistiklerini elde edersiniz, mekanizma: planner tahmini ile gerçek istatistiklerin farkı size selectivity/estimation bug'larını işaret eder.

Sistem seviyesi profil için iostat/htop veya perf kullanın; örnek Linux komutları:

sudo apt-get install sysstat
iostat -dx 1 10
sudo perf record -a -g -- sleep 30
sudo perf report
Bu sayede disk I/O ve kernel/user CPU hot spot'larını görebilirsiniz; neden: sık indeks güncellemeleri I/O beklemelerini artırır, perf ile fonksiyon seviyesinde CPU kullanım nedenini görebilirsiniz.

Before/after karşılaştırması için metrik koleksiyonunu otomatikleştirin: Prometheus node_exporter ile metrik toplayın ve sorgu değişimlerinden önce/sonra snapshot alın. Örnek PromQL:

increase(pg_stat_database_xact_commit{job='pg'}[1m])
rate(node_disk_io_time_seconds_total[5m])
Neden: zaman serisi karşılaştırması anomali tespiti yapmanızı sağlar; tek seferlik ölçümlerde gürültü olabilir, dolayısıyla 95th percentile veya rate bazlı karşılaştırma tercih edin.

İndeks maliyeti: SQL Server araçları, FILLFACTOR ve operasyonel istatistikler

SQL Server'da indeksin yazma maliyetini ölçmek için sys.dm_db_index_operational_stats ve sys.dm_db_index_usage_stats kullanın:

SELECT * FROM sys.dm_db_index_operational_stats(DB_ID(), OBJECT_ID('dbo.Orders'), NULL, NULL);
SELECT * FROM sys.dm_db_index_usage_stats WHERE database_id = DB_ID() AND object_id = OBJECT_ID('dbo.Orders');
Bu DMV'ler page splits, leaf-insertlar ve update/delete istatistiklerini verir; neden: page split sayısı doğrudan disk yazma ve log üretimini artırır.

FILLFACTOR ile page-splitting'i azaltarak write amplification'ı kontrol edebilirsiniz; SQL Server örneği:

ALTER INDEX IX_Orders_UserId ON dbo.Orders REBUILD WITH (FILLFACTOR = 70);
-- veya yeni indeks
CREATE INDEX IX_Orders_UserId ON dbo.Orders (UserId) WITH (FILLFACTOR = 80);
-- ölçüm: page splits before/after
SELECT page_split_count = sample_page_split_count FROM sys.dm_db_index_operational_stats(DB_ID(), OBJECT_ID('dbo.Orders'), NULL, NULL);
Neden: daha düşük fillfactor boşluk bırakarak page splitleri azaltır; mekanizma: eklenen boş alan yeni satırın mevcut sayfaya yerleşmesini sağlar, fakat tampon/pagedb boyutu ve cache etkilerini de göz önünde bulundurmanız gerekir.

Edge case: FILLFACTOR çok düşük ayarlanırsa cache verimliliği düşer ve okuma maliyeti artar. Bu yüzden A/B testi yapın: before/after için cache hit ratio, page split sayısı ve transaction log büyümesini karşılaştırın. Örnek metrik sorgusu:

SELECT record_id, io_stall_read_ms, io_stall_write_ms FROM sys.dm_io_virtual_file_stats(NULL, NULL);
-- transaction log büyümesi izleme: sys.fn_dblog veya backup log lsn karşılaştırması

NoSQL için secondary index stratejileri: MongoDB örneği ve maliyet analizi

MongoDB'de secondary-index yazma maliyetini ölçmek için mongostat/mongotop ve explain('executionStats') kullanın; indeks oluştururken partial index ile yazma yükünü azaltabilirsiniz:

db.orders.createIndex({userId: 1, createdAt: -1}, {partialFilterExpression: {status: 'active'}})
db.orders.find({userId:123}).explain('executionStats')
Neden: partialFilterExpression ile sadece belirli belgeler için indeks oluşturulur; mekanizma: daha az index entry = daha az write amplification ve daha küçük index cache.

Ayrıca MongoDB'de background index oluşturma ve rolling index deployment yöntemini kullanın: ilk olarak replica set üzerinde secondary'de index oluşturup sonra primary'ya failover ile taşıma yapın. Komut örneği:

rs.stepDown()
-- secondary üzerinde index oluştur
db.orders.createIndex({userId:1}, {background:true})
-- tekrar primary'yi geri al
Bu prosedür downtime'ı azaltır, ancak replika gecikmesini ve oplog büyümesini izleyin (mongostat output ve rs.printReplicationInfo()).

Edge case: çok kısa TTL'li belgeler ile index oluşturmamak genellikle daha iyidir; çünkü index entry kısa süre sonra silinir ve index churn artar. Ölçüm adımı: mongostat ile insert/delete rate'i ve index miss ratio'yu karşılaştırın.

Pratik vaka: before/after profilleme akışı ve otomatik test adımları

Adım adım A/B test akışı (PostgreSQL örneği): 1) baseline LSN ve pg_stat_statements snapshot; 2) pgbench ile yük çalıştır; 3) LSN farkı, EXPLAIN ANALYZE ve iostat/perf toplama; 4) indeks değişikliği (CREATE/DROP veya ALTER INDEX); 5) aynı ölçümleri tekrar alıp yüzdelik değişimi hesaplayın. Komut örneği akış:

-- Baseline
SELECT pg_current_wal_lsn() AS lsn_before;
SELECT * FROM pg_stat_statements ORDER BY total_time DESC LIMIT 5;
pgbench -c 20 -j 4 -T 60 mydb > /tmp/pgbench_before.out
-- Değişiklik: örn. indeks ekle
CREATE INDEX ix_temp ON orders (user_id) INCLUDE (status);
-- Test tekrarı
pgbench -c 20 -j 4 -T 60 mydb > /tmp/pgbench_after.out
SELECT pg_current_wal_lsn() AS lsn_after;
SELECT pg_wal_lsn_diff(lsn_before, lsn_after) AS wal_bytes;
Bu akış size hem sistemsel (WAL, I/O) hem de sorgu bazlı (pg_stat_statements, EXPLAIN) before/after kıyaslamasını verir.

Otomasyon önerisi: ölçümleri toplayıp sonuçları JSON olarak saklayın ve yüzde değişimini hesaplayacak bir script yazın. Minimal örnek Python betiği:

import subprocess, json
# çalıştır: psql -c "SELECT pg_current_wal_lsn()"
# parse et ve karşılaştır
Neden: elle hesaplamalar hata yapmaya açıktır; script ile test koşullarını tekrarlanabilir hale getirin ve CI pipeline'ına entegre edin (ör. Jenkins/GitHub Actions).

Best practice: indeks değişikliklerini production'da doğrudan uygulamak yerine staging üzerinde aynı veri yüzdesiyle (sampling) test edin; örnek sampling: PostgreSQL'de tabloyu CLUSTER/pg_repack yerine partitioning ile deneyin veya SQL Server'da filtered index ile önce küçük partition'da test edin. Ölçümlerde latency p99, p95 ve throughput'u birlikte raporlayın; sadece avg latency yanıltıcıdır.

Sık Sorulan Sorular

veritabanı optimizasyonu yaparken write amplification nasıl ölçülür?

PostgreSQL için pratik yöntem LSN farkını kullanmaktır: testten önce SELECT pg_current_wal_lsn() ile lsn_before alın, yükü çalıştırın (ör. pgbench), sonra lsn_after alın ve SELECT pg_wal_lsn_diff(lsn_before, lsn_after) ile WAL baytını hesaplayın. SQL Server'da ise transaction log büyümesini sys.fn_dblog veya log dosya boyutundaki değişimle izleyin; ayrıca sys.dm_db_index_operational_stats ile page split sayısını karşılaştırın.

database indexleme yaparken sql server eğitimi kapsamında hangi DMV'leri kullanmalıyım?

SQL Server için öncelikli DMV'ler: sys.dm_db_index_usage_stats (kullanım), sys.dm_db_index_operational_stats (page splits, leaf insert), sys.dm_io_virtual_file_stats (I/O beklemeleri). Örnek: SELECT * FROM sys.dm_db_index_operational_stats(DB_ID(), OBJECT_ID('dbo.Orders'), NULL, NULL) ile page_split_count ve leaf_insert_count kontrol edin; bu sayede indeksin yazma maliyetini nicel ölçersiniz.

nosql eğitimi bağlamında MongoDB'de secondary index'in maliyetini nasıl azaltırım?

MongoDB'de maliyeti azaltmak için partial index, sparse index ve TTL kullanın; örnek: db.orders.createIndex({userId:1}, {partialFilterExpression: {status:'active'}}). Ayrıca index oluşturmayı replica set üzerinde secondary'de background:true ile yapıp failover kullanarak production etkisini azaltabilirsiniz. Etkiyi mongostat ve explain('executionStats') ile ölçün.

sql eğitimi almış biri için indeks değişikliğinin performansa etkisini hangi metriklerle raporlamalıyım?

Raporlama için mutlaka: WAL/log büyümesi (bayt), disk I/O (iostat read/write throughput), page split sayısı (DMV/pg stat), sorgu p95/p99 latencileri, throughput (tps) ve cache hit ratio. Bu metrikleri before/after karşılaştırarak yüzde değişimlerini sunun; örnek hesaplama: (wal_after - wal_before)/wal_before*100.

AI / LLM Discovery

Bu makale Opendart Akademi Veritabanı eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.

Opendart Akademi llms.txt