Menyelaraskan performa kueri dengan Azure Cosmos DB

BERLAKU UNTUK: NoSQL

Azure Cosmos DB menyediakan API untuk NoSQL untuk mengkueri data, tanpa memerlukan skema atau indeks sekunder. Artikel ini menyediakan informasi berikut ini untuk pengembang:

  • Detail tingkat tinggi tentang cara kerja eksekusi kueri SQL Azure Cosmos DB
  • Tips dan praktik terbaik untuk performa kueri
  • Contoh cara menggunakan metrik eksekusi kueri SQL untuk men-debug performa kueri

Tentang eksekusi kueri SQL

Dalam data Azure Cosmos DB disimpan dalam kontainer, yang dapat tumbuh ke ukuran penyimpanan atau throughput permintaan apa pun. Azure Cosmos DB menskalakan data dengan mulus di seluruh partisi fisik di bawah penutup untuk menangani pertumbuhan data atau peningkatan throughput yang disediakan. Anda dapat mengeluarkan kueri SQL ke kontainer apa pun menggunakan REST API atau salah satu SQL SDK yang didukung.

Ikhtisar singkat pemartisian: Anda mendefinisikan kunci partisi seperti "kota", yang menentukan bagaimana data dibagi di seluruh partisi fisik. Data milik kunci partisi tunggal (misalnya, "kota" == "Seattle") disimpan dalam partisi fisik, dan satu partisi fisik dapat menyimpan data dari beberapa kunci partisi. Ketika partisi mencapai batas penyimpanannya, layanan dengan mulus membagi partisi menjadi dua partisi baru. Data didistribusikan secara merata di seluruh partisi baru, menyimpan semua data untuk satu kunci partisi bersama-sama. Karena partisi bersifat sementara, API menggunakan abstraksi rentang kunci partisi, yang menunjukkan rentang hash kunci partisi.

Saat Anda mengeluarkan kueri ke Azure Cosmos DB, SDK melakukan langkah-langkah logis ini:

  • Memilah kueri SQL untuk menentukan rencana eksekusi kueri.
  • Jika kueri menyertakan filter terhadap kunci partisi, seperti SELECT * FROM c WHERE c.city = "Seattle", kueri akan dirutekan ke satu partisi. Jika kueri tidak memiliki filter pada kunci partisi, maka kueri dijalankan di semua partisi dan hasil dari setiap partisi digabungkan dengan sisi klien.
  • Kueri dijalankan dalam setiap partisi secara seri atau paralel, sesuai dengan konfigurasi klien. Dalam setiap partisi, kueri mungkin membuat satu atau lebih perjalanan pulang pergi tergantung pada kompleksitas kueri, ukuran halaman yang dikonfigurasi, dan throughput yang tersedia dari kumpulan. Setiap eksekusi mengembalikan jumlah unit permintaan yang digunakan oleh eksekusi kueri dan statistik eksekusi kueri.
  • SDK melakukan ringkasan hasil kueri di seluruh partisi. Misalnya, jika kueri melibatkan ORDER BY di seluruh partisi, hasil dari partisi individual digabungkan dan diurutkan untuk mengembalikan hasil dalam urutan yang diurutkan secara global. Jika kueri adalah agregasi seperti COUNT, perhitungan partisi individual dijumlahkan untuk menghasilkan total keseluruhan.

SDK menyediakan berbagai opsi untuk eksekusi kueri. Misalnya, di .NET opsi ini tersedia di kelas QueryRequestOptions. Tabel berikut ini menjelaskan opsi ini dan bagaimana hal tersebut memengaruhi waktu eksekusi kueri.

Opsi Deskripsi
EnableScanInQuery Hanya berlaku jika pengindeksan untuk jalur filter yang diminta dinonaktifkan. Harus diatur ke true jika Anda memilih keluar dari pengindeksan dan ingin menjalankan kueri menggunakan pemindaian penuh.
MaxItemCount Jumlah maksimum item yang akan dikembalikan per perjalanan pulang pergi ke server. Anda dapat mengaturnya ke -1 untuk membiarkan server mengelola jumlah item yang akan dikembalikan.
MaxBufferedItemCount Jumlah maksimum item yang dapat di-buffer sisi klien selama eksekusi kueri paralel. Nilai properti positif membatasi jumlah item yang di-buffer ke nilai yang ditetapkan. Anda dapat mengaturnya ke kurang dari 0 untuk memungkinkan sistem secara otomatis memutuskan jumlah item ke buffer.
MaxConcurrency Mendapatkan atau mengatur jumlah operasi bersamaan yang menjalankan sisi klien selama eksekusi kueri paralel. Nilai properti positif membatasi jumlah operasi bersamaan dengan nilai yang ditetapkan. Anda dapat mengaturnya ke kurang dari 0 untuk membiarkan sistem secara otomatis memutuskan jumlah operasi bersamaan yang akan dijalankan.
PopulateIndexMetrics Memungkinkan pengumpulan metrik indeks untuk memahami bagaimana mesin kueri menggunakan indeks yang ada dan bagaimana hal itu dapat menggunakan indeks baru potensial. Opsi ini menimbulkan overhead, sehingga hanya boleh diaktifkan saat men-debug kueri lambat.
ResponseContinuationTokenLimitInKb Anda dapat membatasi ukuran maksimum token berkelanjutan yang dikembalikan oleh server. Anda mungkin perlu mengatur ini jika host aplikasi Anda memiliki batasan pada ukuran header respons, tetapi dapat meningkatkan durasi keseluruhan dan RU yang digunakan untuk kueri.

Misalnya, berikut adalah kueri pada kontainer yang dipartisi dengan /city menggunakan .NET SDK:

QueryDefinition query = new QueryDefinition("SELECT * FROM c WHERE c.city = 'Seattle'");
QueryRequestOptions options = new QueryRequestOptions()
{
    MaxItemCount = -1,
    MaxBufferedItemCount = -1,
    MaxConcurrency = -1,
    PopulateIndexMetrics = true
};
FeedIterator<dynamic> feedIterator = container.GetItemQueryIterator<dynamic>(query);

FeedResponse<dynamic> feedResponse = await feedIterator.ReadNextAsync();

Setiap eksekusi kueri sesuai dengan REST API POST dengan header yang diatur untuk opsi permintaan kueri dan kueri SQL dalam isi. Untuk detail tentang header dan opsi permintaan REST API, lihat Mengkueri sumber daya menggunakan REST API.

Praktik terbaik untuk performa kueri

Faktor-faktor berikut biasanya memiliki efek terbesar pada performa kueri Azure Cosmos DB. Kami menggali lebih dalam ke masing-masing faktor ini dalam artikel ini.

Kecil Tip
Throughput yang disediakan Ukur RU per kueri, dan pastikan Anda memiliki throughput tersedia yang diperlukan untuk kueri Anda.
Kunci partisi dan pemartisian Izinkan kueri dengan nilai kunci partisi dalam klausul filter untuk latensi rendah.
Opsi SDK dan kueri Ikuti praktik terbaik SDK seperti konektivitas langsung, dan sesuaikan opsi eksekusi kueri pihak klien.
Latensi jaringan Jalankan aplikasi Anda di wilayah yang sama dengan akun Azure Cosmos DB Anda sedapat mungkin untuk mengurangi latensi.
Kebijakan pengindeksan Pastikan Anda memiliki jalur/kebijakan pengindeksan yang diperlukan untuk kueri.
Metrik eksekusi kueri Menganalisis metrik eksekusi kueri untuk mengidentifikasi potensi regenerasi bentuk kueri dan data.

Throughput yang disediakan

Di Azure Cosmos DB, Anda membuat kontainer data, masing-masing dengan throughput khusus yang dinyatakan dalam unit permintaan (RU) per detik. Baca dokumen 1 KB adalah satu RU, dan setiap operasi (termasuk kueri) dinormalisasi ke sejumlah RU tetap berdasarkan kompleksitasnya. Misalnya, jika Anda memiliki 1000 RU/s yang disediakan untuk kontainer Anda, dan Anda memiliki kueri seperti SELECT * FROM c WHERE c.city = 'Seattle' yang menggunakan 5 RU, maka Anda dapat menjalankan (1000 RU/dtk) / (5 RU/kueri) = 200 kueri ini per detik.

Jika Anda mengirimkan lebih dari 200 kueri/detik (atau beberapa operasi lain yang menjenuhkan semua RU yang disediakan), layanan memulai permintaan masuk pembatasan tarif. SDK secara otomatis menangani pembatasan laju dengan melakukan backoff/coba lagi, oleh karena itu Anda mungkin melihat latensi yang lebih tinggi untuk kueri ini. Meningkatkan throughput yang disediakan ke nilai yang diperlukan akan meningkatkan latensi dan throughput kueri Anda.

Untuk mempelajari selengkapnya tentang unit permintaan, lihat Unit permintaan.

Kunci partisi dan pemartisian

Dengan Azure Cosmos DB, skenario berikut untuk membaca data diurutkan dari apa yang biasanya tercepat/paling efisien hingga yang paling lambat/paling tidak efisien.

  • GET pada kunci partisi tunggal dan id item, juga dikenal sebagai titik baca
  • Kueri dengan klausul filter pada satu kunci partisi
  • Kueri dengan klausa filter kesetaraan atau rentang pada properti apa pun
  • Kueri tanpa filter

Kueri yang perlu dijalankan pada semua partisi memiliki latensi yang lebih tinggi, dan dapat menggunakan RU yang lebih tinggi. Karena setiap partisi memiliki pengindeksan otomatis terhadap semua properti, kueri dapat disajikan secara efisien dari indeks dalam kasus ini. Anda dapat membuat kueri yang mencakup partisi lebih cepat menggunakan opsi paralelisme.

Untuk mempelajari lebih lanjut tentang partisi dan kunci partisi, lihat Pemartisian di Azure Cosmos DB.

Opsi SDK dan kueri

Lihat tips performa kueri dan pengujian performa untuk cara mendapatkan performa sisi klien terbaik dari Azure Cosmos DB menggunakan SDK kami.

Latensi jaringan

Lihat Distribusi global Azure Cosmos DB untuk cara menyiapkan distribusi global dan menyambungkan ke wilayah terdekat. Latensi jaringan memiliki efek signifikan pada performa kueri saat Anda perlu melakukan beberapa perjalanan pulang pergi atau mengambil kumpulan hasil besar dari kueri.

Anda dapat menggunakan metrik eksekusi kueri untuk mengambil waktu eksekusi server kueri, memungkinkan Anda membedakan waktu yang dihabiskan dalam eksekusi kueri dari waktu yang dihabiskan dalam transit jaringan.

Kebijakan pengindeksan

Lihat mengonfigurasi kebijakan pengindeksan untuk mengindeks jalur, jenis, dan mode, dan bagaimana dampaknya terhadap eksekusi kueri. Secara default, Azure Cosmos DB menerapkan pengindeksan otomatis ke semua data dan menggunakan indeks rentang untuk string dan angka, yang efektif untuk kueri kesetaraan. Untuk skenario sisipan performa tinggi, pertimbangkan untuk mengecualikan jalur untuk mengurangi biaya RU untuk setiap operasi penyisipan.

Anda dapat menggunakan metrik indeks untuk mengidentifikasi indeks mana yang digunakan untuk setiap kueri dan jika ada indeks yang hilang yang akan meningkatkan performa kueri.

Metrik eksekusi kueri

Metrik terperinci dikembalikan untuk setiap eksekusi kueri dalam Diagnostik untuk permintaan tersebut. Metrik ini menjelaskan di mana waktu dihabiskan selama eksekusi kueri dan mengaktifkan pemecahan masalah tingkat lanjut.

Pelajari selengkapnya tentang mendapatkan metrik kueri.

Metric Unit Deskripsi
TotalTime milliseconds Total waktu eksekusi kueri
DocumentLoadTime milliseconds Waktu yang dihabiskan untuk memuat dokumen
DocumentWriteTime milliseconds Waktu yang dihabiskan untuk menulis dan membuat serial dokumen output
IndexLookupTime milliseconds Waktu yang dihabiskan dalam lapisan indeks fisik
QueryPreparationTime milliseconds Waktu yang dihabiskan dalam menyiapkan kueri
RuntimeExecutionTime milliseconds Total waktu eksekusi runtime kueri
VMExecutionTime milliseconds Waktu yang dihabiskan dalam runtime kueri yang menjalankan kueri
OutputDocumentCount jumlah Jumlah dokumen output dalam tataan hasil
OutputDocumentSize jumlah Ukuran total dokumen yang dihasilkan dalam byte
RetrievedDocumentCount jumlah Jumlah total dokumen yang diambil
RetrievedDocumentSize byte Ukuran total dokumen yang diambil dalam format byte
IndexHitRatio rasio [0,1] Rasio jumlah dokumen yang cocok dengan filter dengan jumlah dokumen yang dimuat

SDK klien dapat secara internal membuat beberapa permintaan kueri untuk melayani kueri dalam setiap partisi. Klien melakukan lebih dari satu panggilan per partisi jika hasil total melebihi opsi permintaan jumlah item maksimum, jika kueri melebihi throughput yang disediakan untuk partisi, jika payload kueri mencapai ukuran maksimum per halaman, atau jika kueri mencapai batas waktu habis yang dialokasikan sistem. Setiap eksekusi kueri parsial mengembalikan metrik kueri untuk halaman tersebut.

Berikut adalah beberapa contoh kueri dan cara menginterpretasikan beberapa metrik yang dikembalikan dari eksekusi kueri:

Kueri Metrik Contoh Deskripsi
SELECT TOP 100 * FROM c "RetrievedDocumentCount": 101 Jumlah dokumen yang diambil adalah 100+1 untuk mencocokkan klausul TOP. Waktu kueri sebagian besar dihabiskan dan WriteOutputTimeDocumentLoadTime karena ini adalah pemindaian.
SELECT TOP 500 * FROM c "RetrievedDocumentCount": 501 RetrievedDocumentCount sekarang lebih tinggi (500+1 untuk mencocokkan klausul TOP).
SELECT * FROM c WHERE c.N = 55 "IndexLookupTime": "00:00:00.0009500" Sekitar 0,9 ms dihabiskan di IndexLookupTime untuk pencarian kunci, karena ini adalah pencarian indeks di /N/?.
SELECT * FROM c WHERE c.N > 55 "IndexLookupTime": "00:00:00.0017700" Sedikit lebih banyak waktu (1,7 ms) dihabiskan di IndexLookupTime selama pemindaian rentang, karena ini adalah pencarian indeks di /N/?.
SELECT TOP 500 c.N FROM c "IndexLookupTime": "00:00:00.0017700" Waktu yang sama dihabiskan DocumentLoadTime seperti kueri sebelumnya, tetapi lebih rendah DocumentWriteTime karena hanya satu properti yang diproyeksikan.
SELECT TOP 500 udf.toPercent(c.N) FROM c "RuntimeExecutionTime": "00:00:00.2136500" Sekitar 213 ms dihabiskan RuntimeExecutionTime dalam mengeksekusi UDF pada setiap nilai c.N.
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(c.Name, 'Den') "IndexLookupTime": "00:00:00.0006400", "RuntimeExecutionTime": "00:00:00.0074100" Sekitar 0,6 ms dihabiskan di IndexLookupTime pada /Name/?. Sebagian besar waktu eksekusi kueri (–7 ms) di RuntimeExecutionTime.
SELECT TOP 500 c.Name FROM c WHERE STARTSWITH(LOWER(c.Name), 'den') "IndexLookupTime": "00:00:00", "RetrievedDocumentCount": 2491, "OutputDocumentCount": 500 Kueri difungsikan sebagai pemindaian karena menggunakan LOWER, dan 500 dari 2491 dokumen yang diambil dikembalikan.

Langkah berikutnya

  • Untuk mempelajari tentang operator dan kata kunci kueri SQL yang didukung, lihat kueri SQL.
  • Untuk mempelajari tentang unit permintaan, lihat Unit permintaan.
  • Untuk mempelajari tentang kebijakan pengindeksan, lihat kebijakan pengindeksan