MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Cara Mengoptimalkan Kinerja MongoDB

Performa database yang luar biasa penting ketika Anda mengembangkan aplikasi dengan MongoDB. Terkadang proses penyajian data secara keseluruhan dapat menurun karena sejumlah alasan, beberapa di antaranya termasuk:

  • Pola desain skema yang tidak sesuai
  • Penggunaan strategi pengindeksan yang tidak tepat atau tidak sama sekali
  • Perangkat keras tidak memadai
  • Keterlambatan replikasi
  • Teknik kueri berkinerja buruk

Beberapa kemunduran ini mungkin memaksa Anda untuk meningkatkan sumber daya perangkat keras sementara yang lain mungkin tidak. Misalnya, struktur kueri yang buruk dapat mengakibatkan kueri membutuhkan waktu lama untuk diproses, menyebabkan jeda replika dan bahkan mungkin beberapa kehilangan data. Dalam hal ini, orang mungkin berpikir bahwa mungkin memori penyimpanan tidak cukup, dan mungkin perlu ditingkatkan. Artikel ini membahas prosedur paling tepat yang dapat Anda terapkan untuk meningkatkan kinerja database MongoDB Anda.

Desain Skema

Pada dasarnya dua hubungan skema yang paling umum digunakan adalah...

  • Satu-ke-Beberapa
  • Satu-ke-Banyak

Meskipun desain skema yang paling efisien adalah hubungan Satu-ke-Banyak, masing-masing memiliki kelebihan dan keterbatasannya sendiri.

Satu-ke-Beberapa

Dalam hal ini, untuk bidang tertentu, ada dokumen yang disematkan tetapi tidak diindeks dengan identitas objek.

Berikut ini contoh sederhananya:

{
      userName: "Brian Henry",
      Email : "[email protected]",
      grades: [
             {subject: ‘Mathematics’,  grade: ‘A’},
             {subject: English,  grade: ‘B’},
      ]
}

Salah satu keuntungan menggunakan hubungan ini adalah Anda bisa mendapatkan dokumen yang disematkan hanya dengan satu kueri. Namun, dari sudut pandang kueri, Anda tidak dapat mengakses satu pun dokumen yang disematkan. Jadi, jika Anda tidak akan mereferensikan dokumen yang disematkan secara terpisah, sebaiknya gunakan desain skema ini.

Satu-ke-Banyak

Untuk hubungan ini data dalam satu database berhubungan dengan data dalam database yang berbeda. Misalnya, Anda dapat memiliki database untuk pengguna dan database lain untuk posting. Jadi, jika pengguna membuat posting, itu direkam dengan id pengguna.

Skema pengguna

{ 
    Full_name: “John Doh”,
    User_id: 1518787459607.0
}

Skema postingan

{
    "_id" : ObjectId("5aa136f0789cf124388c1955"),
    "postTime" : "16:13",
    "postDate" : "8/3/2018",
    "postOwnerNames" : "John Doh",
    "postOwner" : 1518787459607.0,
    "postId" : "1520514800139"
}

Keuntungan dengan desain skema ini adalah dokumen dianggap standalone (dapat dipilih secara terpisah). Keuntungan lain adalah bahwa desain ini memungkinkan pengguna dari id yang berbeda untuk berbagi informasi dari skema posting (maka nama One-to-Many) dan kadang-kadang dapat skema "N-ke-N" - pada dasarnya tanpa menggunakan tabel bergabung. Batasan dengan desain skema ini adalah Anda harus melakukan setidaknya dua kueri untuk mengambil atau memilih data di koleksi kedua.

Oleh karena itu, cara memodelkan data akan bergantung pada pola akses aplikasi. Selain itu, Anda perlu mempertimbangkan desain skema yang telah kita bahas di atas.

Teknik Optimasi untuk Desain Skema

  1. Gunakan penyematan dokumen sebanyak mungkin untuk mengurangi jumlah kueri yang perlu Anda jalankan untuk kumpulan data tertentu.

  2. Jangan gunakan denormalisasi untuk dokumen yang sering diperbarui. Jika anfield akan sering diperbarui, maka akan ada tugas untuk menemukan semua instance yang perlu diperbarui. Hal ini akan menghasilkan pemrosesan kueri yang lambat, sehingga membanjiri bahkan manfaat yang terkait dengan denormalisasi.

  3. Jika ada kebutuhan untuk mengambil dokumen secara terpisah, maka tidak perlu menggunakan penyematan karena kueri kompleks seperti pemipaan agregat membutuhkan lebih banyak waktu untuk dieksekusi.

  4. Jika susunan dokumen yang akan disematkan cukup besar, jangan disematkan. Pertumbuhan array setidaknya harus memiliki batas terikat.

Pengindeksan yang Tepat

Ini adalah bagian yang lebih penting dari penyetelan kinerja dan mengharuskan seseorang untuk memiliki pemahaman yang komprehensif tentang kueri aplikasi, rasio membaca dan menulis, dan berapa banyak memori bebas yang dimiliki sistem Anda. Jika Anda menggunakan indeks, kueri akan memindai indeks dan bukan koleksi.

Indeks yang sangat baik adalah indeks yang melibatkan semua bidang yang dipindai oleh kueri. Ini disebut sebagai indeks majemuk.

Untuk membuat indeks tunggal untuk bidang, Anda dapat menggunakan kode ini:

db.collection.createIndex({“fields”: 1})

Untuk indeks gabungan, untuk membuat pengindeksan:

db.collection.createIndex({“filed1”: 1, “field2”:  1})

Selain kueri yang lebih cepat dengan menggunakan pengindeksan, ada keuntungan tambahan dari operasi lain seperti pengurutan, sampel, dan batas. Misalnya, jika saya mendesain skema saya sebagai {f:1, m:1} saya dapat melakukan operasi tambahan selain find as

db.collection.find( {f: 1} ).sort( {m: 1} )

Membaca data dari RAM lebih efisien daripada membaca data yang sama dari disk. Untuk alasan ini, selalu disarankan untuk memastikan bahwa indeks Anda sepenuhnya sesuai dengan RAM. Untuk mendapatkan indexSize koleksi Anda saat ini, jalankan perintah :

db.collection.totalIndexSize()

Anda akan mendapatkan nilai seperti 36864 byte. Nilai ini juga tidak boleh mengambil persentase besar dari ukuran RAM keseluruhan, karena Anda harus memenuhi kebutuhan seluruh rangkaian kerja server.

Permintaan yang efisien juga harus meningkatkan Selektivitas. Selektivitas dapat didefinisikan sebagai kemampuan kueri untuk mempersempit hasil menggunakan indeks. Agar lebih memotong, kueri Anda harus membatasi jumlah kemungkinan dokumen dengan bidang yang diindeks. Selektivitas sebagian besar terkait dengan indeks majemuk yang mencakup bidang selektivitas rendah dan bidang lain. Misalnya jika Anda memiliki data ini:

{ _id: ObjectId(), a: 6, b: "no", c: 45 }
{ _id: ObjectId(), a: 7, b: "gh", c: 28 }
{ _id: ObjectId(), a: 7, b: "cd", c: 58 }
{ _id: ObjectId(), a: 8, b: "kt", c: 33 }

Kueri {a:7, b:“cd”} akan memindai melalui 2 dokumen untuk mengembalikan 1 dokumen yang cocok. Namun jika data untuk nilai a terdistribusi secara merata yaitu

{ _id: ObjectId(), a: 6, b: "no", c: 45 }
{ _id: ObjectId(), a: 7, b: "gh", c: 28 }
{ _id: ObjectId(), a: 8, b: "cd", c: 58 }
{ _id: ObjectId(), a: 9, b: "kt", c: 33 }

Kueri {a:7, b:“cd”} akan memindai 1 dokumen dan mengembalikan dokumen ini. Oleh karena itu, ini akan memakan waktu lebih singkat daripada struktur data pertama.

ClusterControlSingle Console untuk Seluruh Infrastruktur Basis Data AndaCari tahu apa lagi yang baru di ClusterControlInstall ClusterControl GRATIS

Penyediaan Sumber Daya

Memori penyimpanan yang tidak memadai, RAM, dan parameter operasi lainnya dapat secara drastis menurunkan kinerja MongoDB. Misalnya, jika jumlah koneksi pengguna sangat besar, itu akan menghambat kemampuan aplikasi server untuk menangani permintaan secara tepat waktu. Seperti yang dibahas dalam Hal-hal penting untuk dipantau di MongoDB, Anda bisa mendapatkan gambaran umum tentang sumber daya terbatas yang Anda miliki dan bagaimana Anda dapat menskalakannya agar sesuai dengan spesifikasi Anda. Untuk sejumlah besar permintaan aplikasi secara bersamaan, sistem database akan kewalahan untuk memenuhi permintaan.

Keterlambatan Replikasi

Terkadang Anda mungkin melihat beberapa data hilang dari database Anda atau ketika Anda menghapus sesuatu, data itu muncul lagi. Sebanyak yang Anda bisa memiliki skema yang dirancang dengan baik, pengindeksan yang sesuai dan sumber daya yang cukup, pada awalnya aplikasi Anda akan berjalan dengan lancar tanpa cegukan, tetapi kemudian pada titik tertentu Anda melihat masalah yang disebutkan terakhir. MongoDB bergantung pada konsep replikasi di mana data disalin secara berlebihan untuk memenuhi beberapa kriteria desain. Asumsi dengan ini adalah bahwa prosesnya seketika. Namun, beberapa penundaan dapat terjadi mungkin karena kegagalan jaringan atau kesalahan yang tidak ditangani. Singkatnya, akan ada kesenjangan besar antara waktu pemrosesan operasi pada node utama dan waktu akan diterapkan pada node sekunder.

Kemunduran dengan Replica Lag

  1. Data tidak konsisten. Ini terutama terkait dengan operasi baca yang didistribusikan di seluruh sekunder.

  2. Jika kesenjangan lag cukup lebar, maka banyak data yang tidak direplikasi mungkin berada di node utama dan perlu direkonsiliasi di node sekunder. Pada titik tertentu, ini mungkin tidak mungkin, terutama ketika node utama tidak dapat dipulihkan.

  3. Kegagalan untuk memulihkan node utama dapat memaksa seseorang untuk menjalankan node dengan data yang tidak mutakhir dan akibatnya dapat menghapus seluruh database untuk membuat node utama pulih.

Penyebab Kegagalan Node Sekunder

  1. Mengalahkan kekuatan primer di atas sekunder terkait spesifikasi CPU, IOPS disk, dan I/O jaringan.

  2. Operasi penulisan yang kompleks. Misalnya perintah seperti

    db.collection.update( { a: 7}  , {$set: {m: 4} }, {multi: true} )

    Node utama akan merekam operasi ini dalam oplog dengan cukup cepat. Namun, untuk node sekunder, ia harus mengambil operasi tersebut, membaca ke dalam RAM halaman indeks dan data apa pun untuk memenuhi beberapa spesifikasi kriteria seperti id. Karena ia harus melakukan ini cukup cepat untuk menjaga laju dengan node utama melakukan operasi, jika jumlah ops cukup besar maka akan ada lag yang diharapkan.

  3. Mengunci sekunder saat membuat cadangan. Dalam hal ini kita mungkin lupa untuk menonaktifkan yang utama maka akan melanjutkan operasinya seperti biasa. Pada saat kunci akan dilepaskan, jeda replikasi akan memiliki celah yang besar terutama ketika berhadapan dengan cadangan data dalam jumlah besar.

  4. Bangunan indeks. Jika indeks menumpuk di node sekunder, maka semua operasi lain yang terkait dengannya diblokir. Jika indeks berjalan lama maka cegukan lag replikasi akan ditemui.

  5. Sekunder tidak terhubung. Terkadang node sekunder mungkin gagal karena pemutusan jaringan dan ini mengakibatkan jeda replikasi saat terhubung kembali.

Cara Meminimalkan Jeda Replikasi

  • Gunakan indeks unik selain koleksi Anda yang memiliki bidang _id. Ini untuk menghindari proses replikasi gagal total.

  • Pertimbangkan jenis pencadangan lain seperti snapshot point-in-time dan sistem file yang tidak perlu dikunci.

  • Hindari membangun indeks besar karena menyebabkan operasi pemblokiran latar belakang.

  • Buat yang sekunder cukup kuat. Jika operasi tulis ringan, maka penggunaan sekunder yang kurang bertenaga akan ekonomis. Namun, untuk beban tulis yang berat, simpul sekunder mungkin tertinggal di belakang primer. Agar lebih terpotong, sekunder harus memiliki bandwidth yang cukup untuk membantu membaca oplog dengan cukup cepat untuk menjaga kecepatannya dengan node utama.

Teknik Kueri yang Efisien

Selain membuat kueri yang diindeks dan menggunakan Selektivitas Kueri seperti yang dibahas di atas, ada konsep lain yang dapat Anda terapkan untuk mempercepat dan membuat kueri Anda efektif.

Mengoptimalkan Kueri Anda

  1. Menggunakan kueri tertutup. Kueri tertutup adalah kueri yang selalu dipenuhi oleh indeks sehingga tidak perlu memeriksa dokumen apa pun. Oleh karena itu, kueri yang dicakup harus memiliki semua bidang sebagai bagian dari indeks dan akibatnya hasilnya harus berisi semua bidang ini.

    Mari kita perhatikan contoh ini:

    {_id: 1, product: { price: 50 }

    Jika kita membuat indeks untuk koleksi ini sebagai

    {“product.price”: 1} 

    Mempertimbangkan operasi pencarian, maka indeks ini akan mencakup kueri ini;

    db.collection.find( {“product.price”: 50}, {“product.price”: 1, _id: 0}  )

    dan kembalikan bidang dan nilai product.price saja.

  2. Untuk dokumen yang disematkan, gunakan notasi titik (.). Notasi titik membantu dalam mengakses elemen larik dan bidang dokumen yang disematkan.

    Mengakses larik:

    {
       prices: [12, 40, 100, 50, 40]  
    }

    Untuk menentukan elemen keempat misalnya, Anda dapat menulis perintah ini:

    “prices.3”

    Mengakses larik objek:

    {
    
       vehicles: [{name: toyota, quantity: 50},
                 {name: bmw, quantity: 100},
                 {name: subaru, quantity: 300}                    
    } 

    Untuk menentukan bidang nama dalam array kendaraan, Anda dapat menggunakan perintah ini

    “vehicles.name”
  3. Periksa apakah kueri tercakup. Untuk melakukan ini, gunakan db.collection.explain(). Fungsi ini akan memberikan informasi tentang pelaksanaan operasi lain -mis. db.collection.explain().aggregate(). Untuk mempelajari lebih lanjut tentang fungsi explain, Anda dapat melihat explain().

Secara umum, teknik tertinggi sejauh menyangkut kueri adalah menggunakan indeks. Meminta hanya indeks jauh lebih cepat daripada menanyakan dokumen di luar indeks. Mereka bisa muat di memori maka tersedia di RAM daripada di disk. Ini membuatnya cukup mudah dan cepat untuk mengambilnya dari memori.


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB Hubungan Satu ke Banyak

  2. Bagaimana cara mengimpor data dari mongodb ke pandas?

  3. Bagaimana cara memperbarui dokumen Mongo setelah memasukkannya?

  4. mongodb menghitung jumlah nilai yang berbeda per bidang/kunci

  5. Bisakah mongodb digunakan sebagai basis data tertanam?