Kueri Lambat di MongoDB dengan kumpulan kueri agregat luas menggunakan grup

Saya mengalami masalah kinerja pada API yang saya kembangkan menggunakan NodeJS+Express+MongoDB.

Saat menjalankan agregat dengan $match pada produk tertentu, kinerjanya bagus tetapi untuk pencarian terbuka sangat lambat.

Saya ingin menjalankan grup dalam dua kolom: negara dan eksportir dan kemudian mengambil hasilnya terbatas pada 3 hasil per grup di negara.

Persyaratan: Jumlah Total eksportir unik dari setiap negara beserta 3 catatan dari setiap negara.

Saat menjalankan explain() di aggregate function saya, saya mendapatkan petunjuk penting berikut yang menandakan bahwa kueri saya lambat. Mohon koreksi saya jika saya salah.

  1. "indexFilterSet": false
  2. "winningPlan": { "stage": "COLLSCAN", "direction": "forward" },

Jalankan kueri pada 9,264,947 catatan dan waktu yang dibutuhkan sekitar 32 seconds. Saya telah mencoba menggunakan indeks gabungan serta indeks bidang tunggal tetapi tidak membantu sama sekali, karena saya merasa indeks tidak digunakan dengan $match kosong {}

Di bawah ini adalah kueri yang saya jalankan di mongoDB menggunakan driver mongoose

Model.aggregate([
  {"$match" : query},
  { $group : {_id: {country: "$Country", exporter: "$Exporter"}, id: {$first: "$_id"}, product: { $first: "$Description" }}},
  { $group : {_id: "$_id.country", data: {$push: { id: "$id", company: "$_id.exporter", product: "$product" }}, count:{$sum:1}}},
  { "$sort": { "count": -1 } },
  { 
    $project: { 
      "data": { "$slice": [ "$data", 3 ] },
      "_id": 1,
      "count": 1
    }
  },
]).allowDiskUse(true).explain()

di mana, kueri dibuat secara dinamis dan secara default kosong {} untuk penelusuran seluruh koleksi. Bidang yang diindeks adalah

  1. Indeks Gabungan: {Country: 1, Exporter: 1}

  2. Indeks Teks: {Description: "text"}

Penjelasan lengkap() tanggapan:

{
"success": "Successfull",
"status": 200,
"data": {
    "stages": [
        {
            "$cursor": {
                "query": {},
                "fields": {
                    "Country": 1,
                    "Description": 1,
                    "Exporter": 1,
                    "_id": 1
                },
                "queryPlanner": {
                    "plannerVersion": 1,
                    "namespace": "db.OpenExportData",
                    "indexFilterSet": false,
                    "parsedQuery": {},
                    "winningPlan": {
                        "stage": "COLLSCAN",
                        "direction": "forward"
                    },
                    "rejectedPlans": []
                }
            }
        },
        {
            "$group": {
                "_id": {
                    "country": "$Country",
                    "exporter": "$Exporter"
                },
                "id": {
                    "$first": "$_id"
                },
                "product": {
                    "$first": "$Description"
                }
            }
        },
        {
            "$group": {
                "_id": "$_id.country",
                "data": {
                    "$push": {
                        "id": "$id",
                        "company": "$_id.exporter",
                        "product": "$product"
                    }
                },
                "count": {
                    "$sum": {
                        "$const": 1
                    }
                }
            }
        },
        {
            "$sort": {
                "sortKey": {
                    "count": -1
                }
            }
        },
        {
            "$project": {
                "_id": true,
                "count": true,
                "data": {
                    "$slice": [
                        "$data",
                        {
                            "$const": 3
                        }
                    ]
                }
            }
        }
    ],
    "ok": 1
}
}

Ukuran Koleksi : 9.264.947 data & 10,2 GB

Waktu Respons : 32154 mdtk

Kueri menjadi lebih lambat seiring bertambahnya ukuran koleksi saya.


person Abhay Verma    schedule 10.01.2019    source sumber


Jawaban (2)


Jika kueri Anda adalah {}, mesin mongo melewati tahap $match dan langsung masuk ke $group. Tidak ada indeks yang akan digunakan. Anda dapat memverifikasi di atas dari explain() hasil. Operator saluran pipa $match dan $sort dapat memanfaatkan indeks ketika indeks tersebut muncul di awal saluran pipa. Melihat saluran Anda, Anda mengelompokkannya menggunakan Negara dan Eksportir. Yang dapat Anda lakukan adalah membuat indeks pada {Country: 1, Exporter: 1}, dan menggunakan $sort pada {Country: 1, Exporter: 1} sebagai tahap pertama dari pipeline. Ini akan membuat $group lebih efisien.

person simagix    schedule 13.01.2019
comment
Ya, itu masuk akal. Namun, penyortiran juga tidak membantu jika negara dan eksportir saya diindeks. Ternyata hal ini tidak dapat dihindari saat ini dan kami tidak akan menyediakan fitur ini kepada pengguna akhir di mana mereka dapat melihat ringkasan keseluruhan catatan karena koleksinya akan sangat banyak. Terima kasih atas semua informasinya kawan! Bersulang! - person Abhay Verma; 22.01.2019

Menggunakan agregat seperti ini berarti mongodb harus menelusuri semua record, lalu mengelompokkan data (memuat 10 Gb), lalu mengiris array yang akan dibuat.

Tentu saja, semakin banyak koleksi Anda bertambah, semakin panjang pula koleksinya.


Menurut saya, alih-alih mengoptimalkan permintaan Anda yang sebenarnya, ada baiknya mempertimbangkan kembali pendekatan Anda terhadap permintaan tersebut.


Pertama-tama saya akan find setiap nama negara menggunakan satu permintaan. Kemudian gunakan satu permintaan untuk setiap negara untuk mendapatkan 3 eksportir pertama.

Menggunakan indeks pada negara dan eksportir.

Permintaannya lebih banyak, tetapi permintaannya jauh lebih kecil, yang tidak perlu memuat semua data. Dengan akses langsung ke data menggunakan indeks yang tepat.

Dan mengingat tidak ada ribuan negara berbeda di luar sana

person Orelsanpls    schedule 10.01.2019
comment
Salah satu persyaratan inti di sini adalah menemukan ringkasan eksportir unik di setiap negara, dan menurut saya, menjalankan grup berdasarkan negara dan eksportir akan menjadi hal yang wajib. Tolong beri tahu saya jika ada cara lain untuk melakukan itu. Terima kasih! - person Abhay Verma; 10.01.2019
comment
Apakah ini cara mereka memanfaatkan indeks yang ditentukan pada bidang ini dengan agregat group? - person Abhay Verma; 10.01.2019