Bagaimana cara membuat pencarian mongodb lebih cepat?

Performance adalah seni menghindari pekerjaan yang tidak perlu. Ini adalah temuan saya tentang pengoptimalan kueri MongoDB, Anda dapat menggulir di bawah untuk uji kinerja & hasil

1. Gunakan kueri lean untuk operasi GET

Ini mungkin hal terbaik yang dapat Anda lakukan untuk meningkatkan kinerja kueri. Mongoose memungkinkan Anda untuk menambahkan .lean()_ di akhir kueri Anda yang secara dramatis meningkatkan kinerja kueri Anda dengan mengembalikan objek JSON biasa, bukan Dokumen Mongoose

Dari dokumen Mongoose di lean

“Secara default, kueri Mongoose mengembalikan turunan dari Document. Dokumen jauh lebih berat daripada objek vanilla JavaScript, karena mereka memiliki banyak status internal untuk pelacakan perubahan. Mengaktifkan opsi lean memberi tahu Mongoose untuk melewati instantiating dokumen Mongoose lengkap dan hanya memberi Anda POJO

Memberitahu Mongoose untuk melewatkan dokumen hasil. Ini membuat kueri lebih cepat dan lebih sedikit memori, tetapi dokumen hasil adalah objek JavaScript lama (POJO), bukan dokumen Mongoose. ”

Namun ini harus dibayar mahal, Ini berarti bahwa dokumen lean tidak memilikinya

  • Ubah pelacakan
  • Pengecoran dan validasi
  • Getter dan setter
  • Virtual (termasuk "id")
  • save() fungsi

Jadi biasanya optimal untuk titik akhir GET dan .find() operasi yang tidak menggunakan .save() atau virtual

2. Buat Indeks khusus untuk kueri Anda

MongoDB memungkinkan Anda membuat indeks pada properti lain di Skema Anda selain indeks "_id" default. Dengan begitu dokumen Anda dapat diindeks oleh properti yang Anda tentukan di database untuk akses yang lebih cepat

Anda juga dapat membuat indeks majemuk lebih dari satu properti. Ini berguna jika Anda membuat kueri berdasarkan beberapa bidang. Katakanlah Anda memiliki beberapa database dan Anda ingin menemukan semua hewan yang punah, Anda mungkin akan menulis kueri seperti itu Model.find({type: “Animal”, status: “extinct"})

MongoDB harus melihat semua dokumen untuk menemukan yang cocok dengan kriteria ini, Untuk mengoptimalkan kueri ini, Anda dapat membuat indeks majemuk untuk "ketik" dan "status" dengan menambahkan

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
0. MongoDB sekarang akan mencari di mana untuk menemukan dokumen yang relevan

"1" atau "-1" menunjukkan urutan properti. Urutan kolom ditambahkan ke indeks adalah penting. Untuk penjelasan lebih rinci tentang indeks, lihat dan https. //dokumen. mongodb. com/manual/indeks/

3. Minimalkan permintaan DB (hindari. mengisi() jika mungkin)

Semakin banyak permintaan yang Anda lakukan, semakin lambat waktu respons aplikasi Anda. Cobalah untuk meminimalkan kueri basis data Anda sebanyak mungkin dan menggabungkannya bersama atau idealnya menghindarinya sama sekali dengan menyingkirkan duplikat atau operasi db yang tidak perlu. Anda juga dapat meng-cache hasil database Anda di redis

Cobalah untuk mendefinisikan skema Anda sedemikian rupa sehingga Anda tidak harus terlalu bergantung pada

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
1 dan hubungan dua arah antara model. Karena di situlah database NoSQL tidak terlalu ideal. Setiap properti yang Anda tambahkan dalam model Anda akan dikembalikan dari kueri Anda, jadi jika Anda memiliki larik atau objek bersarang di beberapa bidang ini, dokumen Anda akan dengan mudah memperlambat kinerja kueri Anda

Jika dokumen Anda menyertakan larik referensi ke Model lain, dan Anda menggunakan. populate() untuk menggabungkan data antar koleksi, menggunakan

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
1 akan membutuhkan menjalankan kueri tambahan untuk mengambil dokumen sebenarnya di dalam larik itu untuk Anda, jadi ini mirip dengan menjalankan kueri tambahan untuk setiap id untuk setiap dokumen. Lebih baik menggunakan
const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
_3 daripada
const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
1 jika Anda benar-benar harus

4. Menggunakan. select() untuk memilih properti tertentu yang akan dikembalikan

Saat menanyakan database untuk dokumen, kueri akan mengembalikan seluruh dokumen kepada Anda, tetapi terkadang Anda memiliki dokumen besar dengan banyak bidang dan bidang yang merupakan larik/objek seperti yang dijelaskan di atas dan Anda tidak benar-benar perlu menggunakan semua properti yang dikembalikan

Untuk mencegah database melakukan pekerjaan ekstra untuk mengembalikan bidang ini dengan menambah ukuran dokumen yang dikembalikan, Anda dapat menggunakan luwak

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
5 untuk menyertakan/mengecualikan bidang yang ingin Anda kembalikan secara khusus sebagai berikut

Model.find({type: "Animal"}).select({name: 1})
_

Protip. Ini bekerja sangat baik jika Anda menggunakan GraphQL, jadi Anda tahu bidang apa yang sebenarnya diminta klien dan dapat memilih bidang ini dari database. Saya menulis artikel lain tentang ini di sini

Kiat kinerja Apollo GraphQL. pilih bidang yang diminta sepenuhnya dari database

Mengapa mengambil seluruh baris dari database saat Anda mengetahui kebutuhan klien Anda?

sedang. com

5. Jalankan operasi db secara paralel

Kesalahan umum yang saya lihat dalam kode NodeJS setiap kali orang menggunakan async/menunggu adalah orang menjalankan operasi satu demi satu ketika mereka tidak perlu. Misalnya

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()

Tidak ada alasan untuk menunggu hingga pengguna disimpan untuk menyimpan pos. Sebaliknya, operasi basis data dapat dijalankan secara paralel menggunakan

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
6 sebagai berikut

const [user, post] = await Promise.all([user.save(), post.save()])
_

Meskipun hal ini dapat meningkatkan performa pada level api, kami masih melakukan dua permintaan ke database, jadi lebih baik menggunakan

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
7 atau
const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
8 jika Anda ingin melakukan beberapa operasi sebagai satu batch

6. Cache/gunakan kembali koneksi luwak

Pastikan Anda tidak terhubung dan memutuskan sambungan dari database setiap kali Anda ingin memasukkan/meminta sesuatu dari database atau setiap kali titik akhir Anda terpicu. Sebagai gantinya, Anda harus terhubung sekali di awal aplikasi dan menggunakan kembali koneksi tersebut

Ini karena menyiapkan koneksi TCP baru mahal dari segi waktu, permintaan jaringan dan memori, Juga koneksi baru berarti utas baru yang akan dibuat oleh MongoDB menggunakan memori pada database juga

Mari tulis beberapa tes kinerja untuk melihat hasilnya

Seberapa besar kiat ini dapat meningkatkan kinerja kueri Anda?

Saya menjalankan instalasi lokal MongoDB dan menulis skrip NodeJS yang mengisi database dengan daftar pengguna yang dibuat secara acak berkat kasual. Tujuannya adalah untuk menemukan pengguna yang berusia lebih dari 22 tahun

Saya menulis kueri dengan berbagai cara yang menggabungkan metode yang disebutkan di atas dan mencobanya pada dua koleksi database berbeda yang diisi dengan kumpulan data yang sama. Satu koleksi memiliki indeks pada properti "usia" sementara yang lainnya tidak. Hasilnya diukur menggunakan

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
_9 API dan pengujian dijalankan menggunakan versi terbaru dari NodeJS (v12. 7. 0) dan luwak (v5. 6. 7)

Pertama mari kita mulai dengan Skema, di sini saya mendefinisikan koleksi/skema pengguna, satu memiliki indeks pada properti usia sementara yang lain tidak

Sekarang mari kita menulis beberapa kode untuk mengisi database dengan data acak. Saya menggunakan perpustakaan biasa yang cukup berguna untuk menghasilkan data tiruan semantik

Sekarang database sudah siap, Ayo tulis kueri kita

Hasil Kinerja dan Pengamatan

Dengan 1k pengguna
default_query. 135. 646 md
query_with_index. 168. 763 md
query_with_select. 27. 781 md
query_with_select_index. 55. 686 md
lean_query. 7. 191 md
lean_with_index. 7. 341 md
lean_with_select. 4. 226 md
lean_select_index. 7. 881ms

Dengan 10k pengguna dalam database

default_query. 323. 278 md
query_with_index. 355. 693 md
query_with_select. 212. 403 md
query_with_select_index. 183. 736 md
lean_query. 92. 935 md
lean_with_index. 92. 755 md
lean_with_select. 36. 175 md
lean_select_index. 38. 456 md

Dengan 100K Pengguna dalam database
default_query. 2425. 857 md
query_with_index. 2371. 716ms
query_with_select. 1580. 393 md
query_with_select_index. 1583. 015 md
lean_query. 858. 839ms
lean_with_index. 944. 712 md
lean_with_select. 383. 548 md
lean_select_index. 458. 000 md

Seperti yang Anda lihat, versi kueri yang dioptimalkan yang menggunakan .lean()

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
5 dan
const [user, post] = await Promise.all([user.save(), post.save()])
2 sekitar 10x lebih cepat daripada kueri default, yang merupakan kemenangan besar

.lean() tampaknya memiliki dampak tertinggi pada kinerja diikuti oleh

const user = new User({name: "bob"})
const post = new Post({title: "hello"})
await user.save()
await post.save()
5 , Alasan indeks khusus saya tidak membantu dalam kasus itu adalah karena indeks saya tidak cukup selektif karena hanya mengurangi jumlah dokumen yang dipindai sebesar 50%

Anda dapat menemukan skrip yang digunakan untuk pengujian ini dan Anda bahkan dapat mencobanya sendiri di sini https. //github. com/khaled osman/mongo-performance-experiments

Seberapa cepat kueri MongoDB?

2. Seberapa cepat kueri MongoDB? . Kunci utama atau kueri indeks hanya perlu beberapa milidetik .

Bagaimana indeks mempercepat kueri di MongoDB?

Indeks meningkatkan efisiensi operasi baca dengan mengurangi jumlah data yang perlu diproses oleh operasi kueri . Ini menyederhanakan pekerjaan yang terkait dengan pemenuhan kueri dalam MongoDB.

Bagaimana cara mengoptimalkan kueri NoSQL?

Pengoptimal Database untuk Meningkatkan Pencarian Kinerja NoSQL .
Penulisan ulang kueri berdasarkan heuristik, biaya, atau keduanya. .
Pemilihan indeks. .
Bergabung menyusun ulang. .
Tipe gabung

Apakah MongoDB bagus untuk pencarian?

Menawarkan skalabilitas, keandalan, dan performa tinggi. MongoDB juga menggunakan indeks berbasis teks untuk kueri teks lengkap, tetapi pencariannya lambat , dan server pencarian tidak menyediakan tokenizer dan penganalisa seperti yang dilakukan Elasticsearch.