Apakah pertanyaan individual lebih cepat dari gabungan?

44

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:

SQL Fiddle

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?

Martin
sumber
Komentar bukan untuk diskusi panjang; percakapan ini telah dipindahkan ke obrolan .
Jack Douglas
1
Saya menjalankan tolok ukur dan memposting hasilnya dalam sebuah artikel di Medium . Saya akan menambahkan jawaban di sini, tetapi sudah melakukannya pada pertanyaan lain , dan memposting jawaban yang sama untuk beberapa pertanyaan tidak disukai .
Benjamin

Jawaban:

45

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?

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.

Saya telah memperhatikan bahwa ketika saya harus mendapatkan informasi dari beberapa tabel, "seringkali" lebih cepat untuk mendapatkan informasi ini melalui beberapa kueri pada masing-masing tabel (mungkin berisi gabungan bagian dalam yang sederhana) dan menambal data bersama-sama di sisi klien untuk dicoba untuk menulis kueri gabungan (kompleks) di mana saya bisa mendapatkan semua data dalam satu kueri.

Sangat mungkin bahwa skema atau indeks basis data dapat ditingkatkan untuk lebih melayani kueri yang Anda ajukan.

Permintaan gabungan selalu harus mengembalikan lebih banyak data daripada kueri individual yang menerima jumlah informasi yang sama.

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.

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.

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.

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?

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.

Jon Seigel
sumber
+1 untuk bandwidth jaringan juga merupakan sumber daya yang terbatas.
Hari Harker
OP mengatakan bahwa set hasil data yang digabungkan selalu lebih besar. > Kueri yang tergabung selalu harus mengembalikan lebih banyak data daripada kueri individual. Saya pikir ini benar secara objektif (untuk> =), misalnya set hasil berbeda dalam ukuran, sehingga lebih banyak data melalui kabel. Apakah Anda memiliki contoh di mana ini tidak benar? Jika saya bergabung dengan Penulis -> Tulisan dan Penulis memiliki bidang yang disebut "biografi" yang merupakan bidang JSON 1MB, untuk Penulis 100 Posting, melalui kabel saya akan mengirimkan 100MB vs 1MB. Apakah ini salah?
hytromo
6

Tentu saja, saya tidak mengukur kinerja apa pun dengan ini

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.

Leigh Riffel
sumber
2

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.

Michael Green
sumber
-3

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.

TomTom
sumber
5
Tidak ada "inefisiensi jaringan" dalam suatu gabungan - semua itu terjadi pada server basis data, jadi tidak ada jaringan yang terlibat (kecuali jika Anda bergabung melalui tautan db!)
Chris Saxon
2
Anda mungkin ingin mempertimbangkan apakah lapisan jaringan memiliki kompresi atau tidak. Oracle * SQL Net tidak, dalam nilai yang berulang dalam kolom yang sama dikompresi secara efisien.
David Aldridge
3
@ TomTom Anda mungkin ada benarnya atau tidak (seperti David Aldridge menunjuk, masalah kompresi) tetapi kata-kata Anda membingungkan. "Jaringan inefisiensi bergabung" ? Sungguh, perbaiki itu jadi jelas apa yang Anda maksud.
ypercubeᵀᴹ
@ ChrisSaxon yakin ada, gambar Anda memiliki tabel untuk laporan "title-> base-> table-rows" dan Anda membutuhkan semua baris sehingga Anda bisa bergabung dengan 3 tabel ini. Setiap tabel memiliki varchars panjang sehingga yang terjadi adalah untuk setiap baris Anda mengulangi varchars panjang ini. Lapisan aplikasi perlu mengalokasikan memori untuk semua string ini dan kemudian mengelompokkannya untuk model Anda. Jadi saya pikir itulah yang dia maksud, ada lebih banyak data yang dikirim
MIKE
@IKE yang bergantung pada ekspresi yang Anda pilih, bukan gabungan. Dan mungkin ada kompresi jaringan. Dalam Oracle Database SQL * Net menghapus nilai duplikat berulang nicetheory.io/2018/01/11/…
Chris Saxon