EXPLAIN, yavaş bir SQL sorgusunun veriye hangi adımlarla ulaştığını göstererek darboğazı görünür hâle getirir. Bir sorgu genellikle gereğinden geniş bir alanı taradığı, uygun erişim yolunu seçemediği, fazla sütun veya satır işlediği ya da filtre ve JOIN koşullarını verimsiz kullandığı için yavaşlar.
EXPLAIN çıktısını kesin bir “sonuç” gibi değil, veritabanı motorunun sorguyu nasıl planladığını gösteren bir teşhis raporu olarak okumak gerekir. SQL temellerini daha düzenli yapılandırmak isteyenler, online yazılım kursu içeriğiyle sorgu yazımından algoritmik düşünmeye kadar temel konuları birlikte çalışabilir.
EXPLAIN Yavaş Bir SQL Sorgusunu Nasıl Görünür Hâle Getirir?
Veritabanı, bir sorguyu çalıştırmadan önce hangi tabloya nasıl erişeceğini, filtreyi hangi aşamada uygulayacağını ve birden fazla tablo varsa JOIN işlemini hangi yöntemle yapacağını planlar. EXPLAIN bu planı, genellikle iç içe geçmiş işlem düğümleri şeklinde gösterir. Alt seviyelerde tablo veya indeks taramaları, üst seviyelerde filtreleme, sıralama, gruplayma ve JOIN adımları bulunabilir. ([postgresql.org](https://www.postgresql.org/docs/current/using-explain.html?utm_source=openai))
Aşağıdaki örnekte amaç, belirli bir müşterinin siparişlerini bulmaktır:
EXPLAIN
SELECT order_id, order_date, total_amount
FROM orders
WHERE customer_id = 42;
PostgreSQL gibi motorlarda plan çıktısında Seq Scan ifadesi tablonun baştan sona taranmasını, Index Scan ise uygun bir indeks üzerinden hedefli erişimi ifade edebilir. Ancak operatör adları ve çıktı biçimleri veritabanı motoruna göre değişir; bu nedenle bir planı yorumlarken kullanılan motorun resmî dokümantasyonundaki terimler esas alınmalıdır. ([postgresql.org](https://www.postgresql.org/docs/current/using-explain.html?utm_source=openai))
EXPLAIN çoğunlukla planlayıcının tahminlerini gösterir. EXPLAIN ANALYZE ise PostgreSQL dokümantasyonunda belirtildiği üzere sorguyu gerçekten çalıştırarak düğümlere ilişkin gerçekleşen süre ve satır bilgilerini de plana ekler. Bu nedenle özellikle veri değiştiren komutlarda dikkatli kullanılmalıdır; bir UPDATE veya DELETE komutunu analiz etmek gerçek değişikliklere yol açabilir. ([postgresql.org](https://www.postgresql.org/docs/18/sql-explain.html?utm_source=openai))
İlk teşhiste şu sorulara odaklanın:
- Veritabanı hangi erişim yöntemini seçmiş?
- Hangi tablo veya indeks üzerinde çalışıyor?
- Tahmini olarak kaç satırı inceliyor?
- Filtre koşulu tarama sırasında mı, yoksa daha sonra mı uygulanıyor?
- Bir sonraki plan adımına gereğinden fazla satır taşınıyor mu?
Tam Tablo Taraması ile İndeksli Erişim Nasıl Ayırt Edilir?

Tam tablo taramasında motor, aranan kayıt az sayıda olsa bile tablonun çok büyük bölümünü veya tamamını inceleyebilir. İndeksli erişimde ise filtre koşuluyla uyumlu bir indeks varsa, motor önce indeks üzerinden aday kayıtların konumunu bulur ve gerekli satırlara daha hedefli biçimde ulaşır. İndeks kullanılması her zaman daha iyi plan anlamına gelmez; tablonun küçük olması veya sorgunun satırların büyük bölümünü döndürmesi durumunda tam tarama makul olabilir.
| Özellik | Tam tablo taraması | İndeksli erişim | Teşhis yorumu |
|---|---|---|---|
| Erişim yöntemi | Tablodaki kayıtlar geniş biçimde incelenir | İndeks üzerinden hedefli kayıt araması yapılır | Filtre sütunuyla erişim yöntemi uyumlu mu kontrol edilir |
| İncelenen nesne | Doğrudan tablo | İlgili indeks ve gerektiğinde tablo | Planın hangi tablo veya indeks üzerinde çalıştığına bakılır |
| Satır miktarı | Geniş bir aday kümesi oluşabilir | Daha dar bir aday kümesi hedeflenebilir | Tahmini satır sayısı ile filtre sonucunu karşılaştırın |
| Filtreleme aşaması | Satırlar okunduktan sonra filtre uygulanabilir | Filtre, indeks aramasına katkı sağlayabilir | Filter ile indeks koşulunun nerede göründüğünü ayırın |
| Üst adıma taşınan veri | Gereğinden fazla satır taşınabilir | Üst düğüme daha sınırlı veri aktarılabilir | JOIN, sıralama veya gruplama öncesindeki hacmi inceleyin |
İndeks yokken aynı sorgu kavramsal olarak şöyle bir plan üretebilir:
Seq Scan on orders
Filter: (customer_id = 42)
Bu planda koşul bulunmasına rağmen motor tabloyu geniş biçimde tarayıp her satırı filtreyle karşılaştırıyor olabilir. Uygun bir indeks oluşturulduktan sonra planın erişim bölümü şu yapıya yaklaşabilir:
Index Scan using idx_orders_customer_id on orders
Index Cond: (customer_id = 42)
Buradaki önemli fark yalnızca Seq Scan ve Index Scan ifadelerini görmek değildir. Filtrenin Filter olarak sonradan mı, yoksa Index Cond olarak indeks aramasının parçası şeklinde mi uygulandığını da incelemek gerekir. Bu ayrım, yavaşlığın geniş taramadan mı yoksa planın üst adımlarındaki başka bir işlemden mi kaynaklandığını anlamaya yardımcı olur. ([postgresql.org](https://www.postgresql.org/docs/current/using-explain.html?utm_source=openai))
EXPLAIN Çıktısı Satır Satır Nasıl Okunur?
EXPLAIN çıktısını tek bir “hızlı mı, yavaş mı?” etiketi gibi değil, sorgunun veritabanında izlediği yolun krokisi gibi okuyun. Aşağıdaki örnek PostgreSQL sözdizimiyle hazırlanmıştır. PostgreSQL EXPLAIN dokümantasyonu, plan düğümlerindeki maliyet, tahmini satır ve gerçek çalışma değerlerinin nasıl yorumlandığını açıklar.
DROP TABLE IF EXISTS orders;
CREATE TABLE orders (id integer, customer_id integer, total numeric);
INSERT INTO orders
SELECT n, (n % 10000) + 1, (n % 500) + 10
FROM generate_series(1, 100000) AS n;
EXPLAIN SELECT * FROM orders WHERE customer_id = 42;
CREATE INDEX idx_orders_customer_id ON orders (customer_id);
ANALYZE orders;
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM orders WHERE customer_id = 42;
İlk planda indeks yoksa PostgreSQL’in Seq Scan seçmesi beklenebilir. Temsili olarak plan satırı şu yapıda görülebilir:
Seq Scan on orders (cost=0.00..1834.00 rows=10 width=...)
Filter: (customer_id = 42)
İndeks oluşturulduktan sonra aynı sorgu için temsili plan şu biçime yaklaşabilir:
Index Scan using idx_orders_customer_id on orders
(cost=0.29..40.00 rows=10 width=...)
Index Cond: (customer_id = 42)
Buradaki sayılar veri miktarına, istatistiklere ve çalışma ortamına göre değişir; önemli olan planın Seq Scan yerine Index Scan kullanmasıdır. cost=a..b ifadesinde ilk değer başlangıç maliyetini, ikinci değer tüm çıktıyı üretmeye ilişkin tahmini toplam maliyeti gösterir. rows, taranan değil, düğümün üst düğüme aktarmayı beklediği satır sayısıdır. EXPLAIN ANALYZE kullanıldığında actual time, actual rows ve loops gibi gerçek çalışma değerleri de eklenir.
- Hangi tabloya gidiyor? Satırdaki tablo adını ve erişim türünü belirleyin.
- Kaç satır bekliyor?
rowstahmini ileactual rowsdeğerini karşılaştırın. - Hangi koşulu uyguluyor?
Filterkoşulun taramadan sonra,Index Condise indeks aramasının parçası olduğunu gösterir. - Bir sonraki adıma ne taşıyor? İç içe planlarda alt düğümün çıktısının üst düğüme nasıl aktarıldığını izleyin.
Yavaşlığın Tipik Nedenleri Nasıl Teşhis Edilir?

EXPLAIN, yavaşlığın nedenini tek başına düzeltmez; ancak hangi aşamada gereksiz iş yapıldığını görünür hâle getirir. Seq Scan her zaman hata değildir. Küçük tabloda veya sorgu satırların büyük bölümünü döndürüyorsa tabloyu baştan sona okumak, indeks üzerinden çok sayıda satır toplamaktan daha uygun olabilir.
| Olası neden | Plan üzerindeki işaret | İlk inceleme |
|---|---|---|
| Eksik indeks | Geniş Seq Scan, yüksek tahmini satır |
Filtre sütununu ve sorgu seçiciliğini değerlendirin. |
| Düşük seçicilik | İndeks kullanılsa da çok fazla satır üretilmesi | Koşulun tablonun ne kadarını döndürdüğüne bakın. |
| Fonksiyonlu koşul | Koşulun Filter olarak kalması |
Sütun üzerinde dönüşüm veya fonksiyon kullanılıp kullanılmadığını kontrol edin. |
| Gereksiz veri taşıma | Geniş width ve SELECT * |
Gerçekten gereken sütunları seçin. |
Örneğin WHERE LOWER(email) = '[email protected]' veya tarih sütununa dönüşüm uygulayan koşullar, normal sütun indeksinin doğrudan kullanılmasını zorlaştırabilir. Bunun sonucu motorun ve indeks tasarımının özelliklerine bağlıdır; bu nedenle planda koşulun Index Cond mı yoksa yalnızca Filter mı olduğuna bakılmalıdır.
rows ile actual rows arasında belirgin fark varsa sorgu planlayıcısının veri dağılımı hakkındaki tahminleri güncel veya yeterince ayrıntılı olmayabilir. PostgreSQL’de ANALYZE, planlayıcının kullandığı tablo istatistiklerini toplar; ancak uygun işlem ve zamanlama motor yapılandırmasına göre değişebilir.
Son olarak SELECT * yalnızca sorgu planını değil, ağ üzerinden taşınan veri miktarını ve uygulamanın bakım yükünü de büyütebilir. Karar basittir: ekran veya işlem yalnızca üç sütuna ihtiyaç duyuyorsa, dört yüz sütun taşımayın. İndeks seçimini ise dönen satır miktarı, veri dağılımı ve ekleme-güncelleme maliyetiyle birlikte değerlendirin.
EXPLAIN ile Sorgu Teşhisi İçin Uygulanabilir Kontrol Listesi
Yavaş bir SQL sorgusunu düzeltmenin en güvenli yolu, aynı anda birçok değişiklik yapmak değil; sorguyu izole edip planı adım adım incelemektir. Aşağıdaki kontrol listesi, ölçüm, plan okuma, tek değişiklik ve yeniden doğrulama döngüsüyle ilerler.
- Sorguyu ve gerçek filtre koşullarını izole edin. Teşhis sorusu: Yavaşlık gerçekten bu sorgudan mı kaynaklanıyor, yoksa uygulamadaki başka bir işlem mi bekliyor? Karar: Sorguyu parametreleriyle birlikte tek başına çalıştırın; gereksiz uygulama kodunu ve sonuç işleme adımlarını ayırın.
- Ölçüm koşullarını sabitleyin. Teşhis sorusu: Aynı sorgu her denemede benzer veri, parametre ve sunucu koşullarıyla mı çalışıyor? Karar: Aynı filtre değerlerini, aynı veritabanını ve mümkün olduğunca benzer yük koşullarını kullanın. Aksi hâlde iki planı veya iki süreyi doğrudan karşılaştırmayın.
- EXPLAIN veya doğrulanmış motor komutunu alın. Teşhis sorusu: Elinizde yalnızca sorgunun süresi mi var, yoksa veritabanının seçtiği işlem planı da mevcut mu? Karar: Önce salt planı inceleyin. PostgreSQL örneğinde güvenli bir okuma şu şekilde yapılabilir:
EXPLAIN
SELECT id, total
FROM orders
WHERE customer_id = 42
AND status = 'paid';
EXPLAIN (ANALYZE, BUFFERS)
SELECT id, total
FROM orders
WHERE customer_id = 42
AND status = 'paid';
EXPLAIN ANALYZE sorguyu gerçekten çalıştırarak tahmini ve gerçekleşen satır sayılarını karşılaştırmaya yarar; bu nedenle üretim ortamında kullanım biçimi ve sorgunun yan etkileri motorun resmi dokümantasyonuna göre değerlendirilmelidir. PostgreSQL’in resmi açıklamasında da plan düğümlerinin tahmini satırlarla birlikte gerçek çalışma bilgilerini gösterebildiği belirtilir. PostgreSQL EXPLAIN dokümantasyonu bu ayrımı ve plan düğümlerinin yapısını ayrıntılandırır.
- En geniş veri işleyen adımı bulun. Teşhis sorusu: Planın hangi adımı en fazla satırı okuyor veya üretiyor? Karar: En üstteki düğüme bakıp karar vermeyin; alt düğümleri de takip edin. Büyük bir tarama, pahalı sıralama veya tekrar tekrar çalışan iç sorgu öncelikli inceleme alanıdır.
- Tam tarama ile indeks erişimini ayırt edin. Teşhis sorusu: Motor tabloyu baştan sona mı okuyor, yoksa filtreye uygun satırlara indeks üzerinden mi ulaşıyor? Karar: Tam tarama küçük tabloda makul olabilir; büyük tabloda ise filtre seçici olduğu hâlde tüm satırların okunması araştırılmalıdır.
- Tahmini satır miktarını ve filtre noktasını inceleyin. Teşhis sorusu: Filtre, çok sayıda satır okunduktan sonra mı uygulanıyor? Tahmin edilen satır sayısı gerçek sonuca yakın mı? Karar: Büyük tahmin sapması varsa istatistiklerin güncelliğini, veri dağılımını ve koşulun plan tarafından nasıl yorumlandığını kontrol edin.
- JOIN sırasını ve ara sonuç büyüklüğünü kontrol edin. Teşhis sorusu: Birleştirme işlemine gereğinden fazla satır mı taşınıyor? Karar: Önce filtrelenebilecek tabloların geç filtrelenmesi veya yanlış birleştirme koşulu olup olmadığını araştırın. JOIN planını yalnızca son satır sayısına bakarak değil, ara sonuçların büyüklüğüyle değerlendirin.
- SELECT * ve fonksiyonlu koşulları gözden geçirin. Teşhis sorusu: Sorgu gerçekten ihtiyaç duyulmayan sütunları mı getiriyor veya indekslenmiş sütunu bir fonksiyonla mı sarıyor? Karar: Gerekli sütunları açıkça seçin.
WHERE LOWER(email) = ...gibi koşullarda motorun ilgili ifadeyi nasıl planladığını doğrulayın; veri türü üzerindeki örtük dönüşümleri de ayrıca inceleyin. - Tek bir değişiklik yaparak planı yeniden alın. Teşhis sorusu: Plan değişikliği hangi müdahaleden sonra ortaya çıktı? Karar: Aynı anda indeks eklemek, JOIN değiştirmek ve sorguyu yeniden yazmak yerine tek bir değişiklik yapın. Böylece neden-sonuç ilişkisi korunur. Algoritmik düşünme ve kontrollü problem çözme pratiği için algoritma bilgi testi benzer adımlı düşünme alışkanlığını destekleyebilir.
- Doğruluğu ve yan etkileri kontrol edin. Teşhis sorusu: Sorgu hızlandı ama sonuç kümesi, yazma maliyeti veya bakım yükü değişti mi? Karar: Sonuçların aynı olduğunu doğrulamadan optimizasyonu tamamlanmış saymayın. İndeksler okuma maliyetini azaltabilir; ancak ek depolama, yazma işlemlerinde ek iş ve bakım gerektirebilir.
Değişiklik sonrası kontrol
- Sonuçlar önceki sorguyla aynı mı?
- Plan gerçekten değişti mi, yoksa yalnızca süre mi farklılaştı?
- Tahmini ve gerçek satır davranışı birbiriyle tutarlı mı?
- Yazma ve indeks bakım maliyeti kabul edilebilir mi?
İndeks Eklemek Her Yavaş Sorguyu Çözer mi?
Hayır. İndeks, teşhis sonucunda değerlendirilen araçlardan yalnızca biridir. Asıl hedef, sorgunun gereksiz veri okumasını azaltmak ve veritabanının uygun işlem planını seçmesine yardımcı olmaktır. Sorgu zaten tablonun büyük bölümünü döndürüyor, pahalı bir sıralama yapıyor veya yanlış bir JOIN üretiyorsa tek başına indeks beklenen sonucu vermeyebilir.
İndeks eklediğiniz hâlde plan değişmiyorsa şu noktaları sırayla kontrol edin:
- Filtre koşulu indeksin sütun sırası ve veri türleriyle uyumlu mu?
- Sorgu, indeks kullanılsa bile çok fazla satır mı döndürüyor?
- Sütun üzerinde fonksiyon veya örtük veri türü dönüşümü var mı?
- JOIN koşullarında gerekli erişim yolu eksik mi?
- Planlayıcının kullandığı istatistikler güncel mi?
- Gerçek darboğaz bu sorgu mu, yoksa ağ, kilitlenme, uygulama kodu veya sonuç aktarımı mı?
Bu soruların yanıtı motorlara ve veri dağılımına göre değişebilir. Bu nedenle plan seçimi, istatistik güncelleme ve örtük dönüşüm davranışı için kullandığınız veritabanı motorunun resmi belgelerini esas alın. Her değişiklikten sonra aynı sorguyu aynı koşullarda yeniden inceleyin; yalnızca plan görünümüne değil, sorgu sonucunun doğruluğuna da bakın.
Sık Sorulan Sorular
EXPLAIN ile EXPLAIN ANALYZE arasındaki temel fark nedir?
EXPLAIN, veritabanının sorgu için oluşturduğu planı ve tahmini maliyetleri gösterir. EXPLAIN ANALYZE ise sorguyu çalıştırarak gerçekleşen süre ve satır davranışını da sunar. Böylece tahminlerin gerçek çalışmaya ne kadar yaklaştığı incelenebilir.
Tam tablo taraması her zaman kötü bir durum mudur?
Hayır. Tablo küçükse veya sorgu satırların büyük bölümünü döndürecekse tam tarama makul olabilir. Sorun, seçici bir filtre olmasına rağmen büyük miktarda verinin okunması ve sonradan elenmesidir.
Bir sorgu için indeks ekledikten sonra EXPLAIN çıktısı neden değişmeyebilir?
Filtre indeksle uyumlu olmayabilir, sorgu çok fazla satır döndürüyor olabilir, istatistikler güncel olmayabilir veya asıl darboğaz başka bir plan adımında bulunabilir. Fonksiyonlar, örtük dönüşümler ve JOIN koşulları da ayrıca incelenmelidir.
EXPLAIN çıktısında tahmini satır sayısı neden önemlidir?
Tahmini satır sayısı, planlayıcının hangi erişim ve JOIN yöntemini seçeceğini etkiler. Tahmin gerçek sonuçtan ciddi biçimde sapıyorsa seçilen plan, veri üzerindeki gerçek çalışma koşullarına uygun olmayabilir.
SELECT * ve sütun üzerinde fonksiyon kullanımı sorguyu neden yavaşlatabilir?
SELECT * gereksiz sütunların okunmasına ve taşınmasına yol açabilir. Sütunu fonksiyonla sarmak ise uygun indeks koşulunun doğrudan kullanılmasını zorlaştırabilir. Bu davranış motorun planlama kurallarına göre doğrulanmalıdır.
EXPLAIN çıktısını satır satır okumaya dayalı bu sistematik yaklaşım, farklı ilişkisel veritabanı ortamlarına uyarlanabilir; önemli olan tek bir reçeteye değil, ölçülebilir plan ve sonuç karşılaştırmasına göre ilerlemektir.