1. İlk soru: Bu sorgu ne kadar veri okuyor?
ClickHouse yavaşlığında sonuç setinin küçük olması çok yanıltıcıdır. Sorgu ekrana 50 satır döndürebilir ama arka planda milyarlarca satır tarıyor olabilir. Bu yüzden ilk bakılacak metrik sadece duration değil; read_rows ve read_bytes değeridir.
Kullanıcının gerçek sorusu genellikle “Bu sorgu neden yavaş?”tır. Cevap çoğu zaman şudur: ClickHouse gereğinden fazla parça, satır veya kolon okuyor. Aşağıdaki sorgu son yavaş SELECT işlemlerini hangi tabloya, kaç satıra ve kaç byte okumaya mal olduğunu gösterir.
Son yavaş SELECT sorgularını ölçme
SELECT event_time, query_duration_ms, read_rows, formatReadableSize(read_bytes) AS read_size, result_rows, memory_usage, left(query, 220) AS query FROM system.query_log WHERE type = 'QueryFinish' AND event_time > now() - INTERVAL 1 HOUR AND query_kind = 'Select' ORDER BY query_duration_ms DESC LIMIT 20;
read_rows yüksek, result_rows düşükse problem çoğunlukla veri eleme tarafındadır; daha fazla CPU eklemekten önce sorgunun okuduğu veri azaltılmalıdır.
2. EXPLAIN ile primary key ve partition pruning kontrolü
ClickHouse klasik B-tree indeks mantığıyla çalışmaz. MergeTree tabloda ORDER BY ifadesi primary key yapısını belirler; ClickHouse bu sıralama sayesinde granule atlar. WHERE koşulunuz ORDER BY sırasının sol tarafını kullanmıyorsa veri atlama zayıflar.
Örneğin tablo ORDER BY (tenant_id, event_name, created_at) ile kurulmuşsa tenant_id ve event_name filtreleri çok değerlidir. Sadece created_at filtresi kullanırsanız ClickHouse tarih aralığını görse bile tenant boyutunda daha geniş okuma yapabilir.
- WHERE koşulu ORDER BY ifadesinin ilk kolonlarını kullanıyor mu?
- Tarih filtresi partition anahtarıyla uyumlu mu?
- WHERE içinde kolona fonksiyon uygulanıp pruning bozuluyor mu?
- Sorgu ihtiyacı olmayan kolonları SELECT * ile okuyor mu?
- FINAL kullanımı gerçekten gerekli mi, yoksa tablo modeli değişmeli mi?
Pruning kontrolü için EXPLAIN
EXPLAIN indexes = 1 SELECT event_name, count() FROM events WHERE tenant_id = 'acme' AND event_name = 'ödeme akışı_completed' AND created_at >= now() - INTERVAL 7 DAY GROUP BY event_name;
Fonksiyonlu WHERE yerine aralık kullanma
-- Kötü: created_at üzerinde fonksiyon pruning'i zayıflatabilir WHERE toDate(created_at) = today() -- İyi: ham kolon üzerinde aralık koşulu WHERE created_at >= today() AND created_at < today() + INTERVAL 1 DAY
3. Tablo tasarımı sorgu niyetine uymuyorsa düzeltme nerede yapılır?
Sorgu her zaman tenant_id, event_name ve zaman aralığıyla çalışıyorsa tablo ORDER BY ifadesi bunu yansıtmalıdır. Buna karşılık kullanıcı_id üzerinden nokta arama yapıyorsanız başka bir projection, materialized view veya ayrı tablo gerekebilir. Tek tabloyla her sorguyu mükemmel yapmak çoğu zaman mümkün değildir.
Partition anahtarı performans indeksinden çok veri yönetimi sınırıdır. Çok ince partition, parça sayısını artırır; çok kaba partition ise silme ve yaşam döngüsü işlerini zorlaştırır. Zaman serisi event verisinde aylık veya günlük partition kararı veri hacmine göre verilmelidir.
Pano sorgusu için temel tablo
CREATE TABLE events ( tenant_id String, event_name LowCardinality(String), user_id String, created_at DateTime, properties String ) ENGINE = MergeTree PARTITION BY toYYYYMM(created_at) ORDER BY (tenant_id, event_name, created_at);
Sık kullanılan metrik için özet tablo
CREATE MATERIALIZED VIEW events_daily_mv ENGINE = SummingMergeTree PARTITION BY toYYYYMM(day) ORDER BY (tenant_id, event_name, day) AS SELECT tenant_id, event_name, toDate(created_at) AS day, count() AS events FROM events GROUP BY tenant_id, event_name, day;
Pano aynı agregasyonu sürekli çalıştırıyorsa, ham tabloyu her seferinde taramak yerine özet tablo kullanmak daha doğru çözümdür.
4. Hızlandı mı, yoksa sadece şanslı bir koşu mu?
Değişiklikten sonra yalnızca “süre düştü mü?” diye bakmayın. Aynı sorgunun read_rows, read_bytes, memory_usage ve query_duration_ms değerlerini önce/sonra karşılaştırın. Okunan veri azalmadıysa hızlanma geçici önbellek etkisi, daha sakin bir an veya tesadüf olabilir.
TürkDB tarafındaki ilişki burada operasyonel karardır: önce sorgu ve tablo tasarımını ölçümle düzeltirsiniz; hâlâ kapasite sınırına geliyorsanız cluster tier veya kaynak artışı anlamlı hale gelir.
TürkDB ve ClickHouse çalışma akışı
turkdb cluster get product-analytics turkdb cluster events product-analytics --limit 20 turkdb connect product-analytics --no-tunnel
Bu komutlar sorgu optimizasyonunun yerine geçmez; doğru cluster, bağlantı ve olay durumunu doğrulayıp ClickHouse içindeki query_log/EXPLAIN incelemesine güvenli zemin hazırlar.