Tips performa kueri untuk SDK Azure Cosmos DB
BERLAKU UNTUK:
SQL API
Azure Cosmos DB adalah database terdistribusi yang cepat dan fleksibel yang menskalakan dengan mulus dengan tingkat latensi dan throughput terjamin. Anda tidak perlu membuat perubahan arsitektur besar atau menulis kode kompleks untuk menskalakan database dengan Azure Cosmos DB. Penskalaan naik dan turun semudah melakukan satu panggilan API. Untuk mempelajari lebih lanjut, lihat sediakan throughput kontainer atau sediakan throughput database.
Mengurangi panggilan Rencana Kueri
Untuk menjalankan kueri, rencana kueri perlu dibuat. Hal ini secara umum mewakili permintaan jaringan ke Gateway Azure Cosmos DB, yang menambah latensi operasi kueri. Ada dua cara untuk menghapus permintaan ini dan mengurangi latensi operasi kueri:
Menggunakan pembuatan Rencana Kueri lokal
SQL SDK mencakup ServiceInterop.dll asli untuk memilah dan mengoptimalkan kueri secara lokal. ServiceInterop.dll hanya didukung pada platform Windows x64. Jenis aplikasi berikut menggunakan pemrosesan hos 32-bit secara default. Untuk mengubah pemrosesan hos menjadi pemrosesan 64-bit, ikuti langkah-langkah ini, berdasarkan jenis aplikasi Anda:
Untuk aplikasi yang dapat dieksekusi, Anda dapat mengubah pemrosesan hos dengan mengatur target platform ke x64 di jendela Properti Proyek, pada tab Bangun.
Untuk proyek pengujian berbasis VSTest, Anda dapat mengubah pemrosesan hos dengan memilih Uji>Pengaturan Pengujian>Arsitektur Prosesor Default sebagai X64 pada menu Uji Visual Studio.
Untuk aplikasi web ASP.NET yang disebarkan secara lokal, Anda dapat mengubah pemrosesan hos dengan memilih Gunakan versi 64-bit IIS Express untuk situs web dan proyek di bawah Alat>Opsi>Proyek dan Solusi>Proyek Web.
Untuk aplikasi ASP.NET web yang disebarkan pada Azure, Anda dapat mengubah pemrosesan hos dengan memilih platform 64-bit dalam Pengaturan aplikasi di portal Azure.
Catatan
Secara default, proyek Visual Studio baru diatur ke CPU mana pun. Kami menyarankan agar Anda mengatur proyek ke x64 sehingga tidak beralih ke x86. Proyek yang diatur ke CPU mana pun dapat dengan mudah beralih ke x86 jika dependensi hanya x86 ditambahkan.
ServiceInterop.dll harus ada di folder tempat SDK DLL dijalankan. Ini sebaiknya menjadi perhatian hanya jika Anda menyalin DLL secara manual atau memiliki sistem bangun/penyebaran kustom.
Menggunakan kueri partisi tunggal
Untuk kueri yang menargetkan Kunci Partisi dengan mengatur properti PartitionKey di QueryRequestOptions dan tidak berisi agregasi (termasuk Distinct, DCount, Group By):
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Washington")}))
{
// ...
}
Catatan
Kueri lintas partisi memerlukan SDK untuk mengunjungi semua partisi yang ada untuk memeriksa hasilnya. Semakin banyak partisi fisik yang dimiliki kontainer, kontainer berpotensi menjadi semakin lambat.
Hindari membuat ulang iterator yang tidak perlu
Saat semua hasil kueri digunakan oleh komponen saat ini, Anda tidak perlu membuat ulang iterator dengan kelanjutan untuk setiap halaman. Sebaiknya hapus kueri sepenuhnya kecuali penomoran halaman dikendalikan oleh komponen panggilan lain:
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey("Washington")}))
{
while (feedIterator.HasMoreResults)
{
foreach(MyItem document in await feedIterator.ReadNextAsync())
{
// Iterate through documents
}
}
}
Mengatur derajat paralelisme
Untuk kueri, sesuaikan properti MaxConcurrency di QueryRequestOptions untuk mengidentifikasi konfigurasi terbaik untuk aplikasi Anda, terutama jika Anda melakukan kueri lintas partisi (tanpa filter pada nilai kunci partisi). MaxConcurrency mengontrol jumlah maksimum tugas paralel, yaitu, maksimum partisi yang akan dikunjungi secara paralel. Mengatur nilai ke -1 akan membuat SDK memutuskan konkurensi yang optimal.
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() {
PartitionKey = new PartitionKey("Washington"),
MaxConcurrency = -1 }))
{
// ...
}
Mari kita asumsikan bahwa
- D = Jumlah maksimum default tugas paralel (= jumlah total prosesor di mesin klien)
- P = Jumlah maksimum tugas paralel yang ditentukan pengguna
- N = Jumlah partisi yang perlu dikunjungi untuk menjawab kueri
Berikut adalah implikasi tentang bagaimana kueri paralel akan berperilaku untuk nilai P yang berbeda.
- (P == 0) => Mode Seri
- (P == 1) => Maksimum satu tugas
- (P > 1) => Min (P, N) tugas paralel
- (P < 1) => Min (N, D) tugas paralel
Menyetel ukuran halaman
Saat Anda mengeluarkan kueri SQL, hasilnya ditampilkan secara tersegmentasi jika tataan hasil terlalu besar. Secara default, hasil dikembalikan dalam gugus 100 item atau 1 MB, batas mana pun yang tercapai lebih dahulu.
Catatan
Properti MaxItemCount sebaiknya tidak digunakan untuk paginasi saja. Penggunaan utamanya adalah untuk meningkatkan kinerja kueri dengan mengurangi jumlah maksimum item yang dikembalikan dalam satu halaman.
Anda juga dapat mengatur ukuran halaman dengan menggunakan SDK Azure Cosmos DB yang tersedia. Properti MaxItemCount dalam QueryRequestOptions memungkinkan Anda mengatur jumlah maksimum item yang akan dikembalikan dalam operasi pencacahan. Ketika MaxItemCount diatur ke -1, SDK secara otomatis menemukan nilai optimal, tergantung pada ukuran dokumen. Contohnya:
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() {
PartitionKey = new PartitionKey("Washington"),
MaxItemCount = 1000}))
{
// ...
}
Saat kueri dijalankan, data yang dihasilkan dikirim dalam paket TCP. Jika Anda menentukan nilai yang terlalu rendah untuk MaxItemCount, jumlah perjalanan yang diperlukan untuk mengirim data dalam paket TCP menjadi tinggi, yang memengaruhi kinerja. Jadi, jika Anda tidak yakin nilai apa yang akan diatur untuk properti MaxItemCount, cara terbaik adalah mengaturnya ke -1 dan biarkan SDK memilih nilai default.
Menyetel ukuran buffer
Kueri paralel dirancang untuk mengambil hasil sebelumnya saat batch hasil saat ini sedang diproses oleh klien. Pra-pengambilan ini membantu meningkatkan latensi keseluruhan kueri. Properti MaxBufferedItemCount di QueryRequestOptions membatasi jumlah hasil yang diambil sebelumnya. Atur MaxBufferedItemCount ke jumlah hasil yang ingin dikembalikan (atau angka yang lebih tinggi) agar kueri menerima manfaat maksimum dari pra-pengambilan. Jika Anda menyetel nilai ini ke -1, sistem akan secara otomatis menentukan jumlah unsur yang akan disangga.
using (FeedIterator<MyItem> feedIterator = container.GetItemQueryIterator<MyItem>(
"SELECT * FROM c WHERE c.city = 'Seattle'",
requestOptions: new QueryRequestOptions() {
PartitionKey = new PartitionKey("Washington"),
MaxBufferedItemCount = -1}))
{
// ...
}
Pra-pengambilan bekerja dengan cara yang sama terlepas dari derajat paralelisme, dan ada satu buffer untuk data dari semua partisi.
Langkah berikutnya
Untuk mempelajari selengkapnya tentang performa menggunakan SDK .NET:
Mengurangi panggilan Rencana Kueri
Untuk menjalankan kueri, rencana kueri perlu dibuat. Hal ini secara umum mewakili permintaan jaringan ke Gateway Azure Cosmos DB, yang menambah latensi operasi kueri.
Menggunakan penembolokan Rencana Kueri
Rencana kueri, untuk kueri yang dicakup ke satu partisi, disimpan di klien. Hal ini menghilangkan kebutuhan untuk melakukan panggilan ke gateway untuk mengambil rencana kueri setelah panggilan pertama. Kunci untuk rencana kueri yang disimpan adalah string kueri SQL. Anda harus memastikan kueri bahwa berparameter. Jika tidak, pencarian cache rencana kueri akan sering menjadi cache yang hilang karena string kueri tidak mungkin identik di seluruh panggilan. Penembolokan rencana kueri diaktifkan secara default untuk versi SDK Java 4.20.0 dan yang lebih baru dan untuk versi SDK Spring Data Cosmos 3.13.0 dan yang lebih baru.
Menggunakan kueri partisi tunggal berparameter
Untuk kueri berparameter yang dicakup ke kunci partisi dengan setPartitionKey di CosmosQueryRequestOptions dan tidak berisi agregasi (termasuk Distinct, DCount, Group By), rencana kueri dapat dihindari:
CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
options.setPartitionKey(new PartitionKey("Washington"));
ArrayList<SqlParameter> paramList = new ArrayList<SqlParameter>();
paramList.add(new SqlParameter("@city", "Seattle"));
SqlQuerySpec querySpec = new SqlQuerySpec(
"SELECT * FROM c WHERE c.city = @city",
paramList);
// Sync API
CosmosPagedIterable<MyItem> filteredItems =
container.queryItems(querySpec, options, MyItem.class);
// Async API
CosmosPagedFlux<MyItem> filteredItems =
asyncContainer.queryItems(querySpec, options, MyItem.class);
Catatan
Kueri lintas partisi memerlukan SDK untuk mengunjungi semua partisi yang ada untuk memeriksa hasilnya. Semakin banyak partisi fisik yang dimiliki kontainer, kontainer dapat menjadi semakin lambat.
Mengatur derajat paralelisme
Kueri paralel bekerja dengan membuat kueri beberapa partisi secara paralel. Tetapi, data dari masing-masing kontainer yang dipartisi diambil secara serial sehubungan dengan kueri. Jadi, gunakan setMaxDegreeOfParallelism pada CosmosQueryRequestOptions untuk mengatur nilai ke jumlah partisi yang Anda miliki. Jika Anda tidak mengetahui jumlah partisi, Anda dapat menggunakan setMaxDegreeOfParallelism untuk menetapkan angka tinggi, dan sistem memilih minimum (jumlah partisi, input yang diberikan pengguna) sebagai derajat paralelisme maksimum. Mengatur nilai ke -1 akan membuat SDK memutuskan konkurensi yang optimal.
Perlu diingat bahwa kueri paralel menghasilkan manfaat terbaik jika data didistribusikan secara merata di semua partisi sehubungan dengan kueri. Jika kontainer berpartisi dipartisi sedemikian rupa sehingga semua atau sebagian besar data yang dikembalikan oleh kueri terkonsentrasi di beberapa partisi (dalam kasus terburuk satu partisi), maka performa kueri akan menurun.
CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
options.setPartitionKey(new PartitionKey("Washington"));
options.setMaxDegreeOfParallelism(-1);
// Define the query
// Sync API
CosmosPagedIterable<MyItem> filteredItems =
container.queryItems(querySpec, options, MyItem.class);
// Async API
CosmosPagedFlux<MyItem> filteredItems =
asyncContainer.queryItems(querySpec, options, MyItem.class);
Mari kita asumsikan bahwa
- D = Jumlah maksimum default tugas paralel (= jumlah total prosesor di mesin klien)
- P = Jumlah maksimum tugas paralel yang ditentukan pengguna
- N = Jumlah partisi yang perlu dikunjungi untuk menjawab kueri
Berikut adalah implikasi tentang bagaimana kueri paralel akan berperilaku untuk nilai P yang berbeda.
- (P == 0) => Mode Seri
- (P == 1) => Maksimum satu tugas
- (P > 1) => Min (P, N) tugas paralel
- (P == -1) => Min (N, D) tugas paralel
Menyetel ukuran halaman
Saat Anda mengeluarkan kueri SQL, hasilnya ditampilkan secara tersegmentasi jika tataan hasil terlalu besar. Secara default, hasil dikembalikan dalam gugus 100 item atau 4 MB, batas mana saja yang tercapai lebih dulu.
Anda dapat menggunakan parameter pageSize di iterableByPage() untuk API sinkronisasi dan byPage() untuk API asinkron, guna menentukan ukuran halaman:
// Sync API
Iterable<FeedResponse<MyItem>> filteredItemsAsPages =
container.queryItems(querySpec, options, MyItem.class).iterableByPage(continuationToken,pageSize);
for (FeedResponse<MyItem> page : filteredItemsAsPages) {
for (MyItem item : page.getResults()) {
//...
}
}
// Async API
Flux<FeedResponse<MyItem>> filteredItemsAsPages =
asyncContainer.queryItems(querySpec, options, MyItem.class).byPage(continuationToken,pageSize);
filteredItemsAsPages.map(page -> {
for (MyItem item : page.getResults()) {
//...
}
}).subscribe();
Menyetel ukuran buffer
Kueri paralel dirancang untuk mengambil hasil sebelumnya saat batch hasil saat ini sedang diproses oleh klien. Pengambilan sebelumnya membantu dalam peningkatan latensi kueri keseluruhan. setMaxBufferedItemCount di CosmosQueryRequestOptions membatasi jumlah hasil yang diambil sebelumnya. Mengatur setMaxBufferedItemCount ke jumlah hasil yang diharapkan yang dikembalikan (atau angka yang lebih tinggi) memungkinkan kueri menerima keuntungan maskimum dari pengambilan sebelumnya (CATATAN: Hal ini juga dapat mengakibatkan penggunaan memori yang tinggi). Jika Anda menetapkan nilai ini ke 0, sistem akan secara otomatis menentukan jumlah item untuk buffer.
CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
options.setPartitionKey(new PartitionKey("Washington"));
options.setMaxBufferedItemCount(-1);
// Define the query
// Sync API
CosmosPagedIterable<MyItem> filteredItems =
container.queryItems(querySpec, options, MyItem.class);
// Async API
CosmosPagedFlux<MyItem> filteredItems =
asyncContainer.queryItems(querySpec, options, MyItem.class);
Pra-pengambilan bekerja dengan cara yang sama terlepas dari derajat paralelisme, dan ada satu buffer untuk data dari semua partisi.
Langkah berikutnya
Untuk mempelajari selengkapnya tentang performa menggunakan SDK Java: