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

Performa kueri MongoDB untuk lebih dari 5 juta catatan

Ini mencari jarum di tumpukan jerami. Kami membutuhkan beberapa keluaran explain() untuk kueri yang tidak berkinerja baik. Sayangnya, bahkan itu akan memperbaiki masalah hanya untuk kueri tertentu, jadi inilah strategi tentang cara mendekati ini:

  1. Pastikan bukan karena RAM yang tidak mencukupi dan paging yang berlebihan
  2. Aktifkan profiler DB (menggunakan db.setProfilingLevel(1, timeout) di mana timeout adalah ambang batas untuk jumlah milidetik yang diperlukan kueri atau perintah, apa pun yang lebih lambat akan dicatat)
  3. Periksa kueri lambat di db.system.profile dan jalankan kueri secara manual menggunakan explain()
  4. Cobalah untuk mengidentifikasi operasi yang lambat di explain() keluaran, seperti scanAndOrder atau nscanned besar , dll.
  5. Alasan tentang selektivitas kueri dan apakah mungkin untuk meningkatkan kueri menggunakan indeks sama sekali . Jika tidak, pertimbangkan untuk tidak mengizinkan setelan filter untuk pengguna akhir atau beri dia dialog peringatan bahwa operasi mungkin lambat.

Masalah utamanya adalah Anda tampaknya mengizinkan pengguna Anda untuk menggabungkan filter sesuka hati. Tanpa perpotongan indeks, itu akan meningkatkan jumlah indeks yang dibutuhkan secara drastis.

Juga, melemparkan indeks secara membabi buta pada setiap kueri yang mungkin adalah strategi yang sangat buruk. Sangat penting untuk menyusun kueri dan memastikan bidang yang diindeks memiliki selektivitas yang memadai .

Katakanlah Anda memiliki kueri untuk semua pengguna dengan status "aktif" dan beberapa kriteria lainnya. Tetapi dari 5 juta pengguna, 3 juta aktif dan 2 juta tidak, jadi lebih dari 5 juta entri hanya ada dua nilai yang berbeda. Indeks seperti itu biasanya tidak membantu. Sebaiknya cari kriteria lain dulu, baru scan hasilnya. Rata-rata, ketika mengembalikan 100 dokumen, Anda harus memindai 167 dokumen, yang tidak akan terlalu merusak kinerja. Tapi itu tidak sesederhana itu. Jika kriteria utama adalah joined_at tanggal pengguna dan kemungkinan pengguna menghentikan penggunaan dengan waktu yang tinggi, Anda mungkin harus memindai ribuan dokumen sebelum menemukan seratus kecocokan.

Jadi pengoptimalan sangat bergantung pada data (tidak hanya strukturnya , tetapi juga data itu sendiri ), korelasi internalnya dan pola kueri Anda .

Hal-hal menjadi lebih buruk ketika data terlalu besar untuk RAM, karena dengan demikian, memiliki indeks sangat bagus, tetapi memindai (atau bahkan hanya mengembalikan) hasilnya mungkin memerlukan pengambilan banyak data dari disk secara acak yang membutuhkan banyak waktu.

Cara terbaik untuk mengontrolnya adalah dengan membatasi jumlah jenis kueri yang berbeda, melarang kueri pada informasi selektivitas rendah, dan mencoba mencegah akses acak ke data lama.

Jika semuanya gagal dan jika Anda benar-benar membutuhkan banyak fleksibilitas dalam filter, mungkin bermanfaat untuk mempertimbangkan DB pencarian terpisah yang mendukung persimpangan indeks, ambil id mongo dari sana dan kemudian dapatkan hasil dari mongo menggunakan $in . Tapi itu penuh dengan bahayanya sendiri.

-- EDIT --

Penjelasan yang Anda posting adalah contoh yang bagus dari masalah dengan pemindaian bidang selektivitas rendah. Rupanya, ada banyak dokumen untuk "[email protected]". Sekarang, menemukan dokumen-dokumen itu dan mengurutkannya berdasarkan stempel waktu cukup cepat, karena didukung oleh indeks selektivitas tinggi. Sayangnya, karena hanya ada dua jenis perangkat, mongo perlu memindai 30060 dokumen untuk menemukan yang pertama cocok dengan 'seluler'.

Saya berasumsi ini semacam pelacakan web, dan pola penggunaan pengguna membuat kueri menjadi lambat (apakah ia beralih seluler dan web setiap hari, kuerinya akan cepat).

Membuat kueri khusus ini lebih cepat dapat dilakukan dengan menggunakan indeks gabungan yang berisi jenis perangkat, mis. menggunakan

a) ensureIndex({'username': 1, 'userAgent.deviceType' : 1, 'timestamp' :-1})

atau

b) ensureIndex({'userAgent.deviceType' : 1, 'username' : 1, 'timestamp' :-1})

Sayangnya, itu berarti kueri seperti find({"username" : "foo"}).sort({"timestamp" : -1}); tidak dapat menggunakan indeks yang sama lagi, jadi, seperti yang dijelaskan, jumlah indeks akan bertambah dengan sangat cepat.

Saya khawatir tidak ada solusi yang sangat baik untuk menggunakan mongodb saat ini.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB vs. DynamoDB:Apa yang perlu Anda ketahui

  2. Memulai dengan PHP dan MongoDB

  3. Cara menggabungkan beberapa koleksi dengan $lookup di mongodb

  4. 2 Cara Mendapatkan Ukuran Dokumen di MongoDB

  5. Bagaimana cara menggunakan Peta/Pengurangan di MongoDB?