Execution Plan: Estimated vs Actual di SQL Server

Foto oleh panumas nikhomkhai via Pexels

Eksekusi Query Lambat? Pahami Beda Execution Plan Estimated vs Actual di SQL Server

Anda pernah mengalami situasi di mana query SQL terasa lambat luar biasa, padahal saat Anda melihat Execution Plan yang muncul di SQL Server Management Studio (SSMS), semuanya tampak baik-baik saja? Operator yang digunakan optimal, biaya (cost) terlihat rendah, dan rasanya tidak ada yang salah. Namun, kenyataannya di lapangan, pengguna mengeluh karena harus menunggu lama.

Situasi ini seringkali menjadi indikasi bahwa ada kesenjangan antara Estimated Execution Plan yang Anda lihat dan Actual Execution Plan yang sesungguhnya dieksekusi oleh SQL Server. Memahami perbedaan fundamental di antara keduanya adalah kunci untuk diagnosis performa query yang akurat dan efektif.

Mengingat Kembali: Peran Penting Execution Plan

Sebelum kita menyelami perbedaannya, mari kita ingat kembali bahwa Execution Plan adalah semacam “cetak biru” atau resep yang dibuat oleh SQL Server Query Optimizer untuk menjalankan sebuah query. Plan ini menunjukkan langkah-langkah yang akan diambil, operator yang digunakan (seperti Index Seek, Table Scan, Join), urutan operasi, dan perkiraan biaya yang terkait. Di artikel sebelumnya, kita sudah membahas dasar-dasar membaca Execution Plan.

Estimated Execution Plan: Prediksi Sebelum Pertandingan Dimulai

Estimated Execution Plan adalah rencana yang dibuat oleh SQL Server Query Optimizer sebelum query benar-benar dieksekusi. Ini adalah prediksi terbaik yang bisa dibuat oleh SQL Server mengenai bagaimana cara paling efisien untuk menjalankan query tersebut.

Bagaimana Estimated Plan Dibuat?

  • Statistik Database: Optimizer sangat bergantung pada statistik yang dikumpulkan dari indeks dan kolom tabel. Statistik ini memberikan informasi tentang distribusi data, jumlah baris unik, dan kepadatan data.
  • Konfigurasi Server/Database: Pengaturan seperti compatibility level database, cost threshold for parallelism, dan lainnya juga memengaruhi keputusan optimizer.
  • Parameter Query: Jika query menggunakan parameter, optimizer akan mencoba menebak nilai parameter atau menggunakan rata-rata distribusi data.

Anda bisa mendapatkan Estimated Execution Plan di SSMS dengan menyorot query dan menekan kombinasi tombol Ctrl + L atau memilih ikon “Display Estimated Execution Plan” di toolbar.

Ikon 'Display Estimated Execution Plan' di SQL Server Management Studio (SSMS).

![Display Estimated Execution Plan Icon](https://docs.microsoft.com/en-us/sql/relational-databases/performance/media/display-estimated-execution-plan-toolbar-icon.png?view=sql-server-ver16)

Kapan Estimated Plan Berguna?

  • Analisis Awal: Untuk mendapatkan gambaran cepat tentang potensi masalah tanpa perlu menjalankan query (yang mungkin berat) di lingkungan produksi.
  • Perbandingan Alternatif: Saat mencoba beberapa variasi query, Anda bisa melihat estimasi biayanya untuk memilih yang paling menjanjikan.
  • Lingkungan Pengembangan: Di mana data mungkin belum banyak atau representatif, estimated plan bisa memberikan panduan awal.

Actual Execution Plan: Realita Setelah Pertandingan Selesai

Berbeda dengan estimated plan, Actual Execution Plan adalah rencana yang *benar-benar dieksekusi* oleh SQL Server setelah query selesai dijalankan. Plan ini tidak hanya menampilkan langkah-langkah yang diambil, tetapi juga metrik runtime yang sesungguhnya, seperti jumlah baris aktual yang diproses, waktu eksekusi, penggunaan memori, dan berapa kali sebuah operator dieksekusi.

Bagaimana Actual Plan Dibuat?

Actual Plan dihasilkan setelah optimizer benar-benar menjalankan query. Ini berarti semua variabel dan kondisi runtime sudah diketahui dan tercatat. Plan ini mencerminkan apa yang *benar-benar terjadi* selama eksekusi.

Untuk mendapatkan Actual Execution Plan, Anda harus mengaktifkan opsi “Include Actual Execution Plan” (dengan menekan Ctrl + M atau ikon di toolbar) sebelum mengeksekusi query. Setelah query selesai, tab Execution Plan akan muncul dengan data aktual.

Ikon 'Include Actual Execution Plan' di SQL Server Management Studio (SSMS).

![Include Actual Execution Plan Icon](https://docs.microsoft.com/en-us/sql/relational-databases/performance/media/include-actual-execution-plan-toolbar-icon.png?view=sql-server-ver16)

Kapan Actual Plan Penting?

  • Diagnosis Akurat: Untuk menemukan akar masalah performa yang sebenarnya di lingkungan apapun, terutama produksi.
  • Validasi Optimasi: Setelah melakukan perubahan pada query atau indeks, actual plan akan menunjukkan apakah optimasi Anda benar-benar efektif.
  • Mendeteksi Anomali: Ketika ada perbedaan signifikan antara estimasi dan kenyataan.

Kesenjangan Prediksi: Mengapa Estimated dan Actual Bisa Berbeda Jauh?

Perbedaan yang mencolok antara Estimated dan Actual Execution Plan adalah sinyal kuat adanya masalah. Kesenjangan ini paling sering terlihat pada metrik seperti Estimated Number of Rows dibandingkan Actual Number of Rows pada setiap operator. Jika perbedaan ini besar, biasanya diikuti oleh perbedaan signifikan dalam biaya CPU dan I/O aktual.

Beberapa penyebab umum kesenjangan ini:

1. Statistik Kedaluwarsa atau Tidak Akurat

Ini adalah penyebab paling sering. SQL Server bergantung pada statistik untuk memperkirakan jumlah baris yang akan dikembalikan oleh sebuah operasi. Jika statistik kedaluwarsa atau tidak mencerminkan distribusi data yang sebenarnya, optimizer akan membuat perkiraan yang salah. Akibatnya, ia bisa memilih plan yang suboptimal, misalnya melakukan Table Scan ketika seharusnya bisa menggunakan Index Seek (sebuah topik yang akan kita bahas lebih lanjut di artikel berikutnya).

Misalnya, jika ada kolom Status di tabel dengan nilai 'Active' dan 'Inactive', dan statistik lama menunjukkan distribusi 50-50, padahal sekarang 99% data adalah 'Active', query untuk 'Active' akan memproses jauh lebih banyak baris dari yang diestimasi.

2. Parameter Sniffing

Seperti yang sudah dibahas pada artikel tentang Parameter Sniffing (artikel 34), masalah ini terjadi ketika Query Optimizer mengkompilasi plan pertama kali berdasarkan nilai parameter yang spesifik. Jika nilai parameter berikutnya memiliki distribusi data yang sangat berbeda, plan yang sama mungkin menjadi sangat tidak efisien.

3. Kompleksitas Query dan Fungsi Skalar

Penggunaan fungsi skalar (UDF), ekspresi kompleks, atau konversi tipe data implisit dapat menyulitkan Query Optimizer untuk membuat estimasi yang akurat, bahkan dengan statistik terbaru sekalipun.

4. Perubahan Data yang Drastis

Jika volume atau distribusi data dalam tabel berubah secara drastis dalam waktu singkat (misalnya, setelah operasi import data besar), statistik mungkin belum diperbarui untuk mencerminkan perubahan tersebut, menyebabkan estimasi yang salah.

Studi Kasus: Menemukan Kesenjangan dengan Data Dummy

Mari kita simulasikan skenario di mana statistik kedaluwarsa menyebabkan perbedaan signifikan.

Persiapan Database dan Data

Kita akan membuat sebuah tabel ProdukLog yang mencatat aktivitas produk, dengan kolom Status yang memiliki distribusi data tidak merata dan statistik yang akan kita buat kedaluwarsa.

Membuat tabel ProdukLog dan mengisi dengan data awal.

IF OBJECT_ID('ProdukLog') IS NOT NULL DROP TABLE ProdukLog; CREATE TABLE ProdukLog ( LogID INT IDENTITY(1,1) PRIMARY KEY, ProdukName VARCHAR(100), Status VARCHAR(20), LogDate DATETIME DEFAULT GETDATE() ); -- Memasukkan 1000 baris data INSERT INTO ProdukLog (ProdukName, Status) SELECT 'Produk ' + CAST(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS VARCHAR(10)), CASE WHEN (ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) % 10 = 0 THEN 'Pending' ELSE 'Completed' END FROM sys.all_columns AS a, sys.all_columns AS b WHERE a.object_id < 10 AND b.object_id < 10; -- Membuat indeks pada kolom Status untuk skenario ini CREATE NONCLUSTERED INDEX IX_ProdukLog_Status ON ProdukLog(Status);

Melihat Estimated Plan untuk Query Produk 'Pending'

Sekarang, mari kita lihat estimated plan untuk mencari produk dengan status 'Pending'. Pastikan Anda mengaktifkan “Display Estimated Execution Plan” (Ctrl+L) dan jalankan query berikut:

Contoh query untuk mendapatkan Estimated Execution Plan.

SELECT * FROM ProdukLog WHERE Status = 'Pending';

Perhatikan pada operator seperti Clustered Index Scan, berapa Estimated Number of Rows yang ditampilkan. Anda mungkin melihat angka yang relatif tinggi, tergantung pada bagaimana SQL Server mengestimasi dari statistik yang baru dibuat.

Memperbarui Statistik dan Melihat Actual Plan

Sekarang, kita akan sengaja membuat statistik “kedaluwarsa” dengan mengupdate sebagian besar data, lalu melihat actual plan. Pertama, jalankan update ini:

Memperbarui data untuk menciptakan distribusi yang tidak merata (data skew) dan membuat statistik kedaluwarsa.

UPDATE ProdukLog SET Status = 'Completed' WHERE LogID % 100 <> 0; -- Perbarui sebagian kecil data menjadi 'Pending' untuk memastikan ada hasil UPDATE ProdukLog SET Status = 'Pending' WHERE LogID % 1000 = 0;

Setelah update, sebagian besar data kita sekarang berstatus 'Completed'. Namun, statistik untuk kolom Status masih mencerminkan distribusi lama. Sekarang, pastikan Anda mengaktifkan “Include Actual Execution Plan” (Ctrl+M) dan jalankan lagi query yang sama:

Contoh query untuk mendapatkan Actual Execution Plan setelah data diubah.

SELECT * FROM ProdukLog WHERE Status = 'Pending';

Bandingkan Execution Plan yang Anda dapatkan dari dua langkah di atas. Anda akan melihat perbedaan signifikan pada properti operator:

  • Estimated Number of Rows (dari Estimated Plan) vs Actual Number of Rows (dari Actual Plan).
  • Estimated I/O Cost vs Actual I/O Cost.
  • Estimated CPU Cost vs Actual CPU Cost.

Untuk query status 'Pending' setelah data diubah, Anda akan melihat bahwa Estimated Number of Rows mungkin masih memprediksi jumlah baris yang lebih banyak (berdasarkan statistik lama), padahal Actual Number of Rows untuk status 'Pending' akan sangat kecil (karena sebagian besar sudah 'Completed'). SQL Server tetap mengambil plan berdasarkan estimasi salah ini, yang berpotensi kurang efisien.

Mengatasi Kesenjangan: Update Statistik

Untuk memperbaiki kesenjangan ini, kita perlu memperbarui statistik agar Query Optimizer memiliki informasi yang paling akurat tentang distribusi data.

Memperbarui statistik secara manual untuk kolom Status.

UPDATE STATISTICS ProdukLog (IX_ProdukLog_Status);

Sekarang, ulangi langkah untuk mendapatkan Actual Execution Plan (Ctrl+M dan jalankan query SELECT * FROM ProdukLog WHERE Status = 'Pending';). Anda akan melihat bahwa Estimated Number of Rows pada operator di Actual Plan kini jauh lebih mendekati Actual Number of Rows. Ini menunjukkan bahwa Query Optimizer memiliki informasi yang lebih baik dan kemungkinan besar akan memilih plan yang lebih efisien jika ada opsi lain (misalnya, jika ada indeks pada kolom Status).

Menganalisis Perbedaan dan Mengambil Tindakan

Ketika Anda menemukan perbedaan besar antara estimated dan actual plan, fokuslah pada area berikut:

  1. Actual vs Estimated Rows: Ini adalah indikator paling jelas. Jika Actual Number of Rows jauh lebih tinggi atau lebih rendah dari Estimated Number of Rows pada suatu operator, itu berarti estimasi kardinalitas optimizer melenceng. Ini seringkali terjadi di operator seperti Index Scan, Table Scan, atau saat melakukan JOIN.

  2. Actual vs Estimated Costs: Perhatikan biaya I/O dan CPU. Jika biaya aktual jauh lebih tinggi dari estimasi, ini mengkonfirmasi bahwa plan yang dipilih tidak efisien.

  3. Warnings di Actual Plan: Actual Execution Plan seringkali menampilkan peringatan (misalnya, “Missing Index Recommendation” atau “Implicit Conversion”). Ini adalah petunjuk berharga tentang area yang perlu dioptimasi. Meskipun Missing Index Recommendation bisa dilihat di Estimated Plan juga, Actual Plan akan menunjukkan jika plan itu sendiri terpaksa melakukan pekerjaan ekstra karena kurangnya indeks yang optimal.

  4. Operator yang Berubah: Terkadang, optimizer bisa saja memilih operator yang sama sekali berbeda dari estimasi karena kondisi runtime yang tak terduga. Ini lebih jarang terjadi, tetapi patut diperhatikan.

Tindakan yang bisa Anda lakukan:

  • Update Statistik: Jalankan UPDATE STATISTICS secara manual atau pastikan pekerjaan pemeliharaan database Anda mengelola statistik secara berkala.
  • Evaluasi Ulang Query: Apakah ada cara untuk menyederhanakan predikat WHERE? Hindari penggunaan fungsi skalar pada kolom di klausa WHERE jika memungkinkan (untuk SARGability, topik yang juga akan kita bahas).
  • Pertimbangkan Indeks Baru: Jika ada rekomendasi missing index dan Anda melihat operator seperti Table Scan atau Clustered Index Scan yang memproses banyak baris, mungkin sudah saatnya menambahkan indeks baru atau memodifikasi yang sudah ada.
  • Optimasi Parameter: Jika masalahnya adalah Parameter Sniffing, pertimbangkan teknik seperti OPTION (RECOMPILE), WITH RECOMPILE pada Stored Procedure, atau menggunakan OPTIMIZE FOR UNKNOWN/hint lainnya.

Kapan Menggunakan Estimated, Kapan Actual? (Trade-off)

Keduanya memiliki perannya masing-masing:

  • Estimated Execution Plan: Ideal untuk analisis awal yang cepat, terutama di lingkungan pengembangan atau saat Anda hanya ingin melihat potensi plan tanpa benar-benar menjalankan query yang mungkin berat. Ini adalah “simulasi” dari Query Optimizer. Kelemahannya: bisa melenceng jauh dari kenyataan.
  • Actual Execution Plan: Sangat penting untuk diagnosis masalah performa yang sesungguhnya. Memberikan data runtime yang akurat. Ini adalah “hasil pertandingan” sesungguhnya. Kelemahannya: membutuhkan eksekusi query, yang mungkin memakan waktu dan sumber daya di lingkungan produksi.

Sebagai developer yang berupaya mengoptimasi query, Anda perlu menggunakan keduanya. Gunakan estimated plan untuk inspeksi awal, lalu *selalu* validasi dengan actual plan saat melakukan optimasi serius atau mendiagnosa masalah performa di lingkungan yang mendekati produksi.

Kesalahan Umum Developer

  • Hanya Melihat Estimated Plan: Mengasumsikan bahwa jika estimated plan terlihat baik, maka query akan berkinerja baik di semua kondisi. Ini adalah jebakan terbesar.
  • Mengabaikan Statistik: Tidak memahami pentingnya statistik yang akurat untuk performa query.
  • Tidak Memeriksa Detail: Hanya melihat operator tingkat tinggi dan mengabaikan properti detail dari setiap operator di actual plan (seperti jumlah baris aktual, biaya memori, dll).
  • Mencoba Mengoptimasi Berdasarkan Feeling: Tanpa data konkret dari actual plan, optimasi yang dilakukan seringkali tidak efektif atau bahkan memperburuk keadaan.

Ringkasan & Langkah Selanjutnya

Memahami dan membandingkan Estimated vs Actual Execution Plan adalah keterampilan krusial bagi setiap developer dan DBA yang berhadapan dengan performa SQL Server.

  • Estimated Plan adalah prediksi awal, Actual Plan adalah kenyataan setelah eksekusi.
  • Perbedaan signifikan pada Estimated vs Actual Rows adalah indikator utama masalah.
  • Penyebab utama adalah statistik kedaluwarsa/tidak akurat, parameter sniffing, atau query kompleks.
  • Selalu gunakan Actual Plan untuk diagnosis performa yang akurat.
  • Tindakan perbaikan meliputi update statistik, evaluasi ulang query, dan penambahan/modifikasi indeks.

Dengan mempraktikkan analisis ini, Anda akan selangkah lebih maju dalam mengidentifikasi mengapa query Anda berjalan lambat dan bagaimana cara memperbaikinya. Di artikel berikutnya, kita akan menyelami lebih jauh perbedaan antara Index Seek vs Index Scan, dua operator fundamental yang seringkali menjadi fokus optimasi saat membaca execution plan.

Seri Belajar SQL Server:

← Sebelumnya: Best Practice Keamanan SQL Server

→ Selanjutnya: Index Seek vs Index Scan di SQL Server