Apa yang memenuhi syarat "terlalu banyak permintaan basis data" dalam kode?


17

Ini adalah diskusi saya sendiri dan beberapa rekan kerja saya sedang dan berpikir saya akan datang ke sini dan melihat bagaimana jika ada konsensus umum tentang itu.

Ini pada dasarnya bermuara pada 2 pendapat berikut tentang panggilan basis data: 1. Buat satu panggilan besar untuk mendapatkan semua yang mungkin diperlukan untuk mengurangi basis data jumlah panggilan DB 2. Buat panggilan terpisah yang lebih kecil berdasarkan apa yang diminta untuk mengurangi ukuran Panggilan DB

Di mana ini terutama ikut bermain adalah dalam kode umum. Kami akan menggunakan contoh kelas Karyawan karena itu cukup mudah.

Katakanlah kelas Karyawan Anda memiliki 10 atribut nilai (nama depan, nama belakang, karyawan, dll.) Dan kemudian 2 atribut kelas ... 1 menunjuk ke kelas Departemen dan kemudian 1 penyelia yang menunjuk kembali ke objek Karyawan lain.

Dalam pola pikir # 1, Anda akan membuat satu panggilan yang mengembalikan data Karyawan serta bidang yang diperlukan untuk mengisi atribut Departemen dan Pengawas ... atau setidaknya bidang yang paling sering digunakan dari sub objek tersebut.

Dalam pola pikir # 2, Anda hanya akan mengisi objek Karyawan pada awalnya dan kemudian hanya mengisi objek Departemen dan Pengawas jika dan ketika mereka benar-benar diminta.

Pendirian 2 cukup mudah ... meminimalkan ukuran permintaan dan berapa banyak objek database yang perlu dipukul setiap kali salah satu permintaan dibuat. Sikap # 1 adalah bahwa bahkan jika itu dapat diimplementasikan dengan benar, fakta bahwa kode harus membuat beberapa koneksi akan menyebabkan lebih banyak ketegangan pada koneksi antara server web dan database sebagai lawan mengurangi itu.

Kekuatan pendorong di balik meneliti ini adalah bahwa jumlah lalu lintas antara server web dan server basis data kami semakin tak terkendali.


7
Dalam pengalaman saya, tidak ada "jawaban yang benar" untuk ini. Ada keseimbangan antara latensi dan throughput. Latensi rendah dapat mentolerir banyak permintaan kecil atau bahkan satu permintaan besar; Namun, tautan latensi tinggi cenderung lebih baik memindahkan banyak data sekaligus. Namun demikian, jika throughput rendah dalam konfigurasi latensi tinggi, Anda lebih baik mengambil potongan yang lebih kecil agar lebih responsif.

3
Mungkin terkait dengan masalah n +1 stackoverflow.com/questions/97197/…
Valera Kolupaev

@Valera: untuk kenyamanan di sini adalah tautan yang diposting pada pertanyaan itu: realsolve.co.uk/site/tech/hib-tip-pitfall.php?name=n1selects
rwong

4
"jumlah lalu lintas antara server web dan server basis data kami semakin tak terkendali." Apa artinya? Bisakah Anda spesifik tentang apa masalah sebenarnya ? Apakah Anda memiliki masalah kinerja? Sudahkah Anda melakukan profil dan pengukuran? Harap berikan hasil aktual dari pengukuran aktual sebagai bagian dari pertanyaan. Kalau tidak, kita hanya menebak.
S.Lott

Jawaban:


8

Jika kekuatan pendorong di belakang pertanyaan ini terlalu banyak lalu lintas, apakah Anda sudah melihat caching objek yang sering digunakan? Misalnya: Setelah Anda mendapatkan objek Karyawan dan Departemen dan Pengawas, mungkin ide yang baik untuk menambahkan mereka cache sehingga jika mereka diminta lagi dalam waktu dekat, mereka sudah ada dalam cache dan tidak perlu diambil lagi. Tentu saja, cache harus membiarkan objek yang jarang digunakan berakhir, dan juga harus dapat menghapus objek yang telah dimodifikasi oleh aplikasi dan disimpan kembali ke database.

Bergantung pada bahasa dan kerangka kerja apa yang Anda gunakan, mungkin sudah ada kerangka kerja cache yang dapat melakukan sebagian (atau sebagian besar) dari apa yang Anda butuhkan. Jika Anda menggunakan Java, Anda bisa melihat ke dalam Apache Commons-Cache (saya belum pernah menggunakannya untuk sementara waktu, dan sementara itu tampak tidak aktif, itu masih tersedia untuk digunakan dan itu cukup baik terakhir kali saya menggunakannya).


3

Selalu gunakan keterbacaan dan kejelasan saat pertama kali Anda menulis sesuatu. Anda kemudian dapat refactor jika dan ketika Anda perlu. Lakukan uji beban untuk menemukan kemacetan, dalam banyak kasus ini bukan jumlah panggilan yang menyebabkan masalah tetapi yang ditulis dengan buruk.

Adapun apa yang mengklasifikasikan terlalu banyak, itu tergantung pada aplikasi. Untuk sebagian besar aplikasi web, apa pun di bawah 30 detik hanya bisa diterima. Saya akan berbicara dengan pengguna Anda tentang harapan mereka.


Apa yang dimaksud dengan panggilan db yang ditulis dengan buruk?
nu everest

3

Pertanyaan Anda tampaknya didasarkan pada asumsi bahwa Anda harus menebak data apa yang akan dibutuhkan untuk halaman tertentu. Bukan itu masalahnya. Ini tidak semudah pendekatan naif, tetapi Anda dapat merancang kode Anda sehingga Anda akan tahu apakah Anda akan memerlukan atribut departemen atau penyelia sebelum membuat panggilan basis data apa pun.


3

Ini adalah aturan yang saya gunakan, mungkin itu akan berguna bagi Anda.

  1. Ukur dulu! Saya bahkan tidak akan melihat kode yang "mungkin lambat" kecuali saya benar-benar dapat melihat lalu lintas mengalir ke sumber daya itu dan sumber daya itu merespons dengan lambat.
  2. 1 Permintaan = K kueri. Frekuensi saya berbicara dengan basis data sepenuhnya ditentukan oleh jenis sumber daya yang diminta; dan tidak pernah dengan sifat permintaan atau keadaan sumber daya itu; Dalam contoh Anda, itu mungkin paling banyak 3 pertanyaan: 1 untuk Karyawan, 1 untuk Departemen dan 1 untuk Pengawas; Tidak masalah berapa banyak masing-masing ada.
  3. Jangan tanya apa yang tidak akan Anda Gunakan . Jika ini adalah HTTP yang sedang kita bicarakan, tidak ada gunanya meminta data untuk nanti; tidak ada yang lebih baru; setiap permintaan dimulai dari yang bersih. Terkadang saya membutuhkan sebagian besar kolom dari sebuah tabel, tetapi kadang-kadang saya hanya membutuhkan satu atau dua; ketika saya tahu persis bidang yang saya butuhkan, saya akan meminta hal itu.
  4. Lempar perangkat keras pada masalahnya. Server murah; Terkadang Anda bisa mendapatkan kinerja yang cukup hanya dengan memindahkan basis data ke kotak yang lebih besar; atau mengirim beberapa pertanyaan ke replika hanya-baca.
  5. Pertama-tama batalkan cache, lalu terapkan caching. Keinginan untuk memasukkan data yang sering digunakan atau sulit untuk ditanyakan dalam cache adalah kuat; tetapi terlalu sering, mengusir data yang tidak terpakai atau data superseded yang kedaluwarsa diabaikan. Jika Anda tahu cara mengeluarkan data dari cache; maka Anda aman memasukkannya ke dalam cache; Jika ternyata lebih mahal untuk membatalkan cache daripada hanya melakukan query; maka Anda tidak perlu cache.

2

Kedua strategi di sini benar-benar valid. Ada kelebihan dan kekurangan untuk masing-masing:

Satu panggilan untuk ketiga objek:

  • akan tampil lebih cepat
  • akan memberi Anda apa yang Anda butuhkan dalam kasus di mana Anda membutuhkannya
  • mungkin hanya bisa digunakan dalam satu kasus (ini mungkin kasus yang sangat umum)
  • akan lebih sulit untuk dipertahankan
  • harus dirawat lebih sering (karena akan berubah jika ada skema 3 objek atau perubahan data yang diperlukan)

Satu panggilan per objek (total 3 panggilan)

  • Memberi Anda panggilan tujuan umum untuk mengisi satu instance dari setiap jenis objek; mereka kemudian dapat digunakan secara mandiri
  • Akan lebih mudah dikelola karena struktur kueri akan lebih sederhana.
  • Akan lebih lambat (tidak harus 3 kali lebih lambat, tetapi overhead meningkat untuk data yang sama)
  • Dapat menyebabkan masalah dengan mengambil data yang tidak dibutuhkan (menarik seluruh catatan saat Anda membutuhkan satu bidang boros)
  • Dapat menyebabkan N + 1 masalah ketika ada banyak-ke-satu hubungan, jika kueri catatan tunggal dikirim N kali, satu per catatan dalam koleksi.

Menanggapi beberapa masalah Anda (# 3 dan 5 di daftar kedua) ... Bagaimana jika Supervisor dan Departemen hanya menggunakan 1/3 (atau kurang) waktunya? Bagaimana jika kode itu dirancang untuk mendapatkan semua anak segera setelah objek kode <> yang dikodekan untuk mengandung mereka pertama kali direferensikan? ... Apakah itu meringankan sebagian besar kewaspadaan?
user107775

Jika objek tambahan jarang diperlukan, maka dalam kasus umum ini akan melakukan lebih cepat (lebih sedikit data untuk mengambil) tetapi kasus terburuk akan lebih lambat (data yang sama atau lebih diambil, menggunakan tiga kali overhead komunikasi dari komputer Anda). Sedangkan untuk masalah N +1, Anda hanya perlu membuat arsitek kueri yang mengambil daftar objek untuk dapat melakukannya berdasarkan kunci asing ke sisi "satu" dari hubungan, dan kemudian menarik beberapa baris keluar dari hasil permintaan. Anda tidak dapat menggunakan versi kueri yang harus memiliki kunci utama catatan.
KeithS

1

Bagi saya, Terlalu banyak permintaan DB membuat lebih banyak permintaan daripada yang Anda butuhkan untuk memuat data yang Anda butuhkan pada waktu tertentu.

Jadi saya tidak perlu data, jangan buang memori untuk menghindari perjalanan kedua nanti. Tetapi jika Anda membutuhkan jumlah data, Anda harus meminimalkan panggilan ke db.

Jadi memiliki kedua opsi, dan gunakan masing-masing di mana situasi membutuhkannya.

EDIT: Perlu diingat bahwa ofcourse ini tergantung pada situasi Anda juga. Jika itu WebApp misalnya, Anda harus memiliki pertimbangan yang berbeda daripada jika itu adalah aplikasi desktop yang mengakses DB dalam jaringan Anda, yang bertentangan dengan di seluruh web untuk WepApp.


Bagaimana jika Anda menulis kode umum dan Anda tidak yakin dengan cara di mana kode Anda akan digunakan. Mungkin Anda tidak akan pernah membayangkan seseorang yang tidak membutuhkan Supervisor tetapi ternyata aplikasi yang Anda kerjakan adalah satu-satunya yang membutuhkannya. Tentu, Anda dapat menulis fungsi terpisah ... satu untuk tidak memasukkannya dan yang lain untuk memasukkannya tetapi pada titik mana kode umum Anda mulai membutuhkan terlalu banyak pengetahuan terperinci untuk digunakan?
user107775

@ user107775 Saya biasanya menulis hanya dua fungsi untuk setiap kasus; yang hanya mengembalikan nilai properti, dan yang mengembalikan kelas dengan semua kelas terkait. Ini karena PALING kali, Anda hanya perlu properti. Dengan cara ini, Anda tidak perlu pengetahuan detail, hanya yang mendapatkan dasar-dasar dan yang lainnya segalanya. Saya menemukan ini sebagai keseimbangan yang masuk akal. (Namun beberapa kasus khusus memerlukan lebih banyak optimasi, tetapi berdasarkan kasus per kasus).
AJC

1

Terhubung ke DB, kirim permintaan dan parsing biasanya membutuhkan waktu yang signifikan dibandingkan dengan mengambil hasil, sehingga tren keseluruhan adalah untuk menggabungkan pertanyaan sebanyak mungkin dalam satu permintaan.

Namun, melakukan ini semua dalam satu kesempatan akan membuat kode tidak dapat dipelihara. Sebaliknya, biasanya diperoleh dengan lapisan abstraksi tambahan: kode menjadwalkan beberapa permintaan sesuai kebutuhan, kemudian mesin mem-parsing ini sebagai satu permintaan besar (mungkin menggunakan cache di jalan) dan kemudian balasan dikirim sesuai kebutuhan.

Tentu saja tidak selalu semua dapat diambil dalam satu kueri - Anda akan sering memiliki kueri yang menyediakan data yang diperlukan untuk membangun kueri berikutnya, jadi Anda harus mengulanginya. Masih mengejutkan bundel pertanyaan dan melakukan sebanyak mungkin sekaligus lebih baik daripada ratusan tembakan kecil ke database.

Jadi, rencanakan apa yang Anda butuhkan, minta dan ambil kembali, jika lebih banyak diperlukan, minta dan ambil lagi, lalu gunakan data dalam menghasilkan konten. Pasti menghindari menggunakan permintaan basis data seperti inisialisasi variabel lokal yang tersebar di seluruh kode.


1

Kami tidak tahu cukup banyak tentang aplikasi Anda untuk mengetahui pilihan mana yang Anda bersalah karena terlalu cepat mengoptimalkannya. Seberapa sering data Supervisor digunakan? Sepertinya itu bisa sia-sia, tapi kita tidak tahu. Jika Anda memisahkannya, Anda mungkin dapat memonitor sistem Anda untuk melihat seberapa sering mereka digunakan bersama. Daripada Anda dapat membuat keputusan untuk hanya menggabungkan mereka dalam satu panggilan. Jika tidak, jika Anda mulai membuat leher botol dengan satu panggilan besar ini, di mana Anda mulai melakukan pemecahan masalah? Sulit untuk mengidentifikasi apa yang masuk akal untuk dihilangkan. Lebih banyak bidang data dapat ditambahkan ke proses ini.

Akan menarik untuk mengetahui berapa banyak ini berasal dari memori db vs disk. Tidak ada yang membuat saya merasa bahwa departemen lebih atau kurang cenderung berubah dibandingkan dengan alamat.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.