Sorun: aynı sorgu binlerce farklı metin
Günlükte şu iki satır aynı sorgudur, ama metinleri farklıdır:
SELECT customer_id, full_name, segment FROM bank_customers WHERE customer_id = 412 SELECT customer_id, full_name, segment FROM bank_customers WHERE customer_id = 87
Metne göre gruplarsan her biri tek satır görünür ve pahalı olan gizlenir: tek çağrısı ucuz, bin çağrısı pahalı bir sorguyu göremezsin. Çözüm, sabitleri atıp parmak izi çıkarmaktır:
SELECT customer_id, full_name, segment FROM bank_customers WHERE customer_id = ?
ops_ tabloları hayali bir portal için tohumlu üreteçle kuruldu. Gerçek bir sistemden alınmadı; süre ve okuma değerleri ölçüm değildir. Motor SQLite olduğu için günlükteki SQL Server sorguları çalıştırılmaz, metin olarak incelenir. Tabloları sorgularsın, sistem yönetimi komutlarını yalnız okursun.Ne kadar sıkışıyor?
Günlükte 7.607 satır, 3.057 farklı metin var. Parmak izi sayısına kendin bak:
SELECT COUNT(*) AS satir,
COUNT(DISTINCT query_text) AS farkli_metin,
COUNT(DISTINCT REGEXP_REPLACE(REGEXP_REPLACE(query_text, '''[^'']*''', '?'), '[0-9]+', '?')) AS parmak_izi
FROM ops_query_log;
Adım adım normalleştirme
- Tırnaklı metinleri
?yap:'[^']*'. Önce bu adım gelir, çünkü metnin içinde rakam olabilir. - Sayıları
?yap:[0-9]+. - Değişken uzunluklu listeyi tek biçime indir:
IN (?, ?, ?)ileIN (?, ?)aynı sorgudur.
SELECT DISTINCT REGEXP_REPLACE(REGEXP_REPLACE(query_text, '''[^'']*''', '?'), '[0-9]+', '?') AS parmak_izi FROM ops_query_log WHERE query_text LIKE '%IN (%';
REGEXP_REPLACE için 'g' bayrağı ister, yoksa yalnız ilk eşleşmeyi değiştirir. Otomatik çeviri bunu ekler. Belgeye göre SQL Server'da REGEXP_REPLACE 2025 sürümüyle gelir, Azure SQL'de de vardır; 2022 ve öncesinde yoktur.En maliyetli 10 sorgu
WITH n AS (SELECT REGEXP_REPLACE(REGEXP_REPLACE(query_text, '''[^'']*''', '?'), '[0-9]+', '?') AS parmak_izi, logical_reads, duration_ms FROM ops_query_log) SELECT parmak_izi, COUNT(*) AS calisma, SUM(logical_reads) AS toplam_okuma, ROUND(AVG(duration_ms)) AS ort_ms FROM n GROUP BY parmak_izi ORDER BY toplam_okuma DESC, parmak_izi LIMIT 10;
Bu haftalık listede ilk sırayı gece ETL'i alır. Bu bir sorun mu? Kullanıcı gündüz şikâyet ediyorsa değil. Liste hangi zaman dilimi için sorusu olmadan anlamsızdır. Salı sabahı için filtrele, sonuç değişir.
Hangi "maliyet"?
| Ölçü | Yakaladığı | Kaçırdığı |
|---|---|---|
| Toplam okuma | Sunucuya en çok yük bindiren | Tek çağrısı yavaş ama seyrek olan |
| Ortalama süre | Kullanıcının beklediği | Çok sık çalışan ucuz sorgu; sıkışıklıkta herkes yavaşlar |
| Çalışma sayısı | Önbellek ya da toplu okuma adayı | Az çalışan pahalı sorgu |
Süre sıkışıklıktan etkilenir: suçsuz sorgu da uzar. Okuma sayısı yapılan işi gösterir. Bu yüzden önce okumaya, sonra süreye bak.
SQL Server'ın hazır parmak izi: query_hash
Normalleştirmeyi elle yapmak zorunda değilsin. Belgeye göre sys.dm_exec_query_stats içindeki query_hash, yalnız sabit değerleri farklı olan sorguların toplam kaynak kullanımını bulmak içindir. İzleme: DMV'ler dersindeki sorgu plan başına listeler; bu sorgu biçim başına toplar.
-- Yalnız okumak için
SELECT TOP 10 qs.query_hash,
SUM(qs.execution_count) AS calisma,
SUM(qs.total_logical_reads) AS toplam_okuma,
MIN(t.text) AS ornek_metin
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) t
GROUP BY qs.query_hash
ORDER BY toplam_okuma DESC;
- Bu görünümde satırın ömrü plana bağlıdır: plan önbellekten çıkınca kayıt da gider. Geçmişi saklamak için Query Store gerekir.
- Yalnız biten sorguları gösterir, süren sorgular yoktur.
- Belge, farklı
query_hashsayısının toplam sorgu sayısına oranını iş yükünün parametresiz olup olmadığını anlamak için kullanır. Yüksek çeşitlilik, plan önbelleğinin boşa harcandığına işaret eder.
Sınırlar ve kişisel veri
- Basit düzenli ifade her şeyi çözmez: yorumlar, büyük ve küçük harf, boşluk farkı, adında rakam olan sütunlar. Gerçek araçlar sorguyu ayrıştırır.
- Sorgu metni sabit değerlerle kişisel veri taşıyabilir. Ad ya da kimlik numarası günlüğe düşer. Normalleştirilmiş metni sakla, ham metne erişimi kısıtla, saklama süresi koy.