1. Pengertian SQL Tuning
Menurut Immanuel Chan (2008, p11-1), SQL Tuning adalah sebuah proses optimasi dengan cara mengubah perintah-perintah SQL serta menentukan teknik indexing agar SQL tersebut bekerja secara optimal.
2. Langkah-langkah SQL Tuning
Langkah pertama yang harus dilakukan untuk melakukan SQL Tuning adalah melakukan identifikasi terhadap High-Load SQL Statements. High-Load SQL Statements adalah query yang membebani server sehingga menyebabkan kinerja sebuah basis data menjadi lambat dan menghabiskan penggunaan sumber daya yang besar dari sistem. Sekalipun optimasi telah dilakukan pada basis data, namun penggunaan SQL yang tidak optimal akan menyebabkan performa basis data menurun. Melakukan identifikasi query ini merupakan aktivitas yang penting dari sebuah proses SQL Tuning, yang telah diotomatisasi dengan fitur ADDM (Automatic Database Diagnostic Monitor) pada Enterprise Manager Oracle 10g.
Melakukan identifikasi High-Load SQL Statements merupakan sebuah aktivitas yang penting dari sebuah proses SQL tuning. Oracle 10 g telah melakukan otomatisasi hal ini dengan fitur ADDM (Automatic Database Diagnostic Monitor) atau dengan menggunakan Entreprise Manager untuk mencari High-Load SQL Statements tersebut. Ada 2 cara untuk melakukan identifikasi High-Load SQL Statements r, yaitu dengan menggunakan ADDM dan Top SQL.
a. Identifikasi High-Load SQL Statements dengan menggunakan ADDM
Secara default, ADDM berjalan secara otomatis setiap jam dan melakukan analisa data yang dikumpulkan dari AWR (Automatic Workload Repository) untuk mengidentifikasi masalah pada kinerja basis data melalui snapshot. Dalam hal ini mencakup High-Load SQL Statements. Ketika terdapat masalah pada kinerja basis data, ADDM akan menampilkan permasalahan tersebut pada halaman ADDM dan memberikan rekomendasi untuk setiap masalah yang ditemukan. Sebagai contoh, ketika sebuah High- Load SQL Statements ditemukan, ADDM akan memberikan rekomendasi untuk menggunakan SQL Tuning Advisor untuk perintah SQL tersebut.
b. Identifikasi High-Load SQL Statements dengan menggunakan Top SQL
Selain menggunakan ADDM. Oracle juga menyediakan sebuah fitur untuk melihat High-Load SQL Statements. Fitur yang disediakan oleh Oracle ini adalah sebuah halaman Top Activity yang terdapat pada Entreprise Manager
Pada halaman ini kita dapat melihat High-Load SQL Statements, ditunjukkan pada gambar 2.21 berikut:

Gambar 2.21 Halaman Top Activity pada Enterprise Manager
Pada Enterprise Manager, klik Top Activity yang terdapat di tab Performance. Halaman Top Activity menunjukkan aktivitas yang berjalan pada basis data selama periode 1 jam. Pada bagian Top Activity, akan tampil chart yang menggambarkan kinerja basis data yang diukur dari average active sessions. Chart ini menunjukkan rata-rata sesi yang aktif dengan penggolongan kategori dari aktivitas yang dilakukan oleh setiap sesi tersebut dengan keterangan indikator warna dari aktivitas yang terdapat pada sisi kanan chart tersebut. Pada sisi bawah chart terdapat bagian tabel top SQL yang berisi daftar query yang membebani server dari seluruh kategori. Untuk melihat detail dari query tersebut, klik pada kolom SQL ID di tabel top SQL, akan muncul teks query detail masing-masing top SQL. Untuk melihat perintah SQL pada kategori tertentu, klik tombol kategori yang diinginkan, kemudian akan tampil chart dari Active Sessions yang menunjukkan aktivitas dan top SQL akan diperbarui sesuai dengan waktu refresh yang dipilih oleh pengguna.
3. Restukturisasi Perintah-Perintah SQL
Menurut Immanuel Chan (2008, p11-7 s.d 11-17), berikut ini adalah beberapa teknik untuk mengoptimalkan query:
Gunakan Equijoin
Sedapat mungkin gunakanlah equijoin, karena perintah equijoin pada kolom yang belum ditransformasikan akan meningkatkan performa basis data dan mempermudah proses tuning.
Gunakan kolom-kolom yang belum ditransformasikan di dalam klausa WHERE
Selalu usahakan untuk menggunakan kolom yang belum ditransformasikan (tidak diberi fungsi seperti substr, to_char, to_number, dsb) pada klausa WHERE.
Contoh where clause dengan kolom yang belum ditransformasikan:
WHERE a.order_no = b.order_no
dibandingkan dengan ini.
Contoh where clause dengan kolom yang ditransformasikan:
WHERE TO_NUMBER
(SUBSTR(a.order_no,INSTR (b.order_no, '.')-1))
=(SUBSTR (a.order_no,INSTR (b.order_no, '.')-1))
Adanya penggunaan fungsi SQL dalam klausa WHERE dapat membuat komputer menggunakan sumber daya lebih banyak untuk mengolah fungsi tersebut sehingga menyebabkan performa yang menurun karena selain butuh proses untuk menjalankan fungsi tersebut, indeks yang terdapat kolom tersebut tidak akan digunakan oleh optimizer. Jika ingin tetap menggunakan fungsi pada kolom dalam klausa WHERE dan indeks tetap digunakan maka gunakan indeks function-based agar optimizer tetap menggunakan indeks dalam proses eksekusi query tersebut.
Berhati-hatilah dengan tipe data baik secara eksplisit maupun implisit
Oracle secara implisit memerlukan proses lebih apabila terdapat jika terdapat sebuah kondisi dimana terdapat perbandingan dari tipe data yang berbeda, dimana Oracle akan langsung mengkonversi tipe data tersebut menggunakan fungsi konversi.
Contoh klausa dimana terdapat implicit conversion
AND charcol = numexpr
Sekilas gambar 2.24 merupakan sintaks yang benar karena gambar 2.24 menggunakan kolom yang tidak diberi fungsi namun charcol mempunyai tipe data varchar dan numexpr mempunyai tipe data numeric. Dalam hal ini, Oracle secara implisit akan mengubah query gambar 2.24 menjadi seperti query gambar 2.25:
Implisit conversion yang dilakukan oleh Oracle
AND TO_NUMBER (charcol) = numexpr
Hal ini tentu saja dapat membuat indeks tidak digunakan oleh optimizer dan membutuhkan proses lebih untuk menjalankan fungsi konversi tersebut.
Jangan membuat SQL layaknya bahasa prosedural
SQL bukanlah bahasa prosedural, jika sebuah SQL dibuat untuk berbagai tugas maka hasilnya akan kurang optimal untuk tugas tertentu. Oleh karena itu, lebih baik gunakanlah banyak perintah untuk setiap fungsi dibandingkan dengan sebuah perintah untuk banyak fungsi. Untuk query yang cukup kompleks, dapat menggunakan perintah yang kompleks menjadi lebih sederhana, seperti pada contoh query gambar 2.26:
Query yang kompleks dan menyebabkan indeks tidak terbaca
SELECT info FROM tabels
WHERE ... AND somecolumn BETWEEN
DECODE (:loval, 'ALL', somecolumn, :loval)
AND DECODE (:hival, 'ALL', somecolumn, :hival);
Indeks pada kolom somecolumn tidak akan digunakan oleh Optimizer pada query gambar 2.26 karena ekspresi tersebut menggunakan kolom yang sama di kedua sisi BETWEEN. Jika ingin indeks dapat digunakan oleh Optimizer maka query tersebut dapat diganti dengan menggunakan
UNION ALL agar indeks dapat digunakan yaitu dengan query seperti pada gambar 2.27:
Query yang dioptimasi dengan menggunakan union all agar indeks dapat digunakan oleh optimizer
SELECT /* change this half of UNION ALL if other half changes */ info FROM tabels
WHERE...AND somecolumn BETWEEN :loval AND :hival
AND (:hival != 'ALL' AND :loval != 'ALL')
UNION ALL SELECT /* Change this half of UNION ALL if other half changes. */ info
FROM tabels
WHERE...AND (:hival = 'ALL' OR :loval = 'ALL');
Penggunaan EXISTS dibandingkan IN untuk subquery
Gunakan IN jika selective-predicate berada di dalam subquery dan gunakanlah EXISTS jika selective-predicate berada di dalam parent karena masing-masing penggunaan IN maupun EXISTS mempunyai keuntungannya masing-masing.
Berikut ini contoh yang mendemonstrasikan keuntungan dari IN dan EXISTS. Kedua contoh ini menggunakan skema yang sama dengan karakteristik seperti berikut:
- Terdapat indeks yang unik di employees.employee_id
- Terdapat indeks di field orders.customer_id.
- Terdapat indeks di field employees.department_id.
- Tabel employee mempunyai 27000 baris
- Tabel order mempunyai 10000 baris
- Skema HR dan OE, keduanya dianalisa dengan COMPUTE
Contoh 1: penggunaan IN -- selective predicate berada di dalam subquery.
Query ini bertujuan untuk mencari semua pekerja yang melayani pesanan pada id pelanggan 144.
Gambar 2.28 menunjukan SQL untuk mencari hal tersebut jika menggunakan perintah EXISTS.
Contoh SQL dengan pengunaan perintah EXISTS
SELECT e.employee_id,e.first_name,e.last_name,e.salary
FROM employees e
WHERE EXISTS(SELECT 1 FROM orders o /* Note 1 */
WHERE e.employee_id = o.sales_rep_id /* Note 2 */
AND o.customer_id = 144); /* Note 3 */
*) Keterangan:
- Penggunaan EXISTS
- Penggunaan EXISTS merupakan correlated-subquery
- Baris ini menunjukkan bahwa di dalam correlated-subquery ini terdapat sebuah selective-query
Tabel 2.1 Execution plan dengan penggunaan EXISTS
| ID | OPERATION | OPTIONS | OBJECT_NAME | OPT | COST |
|----|------------------|----------|-----------------|-----|------|
| 0 | SELECT STATEMENT | | | CHO | |
| 1 | FILTER | | | | |
| 2 | TABEL ACCESS | FULL | EMPLOYEES | ANA | 155 |
| 3 | TABEL ACCESS | BY INDEX | ROWID ORDERS | ANA | 3 |
| 4 | INDEX | SCAN | ORD_CUSTOMER_IX | ANA | 1 |
Tabel 2.1 menunjukkan proses eksekusi (dari V$SQL_PLAN) untuk perintah pada gambar 2.28. Proses eksekusi yang ditunjukkan pada table 2.1 memerlukan full-tabel scan dari tabel employees yang mana menghasilkan banyak row dan kemudian setiap row tersebut difiltrasi dengan tabel order dengan menggunakan indeks.
Gambar 2.29 menunjukkan contoh perintah SQL dengan menggunakan IN:
SQL dengan penggunaan perintah IN
SELECT e.employee_id,e.first_name,e.last_name,e.salary
FROM employees e WHERE e.employee_id
IN (SELECT o.sales_rep_id /* Note 1 */
FROM orders o
WHERE o.customer_id = 144); /* Note 3 */
*) Keterangan:
- Baris inimenunjukkan bahwa correlated-subquery yang mengandung seleksi yang tinggi dengan ditandai dengan sintaks customer_id = number
- Baris ini menunjukkan bahwa digunakan IN. Subquery ini tidak lagi berkorelasi karena IN ini mengganti join di subquery.
Tabel 2.2 Execution plan dengan penggunaan perintah IN
| ID | OPERATION | OPTIONS | OBJECT_NAME | OPT | COST |
|----|------------------|-------------|------------------|-----|------|
| 0 | SELECT STATEMENT | | | CHO | |
| 1 | NESTED_LOOPS | | | | 5 |
| 2 | VIEW | | | | 3 |
| 3 | SORT | UNIQUE | | | 3 |
| 4 | TABEL ACCESS | FULL | ORDERS | ANA | 1 |
| 5 | TABEL ACCESS | BY INDEX | ROWID EMPLOYEES | ANA | 1 |
| 6 | INDEX | UNIQUE SCAN | EMP_EMP_ID_PK | ANA | |
Tabel 2.2 menunjukkan execution plan (dari V$SQL_PLAN) untuk perintah pada gambar 2.29. Optimizer menulis kembali subquery pada gambar 2.29 menjadi sebuah view yang kemudian di-JOIN melalui indeks di tabel employees. Hasil ini menunjukkan bahwa penggunaan IN lebih cepat karena subquery-nya mengandung selective predicate sehingga hanya mengeluarkan beberapa employee_id dan beberapa employee_id tersebut digunakan untuk mengakses employee tabel melalui unique-index.
Contoh 2: menggunakan EXISTS--selective predicate berada pada parent query
Penggunaan EXISTS juga dapat menghasilkan query yang optimal. Contohnya jika terdapat sebuah query yang bertujuan untuk menampilkan semua karyawan yang mempunyai ID yang sama dengan ID perwakilan sales tertentu yang bekerja di departemen 80 dan pernah melayani pesanan pelanggan.
Gambar 2.30 menunjukkan query dimana pengunaan IN tidaklah optimal:
Query dengan penggunaan IN
SELECT e.employee_id, e.first_name, e.last_name, e.department_id, e.salary
FROM employees e
WHERE e.department_id = 80 /*Note 5
AND e.job_id = 'SA_REP' /*Note 6
AND e.employee_id IN
(SELECT o.sales_rep_id FROM orders o); /*Note 4
*) Keterangan:
- Penggunaan IN menunjukkan bahwa subquery tidak lagi berkorelasi karena penggunaan IN menggantikan join.
- Menunjukkan selective-query.
Tabel 2.3 Execution plan dari pengunaan IN
| ID | OPERATION | OPTIONS | OBJECT_NAME | OPT | COST |
|----|------------------|---------------|---------------|-----|------|
| 0 | SELECT STATEMENT | | | CHO | |
| 1 | NESTED LOOPS | | | | 125 |
| 2 | VIEW | | | | 116 |
| 3 | SORT | UNIQUE | | | 116 |
| 4 | TABEL ACCESS | FULL | ORDERS | ANA | 40 |
| 5 | TABEL ACCESS | BY INDEXROWID | EMPLOYEES | ANA | 1 |
| 6 | INDEX | UNIQUE SCAN | EMP_EMP_ID_PK | ANA | |
Tabel 2.3 menunjukkan execution plan (dari V$SQL_PLAN) untuk perintah pada gambar 2.30. Proses ini akan membuat optimizer membuat sebuah view yang berisi banyak employee_id karena tidak adanya selective-predicate dan kemudian akan dibandingkan dengan tabel employees melalui indeks yang unik.
Gambar 2.31 menunjukan contoh query yang menggunakan EXISTS:
SELECT e.employee_id, e.first_name, e.last_name, e.salary
FROM employees e
WHERE e.department_id = 80 /*Note 5*/ AND e.job_id = 'SA_REP' /*Note 6*/ AND EXISTS
(SELECT 1 /*Note 1*/
FROM orders o
WHERE e.employee_id =o.sales_rep_id); /*Note 2*/
*) Keterangan:
- Baris ini menunjukkan penggunaan EXISTS.
- Baris ini menunjukkan bahwa subquery ini merupakan correlated-subquery.
- Baris ini menunjukkan selective-predicate di dalam query tersebut.
Tabel 2. 4 Execution plan dari pengunaan EXISTS
| ID | OPERATION | OPTIONS | OBJECT_NAME | OPT | COST |
|----|------------------|----------------|-------------------|-----|------|
| 0 | SELECT STATEMENT | | | CHO | |
| 1 | FILTER | | | | |
| 2 | TABEL ACCESS | BY INDEX ROWID | EMPLOYEES | ANA | 98 |
| 3 | AND-EQUAL | | | | |
| 4 | INDEX | RANGE SCAN | EMP_JOB_IX | ANA | |
| 5 | INDEX | RANGE SCAN | EMP_DEPARTMENT_IX | ANA | |
| 6 | INDEX | RANGE SCAN | ORD_SALES_REP_IX | ANA | 8 |
Tabel 2.4 menunjukkan execution-plan (dari V$SQL_PLAN) untuk perintah SQL pada gambar 2.31. Cost penggunaan EXISTS lebih kecil karena 2 buah indeks digunakan untuk mengurutkan parent query sehingga menghasilkan beberapa employee_id kemudian beberapa employee_id tersebut digunakan untuk mengakses tabel orders melalui indeks.
Mengatur cara akses dan JOIN melalui hints
Kita dapat mengatur pilihan langkah JOIN, INDEX yang dipakai dan cara mengakses yang dilakukan oleh optimizer dengan cara menggunakan hints di perintah SQL. Contoh nya adalah hints /*+FULL */ untuk memaksa optimizer menggunakan FULL TABEL SCAN meskipun terdapat indeks seperti pada query gambar 2.32.
Contoh pengunaan HINTS FULL
SELECT /*+ FULL(e) */ e.ename
FROM emp e
WHERE e.job = 'CLERK';
Hati-hati dalam menggunakan perintah JOIN
Dalam query, perintah JOIN dapat menyebabkan efek yang signifikan terhadap performa. Sehingga penggunaan perintah JOIN haruslah sangat diperhatikan karena sebuah penggunaan JOIN yang tidak diperlukan akan menyebabkan performa menurun drastis.
Untuk memenuhi tujuan performa, terdapat 3 aturan penting yaitu:
- Hindari FULL TABEL SCAN jika row bisa didapatkan melalui penggunaan indeks.
- Selalu gunakan indeks yang mengembalikan lebih sedikit baris.
- Sesuaikan urutan JOIN sehingga tabel yang paling jumlah barisnya paling sedikit akan dieksekusi paling awal oleh optimizer.
Gambar 2.33 menunjukkan bagaimana cara untuk mengoptimasi urutan JOIN:
Contoh perintah join yang dapat dikerjakan dengan berbagai kondisi
SELECT info
FROM taba a, tabb b, tabc c
WHERE a.acol BETWEEN 100 AND 200
AND b.bcol BETWEEN 10000 AND 20000
AND c.ccol BETWEEN 10000 AND 20000
AND a.key1 = b.key1
AND a.key2 = c.key2;
Jumlah baris yang akan diperiksa dari tabel a ada 100, sedangkan tabel b dan tabel c mempunyai 10000 baris. Query dengan predikat yang demikian akan menghasilkan 2 hasil yang sangat jauh berbeda, yaitu:
Kondisi pertama:
Jika proses selective-query pertama kali dilakukan pada tabel b join dengan c, akan membutuhkan 10000 proses, sekalipun terdapat indeks. Hasilnya akan join dengan tabel a yang hanya mempunyai 100 baris, dengan ini akan membutuhkan 100 proses.
Kondisi kedua:
Jika tabel a di -- join - kan dengan tabel b terlebih dulu maka jumlah proses yang digunakan adalah 100 proses yang akan berjalan dengan cepat melalui penggunaan indeks. Kemudian 100 baris yang dihasilkan akan join dengan tabel c yang juga akan memerlukan 100 proses dan akan berjalan dengan cepat karena penggunaan indeks.
Berhati hatilah dalam menggunakan view
Dalam menggunakan view pastikan bahwa semua tabel yang digunakan di dalam view tersebut terpakai karena proses JOIN terhadap tabel yang tidak dipakai akan mengurangi performa. Apabila hal tersebut terjadi maka gunakanlah view baru daripada membuat sebuah view yang reusable namun dengan performa yang kurang baik.
Melakukan restrukturisasi indeks.
Perfoma dapat ditingkatkan dengan cara melakukan restrukturisasi indeks yang dapat dilakukan dengan cara-cara sebagai berikut:
- Menghapus nonselective indeks untuk mempercepat proses DML.
- Memberi indeks pada bagian selective predicate pada query.
- Cobalah untuk mengurutkan kolom yang terdapat di concatenated-index.
- Menambahkan kolom ke dalam indeks untuk meningkatkan selectivity.
Mengubah dan menonaktifkan triggers dan constraint
Semakin banyak trigger dan contraint yang digunakan maka performa sistem juga akan menurun sehingga penggunaan keduanya haruslah diperhatikan secara tepats
Melakukan restrukturisasi data
Setelah melakukan restrukturisasi indeks dan perintah SQL, restukturisasi data dapat dilakukan dengan cara berikut:
- Hindari penggunaan GROUP BY di dalam perintah-perintah yang kritikal.
- Cobalah untuk melakukan peninjauan kembali desain basis data yang ada, apakah desain basis data sudah optimal. Jika hasilnya adalah tidak, maka cobalah lakukan beberapa optimasi, misalnya melakukan proses denormalisasi.
- Gunakanlah partisi jika memungkinkan.
Menggabungkan multi-scan dengan perintah CASE
Penggunaan agregasi dengan fungsi set yang bermacam-macam hanya untuk 1 set data sangat sering dijumpai pada query. Pengambilan 10 fungsi set dengan sintaks yang sama namun dengan kondisi yang berbeda (klausa WHERE) akan memerlukan proses 10 kali scan pada 10 query. Hal ini dapat dihilangkan dengan cara memindahkan kondisi WHERE di setiap scan ke dalam sebuah kolom dengan penggunaan perintah CASE untuk melakukan penyaringan data.
Sebagai contoh pada query ini kita akan menghitung jumlah karyawan yang mendapatkan gaji lebih kecil dari 2000, diantara 2000 dan 4000 dan lebih dari 4000 setiap bulannya. Hal ini dapat dilakukan dengan 3 query (3 scan) yang berbeda seperti pada gambar 2.34, 2.35 dan 2.36:
Query untuk mengambil jumlah karyawan yang gajinya lebih kecil dari 2000
SELECT COUNT (*)
FROM employees
WHERE salary < 2000;
Query untuk mengambil jumlah karyawan yang gajinya antara 2000 dan 4000
SELECT COUNT (*)
FROM employees
WHERE salary BETWEEN 2000 AND 4000;
Query untuk mengambil jumlah karyawan yang gajinya lebih besar dari 4000
SELECT COUNT (*) FROM employees WHERE salary>4000;
3 Query tersebut dapat diefisienkan dengan mengubah query tersebut menjadi sebuah single query dimana setiap hasil yang ingin didapatkan ditaruh didalam sebuah kolom dengan menggunakan CASE untuk kondisinya. Gambar 2.37 adalah contoh penggunaan CASE untuk menghilangkan multiple scan tersebut:
Pengunaan CASE untuk menggabungkan MULTISCAN
SELECT COUNT
(CASE WHEN salary < 2000
THEN 1 ELSE null END) count1,
COUNT (CASE WHEN salary BETWEEN 2001 AND 4000
THEN 1 ELSE null END) count2,
COUNT (CASE WHEN salary > 4000
THEN 1 ELSE null END) count3
FROM employees;
Gunakan DML dengan klausa RETURNING
Gunakanlah perintah INSERT, UPDATE, atau DELETE...RETURNING untuk mengambil dan mengubah data dengan sekali panggil. Teknik ini akan meningkatkan perfoma dengan cara mengurangi jumlah pemanggilan ke dalam basis data. Cobalah menggabungkan beberapa perintah menjadi sebuah perintah yang sederhana. Contoh yang paling dasar dalam hal ini adalah perintah DELETE seperti pada gambar 2.38:
Penggunaan sintaks delete yang kurang optimal
BEGIN
FOR pos_rec IN
(SELECT * FROM order_positions
WHERE order_id = :id)
LOOP
DELETE FROM order_positions
WHERE order_id = pos_rec.order_id AND
order_position =pos_rec.order_position;
END LOOP;
DELETE FROM orders WHERE order_id = :id;
END;
Perintah diatas akan melakukan penghapusan sebanyak 2 kali yaitu penghapusan data di dalam tabel order_positions kemudian penghapusan data di dalam tabel order. Hal ini tentu saja menghabiskan sumber daya karena perintah tersebut akan disampaikan ke dalam database sebanyak 2 kali.
Perintah tersebut dapat diganti menjadi sebuah perintah dengan hanya menambahkan 1 buah constraint yaitu constraint cascade dimana hanya sebuah perintah delete saja yang digunakan yang secara otomatis akan mempercepat kerja dari proses delete ini.
4. Penggunaan Bind Variable
Setiap kali sebuah query dikirim ke basis data, teks dari query tersebut akan diperiksa apakah teks dari query tersebut sudah pernah ada di dalam shared pool. Jika tidak ada teks query yang sesuai dengan teks query yang ada di dalam shared pool, maka akan dilakukan hard parse. Sebaliknya, jika teks dari query tersebut sudah ada di dalam shared pool, maka akan dilakukan soft parse. Nilai variabel yang berbeda-beda pada query dapat membuat query tersebut dibaca secara berbeda, sehingga akan dilakukan hard parse. Oleh karena itu, penggunaan bind-variable pada teks query yang sama membuat query dapat digunakan kembali atau dibaca sama dengan query yang pernah dimasukkan sebelumnya. Hanya perubahan nilai dari bind-variable yang berubah-ubah. Tujuan dari penggunaan bind-variable untuk mengisi nilai variabel pada query adalah:
- Terlalu sering memasukkan teks query yang sama (hanya berbeda nilai variabel) hanyalah akan membuang banyak memori.
- Memasukkan teks query yang sama ke dalam shared pool akan membuat query tersebut secara cepat dieksekusi keluar dari shared pool tersebut.
- Melakukan parsing untuk query merupakan proses intensif yang membutuhkan sumber daya yang tidak kecil. Mengurangi jumlah hard-parse akan mengurangi jumlah penggunaan CPU.