Optimasi Left Join Dengan Subquery di MySQL

Left Join adalah salah satu dari beberapa tipe join yang terdapat di SQL untuk mengkombinasikan lebih dari satu tabel. Mengkombinasikan lebih dari satu tabel akan mempengaruhi kecepatan suatu query dalam berinteraksi dengan database. Hal ini akan mengakibatkan aplikasi lebih lambat menampilkan informasi. Pada tulisan kali ini saya akan mengambil contoh penggunaan Left Join dengan 2 tabel, yaitu tabel berita dan tabel komentar dengan key berita_id.

Tabel berita memiliki attribut berita_id, tanggal, judul dan berita. Tabel komentar memiliki attribut komentar_id, pengirim, email, komentar dan berita_id. Kedua tabel ini hanya merupakan sampel yang kondisinya memenuhi syarat untuk menggunakan LEFT JOIN. Kalaupun ada kesamaan tokoh, karakter dan lain sebagainya bukanlah disengaja (koq kayak filem ya? hihihihi)

Untuk menampilkan informasi dari berita dengan jumlah komentar pada setiap berita, dapat menggunakan query berikut :

SELECT A.berita_id, A.judul, A.berita, COALESCE(COUNT(B.komentar_id), 0)
AS total_komentar FROM berita A LEFT JOIN komentar B
USING(berita_id) GROUP BY A.berita_id ORDER BY berita_id DESC

Kenapa query di atas bisa menjadi lambat dengan data dalam jumlah besar?

Karena query tersebut menghitung jumlah key pada tabel sebelah kanan (komentar) sebanyak key pada tabel sebelah kiri (berita). Maka jika tabel berita berisi 4000 data dan tabel komentar berisi 8000 data, maka query diatas akan melakukan pengecekan jumlah komentar sebanyak 4000 kali terhadap 8000 data komentar.

Bagaimana cara mengoptimasinya?

Query diatas dapat dioptimasi dengan membuat tabel di sebelah kanan (komentar) jumlah datanya lebih kecil atau sama dengan jumlah data pada tabel sebelah kiri (berita), dan tidak menghitung key pada tabel sebelah kanan sebanyak jumlah key pada tabel sebelah kiri (berita). Untuk melakukan hal ini bisa dengan menggunakan subquery.

SELECT A.berita_id, A.judul, A.berita, COALESCE(B.total_komentar, 0)
AS total_komentar FROM berita A LEFT JOIN
(SELECT berita_id, COUNT(komentar_id) AS total_komentar
FROM komentar GROUP BY berita_id) B
USING(berita_id) GROUP BY A.berita_id ORDER BY berita_id DESC

Dari query diatas, dapat dilihat tabel sebelah kanan (komentar) berisi subquery yang menghasilkan attribut berita_id dan total_komentar dengan jumlah data yang lebih kecil atau sama dengan jumlah data pada tabel sebelah kiri (berita). Kemudian dengan tabel sebelah kiri dan kanan dikombinasikan tanpa ada penghitungan key pada tabel sebelah kanan sebanyak key pada tabel sebelah kiri. Query ini jika dieksekusi akan memakan waktu sebesar 0.01 detik jauh lebih kecil dari query yang sebelumnya.

Sejauh ini saya masih menggunakan subquery untuk mengoptimasi LEFT JOIN pada contoh kasus seperti di atas. Pada contoh kasus di atas penggunaan subquery meningkatkan waktu eksekusi sebesar 90%.

Comments

Tuk tutorial Join Left ini scriptnya cck buat kita-kita yang ingin meload tampilan tabel lebih cepat. Klo blh request AJAX dunk's

Hehehe

NAL

hwalah...
komen dulu baru baca...

baca komen aja deh... :P

Iya, om...
bikinin tutorial ajax duonx...

pake bahasa Indonesia ajah... :P

pak, kalo ada proyek web development php+mysql secara remote, bisa kan?

@rizahnst
Bisa banget bro.
Ditunggu ya...

mas...
kalo pengen nampilin data dari 2 tabel gmn neeh??
contoh kasus
kita pengen nampilin berita berdasarkan kategori dan kategorinya
nah setiap kategori berisi isi berita tsb...

tblnya
tbl_berita -> id, judul, isi, author, kategori

tbl_kategori -> kode_kategori, kategori

gmn script querynya??? plz help me!!!!
thx before :)

@abdie
Di tabel berita itu seharusnya field kode_kategori bukan kategori. Karena di tabel berita itu sebaiknya kita simpan kodenya saja, bukan kategorinya.

Jadi strukturnya seperti ini :
tbl_berita -> id, judul, isi, author, kode_kategori
tbl_kategori -> kode_kategori, kategori

Untuk menampilkan berita berdasarkan kategorinya, bisa menggunakan query berikut:

SELECT A.*, B.kategori FROM tbl_berita A INNER JOIN tbl_kategori B USING(kode_kategori) WHERE B.kode_kategori = [kode_kategori]

Mudah - mudahan bisa membantu ;)

mas bisa g jelasin optimasi query di mysql pake teknik cost based optimization,,trus cara untuk ngeliat execution plannya gimn?

mas ,saya mou tanya nih ttg optimasi query di mysql pake teknik cost based optimization,bisa g dijelasin,n kalo pengen ngeliat execution plan di mysql gimana caranya,,,trus dimana aku bisa dapetin referensi mengenai cbo...thanks

mas.bs jelasin fungsi dr force index,analyze.straight join ga? sm syntaknya skalian? trus simple sql optimizer itu apa sih?

MAS,KALO kasusnya sm sprti diatas dlm optimalisasi left join dng subquery.tp untk di oracle ap syntak querynya sama.sebab ak mo coba dioracle?

Wah, gak tau juga mas. Tapi biasanya kelakuan dari masing - masing RDBMS itu beda - beda. Jadi gak bisa disamakan.

pak
saya buat query, tapi setelah meload data kok lambat banget yach
contoh querynya sbb:

SELECT
event_kelas.tahun_ajaran,
event_kelas.kelas,
data_siswa.nis,
data_siswa.nm_siswa,
nilai_.nilai,
jenis_tagihan.nama_tagihan,
mata_pelajaran.nm_mata_pelajaran,
mata_pelajaran.`id_mata_pelajaran`,
s_kompetensi.id_aspek,
s_kompetensi.program,
s_kompetensi.periode,
kompetensi_dasar.no_kd_sk
FROM anggota_kelas
INNER JOIN event_kelas ON (anggota_kelas.id_events = event_kelas.id_event_kelas)
INNER JOIN data_siswa ON (anggota_kelas.id_siswa = data_siswa.nis)
INNER JOIN nilai_ ON (data_siswa.nis = nilai_.nis)
INNER JOIN jenis_tagihan ON (nilai_.jenis_tagihan = jenis_tagihan.id_jenis_tagihan)
INNER JOIN mata_pelajaran ON (nilai_.mat_pel = mata_pelajaran.id_mata_pelajaran)
INNER JOIN s_kompetensi ON (nilai_.id_sk = s_kompetensi.id_s_kompetensi)
INNER JOIN kompetensi_dasar ON (nilai_.id_kd = kompetensi_dasar.id_kd)
WHERE
event_kelas.tahun_ajaran='2008/2009' AND
event_kelas.id_event_kelas = '20' AND
s_kompetensi.periode ='semester 1'
GROUP BY `data_siswa`.`id_siswa`

sebagai info:
data nilai_ ada 73.000 record.

gimana caranya supaya mempercepat akses loading data, meski dengan merubah inner join atau tanpa menggunakan inner join
atau ada teknik lain yg lebih cepat untuk menkoneksikan data selain inner join, left join dan right join

thanks

saya mau buat (1)artikel

saya mau buat (1)artikel paling banyak di komentari sama (2)pengomentar terbanyak mas(berdasarkan nama aja), mohon bantuannya. tablenya 2

-tb_artikel
id
judul
isi

-tb_komentar
id
id_artikel
nama
komentar

gmana command sql dan script phpnya tuh mas?

@Anton (1). Untuk artikel

@Anton

(1). Untuk artikel paling banyak dikomentari, berarti tabel tb_komentar harus JOIN dengan tabel tb_artikel.

SELECT `A`.*,COUNT(`K`.`id_artikel`) AS `total` 
FROM `tb_komentar` AS `K` INNER JOIN `tb_artikel` AS `A`
ON `A`.`id` = `K`.`id_artikel` GROUP BY `K`.`id_artikel`
ORDER BY `total` DESC LIMIT 1

(2). Untuk nama yang paling banyak memberikan komentar, cukup dengan grouping di table tb_komentar.

SELECT nama,COUNT(`nama`) AS `total` FROM `tb_komentar`
GROUP BY `nama` ORDER BY `total` DESC LIMIT 1

Perintah SQL di atas belum saya test sama sekali. Bisa jadi ada typo.

Makasih Banyak Yaw..

Makasih Banyak Yaw..

Aku coba cari waktu eksekusi

Aku coba cari waktu eksekusi dari kedua query diatas ...
kok ternyata query yg anda optimasi lbih lama....
---------------------------------------------------+
| Query_ID | Duration | Query
---------------------------------------------------+
| 1 | 0.00029275 |
set profiling=1
| 2 | 0.00093050 |
SELECT A.berita_id, A.judul, A.berita, COALESCE(B.total_komentar, 0) AS total_komentar FROM berita A LEFT JOIN (SELECT berita_id, COUNT(komentar_id) AS total_komentar
FROM komentar GROUP BY berita_id) B USING(berita_id) GROUP BY A.berita_id ORDER BY berita_id DESC |
| 3 | 0.00024875 |
SELECT A.berita_id, A.judul, A.berita, COALESCE(COUNT(B.komentar_id), 0)
AS total_komentar FROM berita A LEFT JOIN komentar BUSING(berita_id) GROUP BY A.berita_id ORDER BY berita_id DESC

*> Apa karena data saya terlalu sedikit????
bisa coba minta sql dump dgn data besar dari kedua tabel diatas nggak??

tolong blz...
my facebook/ym : linzyxer@yahoo.com

@Ras Query di atas, berlaku

@Ras
Query di atas, berlaku untuk tabel dengan data yang banyak. Jika data dalam jumlah kecil, query di atas belum tentu mempercepat query, bisa sama saja atau bahkan lebih lambat seperti yang mas coba.

Data dalam jumlah kecil, tidak membutuhkan optimisasi. Sehingga ada pepatah yang mengatakan "Early optimization is root of all evil".

Maaf, untuk file dump untuk data yang besar, saya sudah tidak punya lagi

Terima kasih atas responnya

saya baru belajar sql.. saya

saya baru belajar sql..

saya pny table
MST2009 -> ID,Begbal,Emp_Name,Branch_Id,Jbtn_Id
TRX2009-> ID,TrxDb,TrxCr,Desc,Date

Kalo saya ingin mengambil data yang ada transaksi (aktif) saya menggunakan comment :

Select A.ID , A.BegBal , A.Emp_Name , A.Branch_ID , A.Jbtn_ID,
B.TrxDb , B.TrxCr , B.Desc , B.Date
from MST2009 A , TRX2009 B Where A.ID=B.ID order by A.ID

tapi dalam kasus saya , saya ingin mengambil data yang tidak bertransksi , saya coba pakai comment ini (coba coba) tapi hasilnya gak sesuai dengan yang saya harapkan...!

Select A.ID , A.BegBal , A.Emp_Name , A.Branch_ID , A.Jbtn_ID,
B.TrxDb , B.TrxCr , B.Desc , B.Date
from MST2009 A , TRX2009 B Where A.ID <> B.ID order by A.ID

karena sudah mentok akhirnya saya pakai cara lama..!
begini.. (dari Foxpro)

close all
set deleted on

use trx2009 alias emp
index on emp_no tag mst
set order to tag mst
select 2
use MST2009
set relation to emp_no into emp
copy to xnew for not found("EMP")

Tolong yah pak.. sebelum nya saya ucapkan terima kasih

@evon Table: MST2009 ->

@evon

Table:
MST2009 -> ID,Begbal,Emp_Name,Branch_Id,Jbtn_Id
TRX2009 -> ID,TrxDb,TrxCr,Desc,Date

Kalau mencari data yang tidak ada transaksinya, berarti data yg di table TRX2009 tidak perlu ditampilkan.

Logikanya kita cuma menghitung jumlah transaksi yg ada di table TRX2009 berdasarkan ID. Nah yang nilainya 0 itu adalah data yang tidak ada transaksinya.

SELECT `MST`.*, COUNT(`TRX`.`ID`) AS `counter` FROM 
`MST2009` AS `MST` LEFT JOIN `TRX2009` AS `TRX`
ON `MST`.`ID` = `TRX`.`ID` GROUP BY `MST`.`ID`
HAVING `counter` = 0;

saya ada query sbb

saya ada query sbb :

select
a.KD_DATI2,
a.KD_KECAMATAN,
a.KD_KELURAHAN,
a.KD_BLOK,
a.TGL_PENDATAAN_OP as "Tanggal Pendataan",
count(a.TGL_PENDATAAN_OP) as "Jumlah Tanggal Pendataan"
from TABEL1 a
where
a.KD_DATI2='02' and
a.KD_KECAMATAN='080' and
a.KD_KELURAHAN='001'
group by
a.KD_DATI2,
a.KD_KECAMATAN,
a.KD_KELURAHAN,
a.KD_BLOK,
a.TGL_PENDATAAN_OP
order by
a.KD_DATI2,
a.KD_KECAMATAN,
a.KD_KELURAHAN,
a.KD_BLOK,
a.TGL_PENDATAAN_OP

yang saya tanyakan bagaimana query diatas dimodif supaya menghasilkan :

KD_DATI2,KD_KECAMATAN,KD_KELURAHAN,KD_BLOK,Tanggal Pendataan, Jumlah Tanggal Pendataan.

Adapun record yg dihasilkan adalah Tanggal Pendataan Paling Lama / paling awal pada tiap-tiap KD_BLOK.

Terima Kasih

kalo kasusnya ini, gimana Sub

kalo kasusnya ini, gimana Sub Query nya bang?

SELECT kode_Jabatan.kd_jab, kode_Jabatan.pejabat, kode_Jabatan.jabatan, kode_Jabatan.unit_kerja, kode_Jabatan.kd_inst, kode_Jabatan.inst_induk, kode_Jabatan.kd_esl, kode_Jabatan.eselon, kode_Jabatan.jab_lengkap FROM kode_Jabatan LEFT JOIN induk ON kode_Jabatan.kd_jab = induk.kd_jabstruk WHERE (((kode_Jabatan.eselon)<>'Non Eselon') AND ((induk.kd_jabstruk) Is Null));

mohon pencerahannya. trimakasih.

mungkin agan bisa coba dengan

mungkin agan bisa coba dengan fungsi explain
jadi kurang lebih seperti ini
explain >>query yg akan diperiksa

untuk optimasi yang paling baik adalah meminimalisi penggunaan fungsi utk lebih jelas bs diliat di manualnya hehe maaf..tapi untuk sedikit meningkatkan performance bisa dicoba dengan indexing field2 yg akan dijadikan parameter pencarian..
CMIIW

Kirim Komentar

Tidak akan dipublikasikan
  • Alamat web dan email dirubah menjadi hyperlink secara otomatis
  • Tag HTML yang diizinkan: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Baris baru maupun paragraph dipisahkan secara otomatis

Informasi lebih lanjut tentang format pesan