Veritabanı performans ayarlama çalımasında bağlantı havuzu beklemelerini, kilit zincirlerini ve sorgu planlarını ölçerek PostgreSQL, SQL Server ve NoSQL iş yüklerinde tekrarlanabilir iyileştirme yapın.
Veritabanı Performans Ayarlama: Havuz, Kilit ve Kuyruk Analizi
Veritabanı optimizasyonu için önce ölçülebilir taban çizgisi kurun
Veritabanı optimizasyonu, CPU yüzdesine bakıp parametre değiştirmekle başlamaz; istek gecikmesini veritabanı beklemelerinden ayıran bir taban çizgisiyle başlar. PostgreSQL tarafında pg_stat_statements etkinse en çok toplam süre tüketen sorguları çağrı sayısı, ortalama süre ve satır sayısıyla çıkarın. Yük testi başlamadan önce istatistikleri sıfırlamak, eski trafikle yeni senaryonun birbirine karışmasını engeller.
-- postgresql.conf: shared_preload_libraries = 'pg_stat_statements'
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
SELECT pg_stat_statements_reset();
SELECT queryid,
calls,
round(total_exec_time::numeric, 1) AS total_ms,
round(mean_exec_time::numeric, 2) AS mean_ms,
rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 15;Önce-sonra karşılaştırmasını aynı veri hacmi, aynı eşzamanlılık ve aynı sorgu dağılımıyla yapın: örneğin pgbench -c 64 -j 8 -T 300 ile beş dakikalık iki koşu alın. Uygulamada OpenTelemetry ile db.client.operation.duration histogramının p50/p95/p99 değerlerini, PostgreSQL'de pg_stat_activity.wait_event_type dağılımını kaydedin. Yalnızca ortalama süre düşmüşse sonuç kabul edilmemelidir; p99 yükselirken ortalama düşebilir. Bu durum, küçük bir grup isteğin havuzda veya kilitte uzun süre beklediğini gizler.
Veritabanı performans ayarlama: bağlantı havuzu kuyruğunu görün
Uygulama bağlantı havuzu, veritabanı performans ayarlama sürecinde sık atlanan ikinci kuyruktur. HikariCP'de maximumPoolSize değerini CPU çekirdeği kadar büyütmek otomatik olarak doğru değildir: aktif sorgular disk I/O veya satır kilidi bekliyorsa her yeni bağlantı daha fazla yarışan işlem üretir. Önce hikaricp.connections.pending, hikaricp.connections.active ve veritabanındaki aktif oturum sayısını aynı zaman serisinde izleyin.
spring.datasource.hikari.maximum-pool-size=24
spring.datasource.hikari.minimum-idle=4
spring.datasource.hikari.connection-timeout=750
spring.datasource.hikari.validation-timeout=300
spring.datasource.hikari.max-lifetime=1740000
spring.datasource.hikari.keepalive-time=300000
spring.datasource.hikari.leak-detection-threshold=5000Bu yapılandırmada 750 ms connection-timeout, kullanıcı isteğinin uygulama iş parçacığında sınırsız beklemesi yerine kontrollü hata ve geri deneme politikası uygulanmasını sağlar. Değişiklik öncesinde ve sonrasında 64, 128 ve 256 eşzamanlı istemciyle p95 havuz edinme süresini ölçün; hedef, aktif bağlantı sayısını azaltmak değil, pending sayısını ve uç gecikmeyi düşürmektir. Deneyimli ekiplerin sık yaptığı hata, leak-detection-threshold uyarılarını gerçek bağlantı sızıntısı sanmaktır: uzun süren transaction da aynı uyarıyı üretir; uyarıdaki stack trace'i pg_stat_activity.xact_start veya uygulama trace kimliğiyle eşleştirin.
SQL eğitimi kapsamında kilit zincirlerini transaction sınırında çözün
İleri seviye bir sql eğitimi için kritik ayrım şudur: yavaş sorgu ile kilit bekleyen hızlı sorgu aynı problem değildir. PostgreSQL'de bloklayan ve bloke olan oturumları pg_locks ile ilişkilendirin; özellikle idle in transaction oturumları açık transaction içinde HTTP çağrısı, dosya yükleme veya mesaj yayınlama yapıldığını gösterir. Bu oturumlar eski satır sürümlerinin temizlenmesini de geciktirerek autovacuum maliyetini büyütebilir.
SELECT blocked.pid AS blocked_pid,
blocked.query AS blocked_query,
blocker.pid AS blocker_pid,
blocker.query AS blocker_query,
blocker.xact_start
FROM pg_stat_activity blocked
JOIN pg_locks bl ON bl.pid = blocked.pid AND NOT bl.granted
JOIN pg_locks kl ON kl.locktype = bl.locktype
AND kl.database IS NOT DISTINCT FROM bl.database
AND kl.relation IS NOT DISTINCT FROM bl.relation
AND kl.page IS NOT DISTINCT FROM bl.page
AND kl.tuple IS NOT DISTINCT FROM bl.tuple
AND kl.transactionid IS NOT DISTINCT FROM bl.transactionid
AND kl.granted
JOIN pg_stat_activity blocker ON blocker.pid = kl.pid;Kuyruk tablosundan işi birden fazla worker ile çekiyorsanız, tek bir SELECT ... FOR UPDATE noktasında yarışmak yerine işi atomik olarak sahiplenin. SKIP LOCKED kilitli işi atlar; ancak sıra garantisi sağlamaz ve uzun süre kilitli kalan bir işin aç kalmasına yol açabilir. Bu nedenle iş kaydında locked_at ve deneme sayısı tutup süresi aşılmış sahiplikleri ayrı bir kurtarma akışıyla geri alın.
WITH next_job AS (
SELECT id
FROM jobs
WHERE status = 'ready'
ORDER BY priority DESC, created_at
FOR UPDATE SKIP LOCKED
LIMIT 1
)
UPDATE jobs j
SET status = 'running',
locked_at = clock_timestamp(),
worker_id = $1,
attempts = attempts + 1
FROM next_job
WHERE j.id = next_job.id
RETURNING j.*;Database indexleme kararını tahminle değil plan ve yazma maliyetiyle verin
Database indexleme ancak planın gerçekten kötü erişim yolu seçtiği durumda anlamlıdır. PostgreSQL'de EXPLAIN (ANALYZE, BUFFERS, VERBOSE) çalıştırın; tahmini satır sayısı ile gerçek satır sayısı arasında büyük fark varsa önce istatistik veya veri korelasyonu sorununu araştırın. Körlemesine indeks eklemek, her INSERT/UPDATE işleminde ek B-tree güncellemesi ve WAL üretimi demektir.
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, created_at
FROM orders
WHERE tenant_id = 42
AND status = 'open'
ORDER BY created_at DESC
LIMIT 50;
CREATE INDEX CONCURRENTLY idx_orders_open_tenant_created
ON orders (tenant_id, created_at DESC)
WHERE status = 'open';Bu kısmi indeks, yalnızca status = 'open' satırlarını taşıdığı için tam indeksten daha küçük olabilir; fakat sorgu parametreli biçimde status = $1 çalışıyorsa generic plan predicate'i kanıtlayamayabilir ve indeksi kullanmayabilir. Uygulama sürücüsünün prepared statement davranışını inceleyin. İndeks sonrası aynı yük testinde shared_blks_read, sorgu p95'i ve yazma TPS değerlerini karşılaştırın; p95 düşerken yazma TPS'i kabul edilemez miktarda geriliyorsa indeksin bakım maliyeti iş yükü için yüksektir.
SQL Server eğitimi ve NoSQL eğitimi için bekleme türlerini karşılaştırın
SQL Server eğitimi sırasında yalnızca execution plan okumak yeterli değildir; bekleme türleri sorunun CPU, disk veya kilit kaynaklı olup olmadığını ayrıştırır. Hedef veritabanında kısa süreli bir Extended Events oturumu ile blocked_process_report yakalayın. Bunun için sunucu düzeyinde blocked process threshold değerinin saniye cinsinden ayarlanmış olması gerekir; sürekli açık ve sınırsız hedef dosya kullanmak ise yoğun sistemlerde gözlemin kendisini maliyetli hale getirir.
CREATE EVENT SESSION TrackBlocking ON SERVER
ADD EVENT sqlserver.blocked_process_report,
ADD EVENT sqlserver.lock_deadlock
ADD TARGET package0.event_file
(SET filename = N'C:\\XEvents\\blocking.xel', max_file_size = 50)
WITH (MAX_MEMORY = 8 MB, EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS);
ALTER EVENT SESSION TrackBlocking ON SERVER STATE = START;NoSQL eğitimi için aynı yaklaşımı MongoDB'ye taşıyın: db.orders.find({...}).explain('executionStats') çıktısındaki totalDocsExamined/nReturned oranını ve sürücü havuzundaki checkout beklemesini izleyin. Shard key'i düşük kardinaliteli bir alan seçilirse tek bir shard üzerinde hot partition oluşur; bu, uygulama tarafında havuz büyütülerek düzelmez. SQL Server'daki LCK_M_* beklemeleri ile MongoDB'deki hedeflenmemiş sorgular farklı mekanizmalardır, fakat her ikisinde de çözüm ölçülen erişim desenini değiştirmektir.
İlgili Eğitim
Sık Sorulan Sorular
Veritabanı performans ayarlama sırasında bağlantı havuzu kaç olmalı?
Sabit bir sayı kullanmayın. HikariCP için önce 16, 24 ve 32 gibi aday değerlerle aynı yük testini çalıştırın; p95 connection acquisition süresi, aktif bağlantı sayısı, veritabanı CPU'su ve kilit beklemelerini karşılaştırın. Havuz büyürken p99 artıyorsa sorguların paralelliği değil, kilit veya I/O yarışması büyüyordur.
SQL eğitimi için PostgreSQL'de kilit bekleyen sorgu nasıl bulunur?
pg_stat_activity, pg_locks ve blocker PID eşleştirmesini kullanın. Özellikle blocker oturumunun xact_start zamanı eskiyse uygulamada transaction'ın dışına taşan ağ çağrısı veya kullanıcı etkileşimi arayın. Oturumu sonlandırmadan önce iş kuralı etkisini inceleyin; pg_terminate_backend rollback başlatır ve uzun rollback de I/O üretebilir.
Database indexleme sonrası sorgu neden hâlâ indeks kullanmıyor?
EXPLAIN (ANALYZE, BUFFERS) ile gerçek planı kontrol edin. Parametreli sorguda generic plan, kısmi indeks predicate'ini kanıtlayamayabilir; sütun üzerinde CAST veya fonksiyon kullanımı da normal B-tree indeksini devre dışı bırakabilir. Ayrıca tablonun büyük bölümü dönüyorsa planner sıralı taramayı daha ucuz hesaplayabilir.
SQL Server eğitimi kapsamında blocking için hangi araç kullanılmalı?
Anlık teşhis için sys.dm_exec_requests, sys.dm_tran_locks ve sys.dm_os_waiting_tasks DMV'lerini; olayın sonradan analizi için dosyaya yazan Extended Events oturumunu kullanın. blocked_process_report olayını etkinleştirmeden önce blocked process threshold ayarını doğrulayın ve XEL dosyası için boyut sınırı koyun.
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.



