Pertanyaan konseptual: Apakah pertanyaan individu lebih cepat daripada bergabung, atau: Haruskah saya mencoba memeras setiap info yang saya inginkan di sisi klien menjadi satu pernyataan SELECT atau hanya menggunakan sebanyak mungkin yang dianggap nyaman?
TL; DR : Jika kueri gabungan saya membutuhkan waktu lebih lama daripada menjalankan kueri individual, apakah ini salah saya atau apakah ini yang diharapkan?
Pertama, saya tidak terlalu paham basis data, jadi mungkin hanya saya, tetapi saya perhatikan bahwa ketika saya harus mendapatkan informasi dari beberapa tabel, "seringkali" lebih cepat untuk mendapatkan informasi ini melalui beberapa kueri di setiap tabel (mungkin berisi gabungan bagian dalam yang sederhana) dan menambal data bersama di sisi klien yang mencoba menulis kueri gabungan (kompleks) di mana saya bisa mendapatkan semua data dalam satu kueri.
Saya telah mencoba menyatukan satu contoh sederhana:
Pengaturan Skema :
CREATE TABLE MASTER
( ID INT NOT NULL
, NAME VARCHAR2(42 CHAR) NOT NULL
, CONSTRAINT PK_MASTER PRIMARY KEY (ID)
);
CREATE TABLE DATA
( ID INT NOT NULL
, MASTER_ID INT NOT NULL
, VALUE NUMBER
, CONSTRAINT PK_DATA PRIMARY KEY (ID)
, CONSTRAINT FK_DATA_MASTER FOREIGN KEY (MASTER_ID) REFERENCES MASTER (ID)
);
INSERT INTO MASTER values (1, 'One');
INSERT INTO MASTER values (2, 'Two');
INSERT INTO MASTER values (3, 'Three');
CREATE SEQUENCE SEQ_DATA_ID;
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.5);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.7);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 2, 2.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.14);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.7);
Kueri A :
select NAME from MASTER
where ID = 1
Hasil :
| NAME |
--------
| One |
Kueri B :
select ID, VALUE from DATA
where MASTER_ID = 1
Hasil :
| ID | VALUE |
--------------
| 1 | 1.3 |
| 2 | 1.5 |
| 3 | 1.7 |
Kueri C :
select M.NAME, D.ID, D.VALUE
from MASTER M INNER JOIN DATA D ON M.ID=D.MASTER_ID
where M.ID = 1
Hasil :
| NAME | ID | VALUE |
---------------------
| One | 1 | 1.3 |
| One | 2 | 1.5 |
| One | 3 | 1.7 |
Tentu saja, saya tidak mengukur kinerja apa pun dengan ini, tetapi orang dapat mengamati:
- Kueri A + B mengembalikan informasi yang dapat digunakan dengan jumlah yang sama dengan Kueri C.
- A + B harus mengembalikan 1 + 2x3 == 7 "Sel Data" ke klien
- C harus mengembalikan 3x3 == 9 "Sel Data" ke klien, karena dengan bergabung saya secara alami menyertakan beberapa redundansi dalam set hasil.
Generalisasi dari ini (sejauh apa adanya):
Permintaan gabungan selalu harus mengembalikan lebih banyak data daripada kueri individual yang menerima jumlah informasi yang sama. Karena basis data harus menggabungkan data, untuk kumpulan data yang besar seseorang dapat mengasumsikan bahwa basis data harus melakukan lebih banyak pekerjaan pada satu permintaan gabungan daripada pada permintaan individu, karena (setidaknya) ia harus mengembalikan lebih banyak data ke klien.
Apakah ini akan mengikuti dari ini, bahwa ketika saya amati bahwa memecah permintaan sisi klien menjadi beberapa kueri menghasilkan kinerja yang lebih baik, ini adalah cara yang tepat, atau apakah itu lebih berarti bahwa saya mengacaukan kueri yang tergabung?
Jawaban:
Dalam skenario kinerja apa pun, Anda harus menguji dan mengukur solusi untuk melihat mana yang lebih cepat .
Yang mengatakan, itu hampir selalu terjadi bahwa hasil gabungan ditetapkan dari database yang disetel dengan benar akan lebih cepat dan skala lebih baik daripada mengembalikan baris sumber ke klien dan kemudian bergabung dengan mereka di sana. Secara khusus, jika set input besar dan set hasil kecil - pikirkan tentang kueri berikut dalam konteks kedua strategi: bergabung bersama dua tabel yang masing-masing 5 GB, dengan set hasil 100 baris. Itu ekstrem, tapi Anda mengerti maksud saya.
Sangat mungkin bahwa skema atau indeks basis data dapat ditingkatkan untuk lebih melayani kueri yang Anda ajukan.
Biasanya ini bukan masalahnya. Sebagian besar waktu, bahkan jika set input besar, set hasil akan jauh lebih kecil dari jumlah input.
Bergantung pada aplikasinya, set hasil kueri yang sangat besar yang dikembalikan ke klien merupakan tanda bahaya langsung: apa yang dilakukan klien dengan sekumpulan data besar yang tidak dapat dilakukan lebih dekat ke basis data? Menampilkan 1.000.000 baris ke pengguna sangat mencurigakan. Bandwidth jaringan juga merupakan sumber daya yang terbatas.
Belum tentu. Jika data diindeks dengan benar, operasi gabungan lebih mungkin dilakukan lebih efisien di database tanpa perlu memindai sejumlah besar data. Selain itu, mesin basis data relasional secara khusus dioptimalkan pada tingkat rendah untuk bergabung ; tumpukan klien tidak.
Karena Anda mengatakan Anda tidak berpengalaman dalam hal database, saya akan menyarankan untuk mempelajari lebih lanjut tentang desain basis data dan penyempurnaan kinerja. Saya cukup yakin di situlah masalahnya terletak di sini. Pertanyaan SQL yang tidak efisien juga dimungkinkan, tetapi dengan skema sederhana yang cenderung menjadi masalah.
Nah, bukan berarti tidak ada cara lain untuk meningkatkan kinerja. Ada skenario di mana Anda mungkin memilih untuk memindai set data menengah ke besar dan mengembalikannya ke klien jika tujuannya adalah untuk menggunakan semacam mekanisme caching. Caching bisa jadi hebat, tetapi memperkenalkan kompleksitas dalam desain Anda. Caching bahkan mungkin tidak sesuai untuk aplikasi Anda.
Satu hal yang belum disebutkan di mana pun adalah menjaga konsistensi dalam data yang dikembalikan dari database. Jika kueri terpisah digunakan, kemungkinan besar (karena banyak faktor) memiliki data yang tidak konsisten dikembalikan, kecuali bentuk isolasi snapshot digunakan untuk setiap set kueri.
sumber
Anda mengumpulkan beberapa kode sampel yang baik. Apakah Anda melihat waktu di SQL Fiddle? Bahkan beberapa pengujian kinerja tidak ilmiah singkat akan menunjukkan bahwa kueri tiga dalam demonstrasi Anda membutuhkan waktu yang sama untuk dijalankan sebagai kueri satu atau dua secara terpisah. Gabungan satu dan dua memakan waktu sekitar dua kali lebih lama dari tiga dan itu sebelum setiap sisi klien bergabung dilakukan.
Saat Anda meningkatkan data, kecepatan kueri satu dan dua akan berbeda, tetapi penggabungan basis data akan tetap lebih cepat.
Anda juga harus mempertimbangkan apa yang akan terjadi jika gabungan batin menghilangkan data.
sumber
Pengoptimal kueri juga harus dipertimbangkan. Perannya adalah untuk mengambil SQL deklaratif Anda dan menerjemahkannya ke dalam langkah prosedural. Untuk menemukan kombinasi langkah-langkah prosedural yang paling efisien, ia akan memeriksa kombinasi penggunaan indeks, jenis, set caching hasil antara dan segala macam hal lainnya juga. Jumlah permutasi bisa menjadi sangat besar bahkan dengan apa yang tampak seperti pertanyaan yang cukup sederhana.
Banyak perhitungan yang dilakukan untuk menemukan rencana terbaik didorong oleh distribusi data dalam tabel. Distribusi ini disampel dan disimpan sebagai objek statistik. Jika ini salah, mereka mengarahkan pengoptimal untuk membuat pilihan yang buruk. Pilihan yang buruk di awal rencana menyebabkan pilihan yang lebih buruk di kemudian hari dalam efek bola salju.
Bukan tidak lazim untuk kueri berukuran sedang yang mengembalikan jumlah data sederhana untuk mengambil menit untuk dijalankan. Pengindeksan yang benar dan statistik yang baik kemudian mengurangi ini menjadi milidetik.
sumber
Berbagai pertanyaan adalah cara untuk melakukannya. Jika Anda menangani skenario sederhana seperti itu - biaya overhead dari pengoptimal kueri adalah faktor. Dengan lebih banyak data, inefisiensi jaringan sambungan (baris redundan) masuk. Hanya dengan lebih banyak data, ada efisiensi.
Pada akhirnya, apa yang Anda alami adalah sesuatu yang dilihat banyak pengembang. DBA selalu mengatakan "tidak, buat bergabung" tetapi kenyataannya adalah: itu lebih cepat untuk membuat banyak pilihan sederhana dalam kasus ini.
sumber