Azure Cosmos DB for MongoDB kullanırken karşılaşılan sorgu sorunlarını giderin

ŞUNLAR IÇIN GEÇERLIDIR: MongoDB

Bu makalede, Azure Cosmos DB'de sorgu sorunlarını gidermek için önerilen genel bir yaklaşım açıklanmaktadır. Bu makalede açıklanan adımları olası sorgu sorunlarına karşı eksiksiz bir savunma olarak değerlendirmemeniz gerekir ancak en yaygın performans ipuçlarını buraya dahil ettik. MongoDB için Azure Cosmos DB API'sinde yavaş veya pahalı sorguların sorunlarını gidermek için bu makaleyi başlangıç noktası olarak kullanmalısınız. NoSQL için Azure Cosmos DB kullanıyorsanız NoSQL için API sorgu sorun giderme kılavuzu makalesine bakın.

Azure Cosmos DB'deki sorgu iyileştirmeleri aşağıda gösterildiği gibi geniş bir kategoriye ayrılır:

  • Sorgunun İstek Birimi (RU) ücretini azaltan iyileştirmeler
  • Yalnızca gecikme süresini azaltan iyileştirmeler

Sorgunun RU ücretini azaltırsanız genellikle gecikme süresini de azaltırsınız.

Bu makalede, beslenme veri kümesini kullanarak yeniden oluşturabileceğiniz örnekler sağlanmaktadır.

Not

Bu makalede, Azure Cosmos DB'nin 3.6 ve üzeri sürüme sahip MongoDB hesapları için API'sini kullandığınız varsayılır. Sürüm 3.2'de kötü performans gösteren bazı sorguların 3.6+ sürümlerinde önemli geliştirmeler vardır. Destek isteği göndererek sürüm 3.6'ya yükseltin.

Ölçümleri almak için $explain komutunu kullanma

Azure Cosmos DB'de bir sorguyu iyileştirdiğinizde ilk adım her zaman sorgunuzun RU ücretini almaktır. Kabaca bir kılavuz olarak, ücretleri 50 RU'dan fazla olan sorgular için RU ücretini düşürmenin yollarını araştırmalısınız.

RU ücretini almanın yanı sıra, sorgu ve dizin kullanım ölçümlerini almak için $explain komutunu kullanmalısınız. Sorguyu çalıştıran ve sorgu ve dizin kullanım ölçümlerini göstermek için komutunu kullanan $explain bir örnek aşağıda verilmiştir:

$explain komutu:

db.coll.find({foodGroup: "Baby Foods"}).explain({"executionStatistics": true })

Çıkış:

{
    "stages" : [ 
        {
            "stage" : "$query",
            "timeInclusiveMS" : 905.2888,
            "timeExclusiveMS" : 905.2888,
            "in" : 362,
            "out" : 362,
            "details" : {
                "database" : "db-test",
                "collection" : "collection-test",
                "query" : {
                    "foodGroup" : {
                        "$eq" : "Baby Foods"
                    }
                },
                "pathsIndexed" : [],
                "pathsNotIndexed" : [ 
                    "foodGroup"
                ],
                "shardInformation" : [ 
                    {
                        "activityId" : "e68e6bdd-5e89-4ec5-b053-3dbbc2428140",
                        "shardKeyRangeId" : "0",
                        "durationMS" : 788.5867,
                        "preemptions" : 1,
                        "outputDocumentCount" : 362,
                        "retrievedDocumentCount" : 8618
                    }
                ],
                "queryMetrics" : {
                    "retrievedDocumentCount" : 8618,
                    "retrievedDocumentSizeBytes" : 104963042,
                    "outputDocumentCount" : 362,
                    "outputDocumentSizeBytes" : 2553535,
                    "indexHitRatio" : 0.0016802042237178,
                    "totalQueryExecutionTimeMS" : 777.72,
                    "queryPreparationTimes" : {
                        "queryCompilationTimeMS" : 0.19,
                        "logicalPlanBuildTimeMS" : 0.14,
                        "physicalPlanBuildTimeMS" : 0.09,
                        "queryOptimizationTimeMS" : 0.03
                    },
                    "indexLookupTimeMS" : 0,
                    "documentLoadTimeMS" : 687.22,
                    "vmExecutionTimeMS" : 774.09,
                    "runtimeExecutionTimes" : {
                        "queryEngineExecutionTimeMS" : 37.45,
                        "systemFunctionExecutionTimeMS" : 10.82,
                        "userDefinedFunctionExecutionTimeMS" : 0
                    },
                    "documentWriteTimeMS" : 49.42
                }
            }
        }
    ],
    "estimatedDelayFromRateLimitingInMilliseconds" : 0.0,
    "continuation" : {
        "hasMore" : false
    },
    "ok" : 1.0
}

$explain Komut çıktısı uzundur ve sorgu yürütme hakkında ayrıntılı bilgilere sahiptir. Ancak genel olarak, sorgu performansını iyileştirirken odaklanmanız gereken birkaç bölüm vardır:

Metrik Sistem Açıklama
timeInclusiveMS Arka uç sorgusu gecikme süresi
pathsIndexed Sorgunun kullandığı dizinleri gösterir
pathsNotIndexed Varsa, sorgunun kullanabileceği dizinleri gösterir
shardInformation Belirli bir fiziksel bölüm için sorgu performansının özeti
retrievedDocumentCount Sorgu altyapısı tarafından yüklenen belge sayısı
outputDocumentCount Sorgu sonuçlarında döndürülen belge sayısı
estimatedDelayFromRateLimitingInMilliseconds Hız sınırlaması nedeniyle tahmini ek sorgu gecikme süresi

Sorgu ölçümlerini aldıktan sonra sorgunuzun ile outputDocumentCount karşılaştırınretrievedDocumentCount. Bu makalede gözden geçirecek ilgili bölümleri belirlemek için bu karşılaştırmayı kullanın. retrievedDocumentCount, sorgu altyapısının yüklemesi gereken belge sayısıdır. outputDocumentCount, sorgunun sonuçları için gereken belge sayısıdır. retrievedDocumentCount değeri değerinden outputDocumentCountönemli ölçüde yüksekse, sorgunuzun dizin kullanamayan ve tarama yapması gereken en az bir bölümü vardır.

Senaryonuza yönelik ilgili sorgu iyileştirmelerini anlamak için aşağıdaki bölümlere bakın.

Sorguya ait RU ücreti çok yüksek

Alınan Belge Sayısı, Çıktı Belge Sayısından oldukça fazla

Alınan Belge Sayısı, Çıktı Belge Sayısı'na yaklaşık olarak eşittir

Sorguya ait RU ücreti kabul edilebilir ancak gecikme süresi yine de çok yüksek

Alınan belge sayısının çıkış belgesi sayısını aştığı sorgular

retrievedDocumentCount, sorgu altyapısının yüklenmesi gereken belge sayısıdır. outputDocumentCount, sorgu tarafından döndürülen belge sayısıdır. retrievedDocumentCount değeri değerinden outputDocumentCountönemli ölçüde yüksekse, sorgunuzun dizin kullanamayan ve tarama yapması gereken en az bir bölümü vardır.

Aşağıda, dizin tarafından tam olarak sunulmamış bir tarama sorgusu örneği verilmiştir:

$explain komutu:

db.coll.find(
  {
    $and : [
            { "foodGroup" : "Cereal Grains and Pasta"}, 
            { "description" : "Oat bran, cooked"}
        ]
  }
).explain({"executionStatistics": true })

Çıkış:

{
    "stages" : [ 
        {
            "stage" : "$query",
            "timeInclusiveMS" : 436.5716,
            "timeExclusiveMS" : 436.5716,
            "in" : 1,
            "out" : 1,
            "details" : {
                "database" : "db-test",
                "collection" : "indexing-test",
                "query" : {
                    "$and" : [ 
                        {
                            "foodGroup" : {
                                "$eq" : "Cereal Grains and Pasta"
                            }
                        }, 
                        {
                            "description" : {
                                "$eq" : "Oat bran, cooked"
                            }
                        }
                    ]
                },
                "pathsIndexed" : [],
                "pathsNotIndexed" : [ 
                    "foodGroup", 
                    "description"
                ],
                "shardInformation" : [ 
                    {
                        "activityId" : "13a5977e-a10a-4329-b68e-87e4f0081cac",
                        "shardKeyRangeId" : "0",
                        "durationMS" : 435.4867,
                        "preemptions" : 1,
                        "outputDocumentCount" : 1,
                        "retrievedDocumentCount" : 8618
                    }
                ],
                "queryMetrics" : {
                    "retrievedDocumentCount" : 8618,
                    "retrievedDocumentSizeBytes" : 104963042,
                    "outputDocumentCount" : 1,
                    "outputDocumentSizeBytes" : 6064,
                    "indexHitRatio" : 0.0,
                    "totalQueryExecutionTimeMS" : 433.64,
                    "queryPreparationTimes" : {
                        "queryCompilationTimeMS" : 0.12,
                        "logicalPlanBuildTimeMS" : 0.09,
                        "physicalPlanBuildTimeMS" : 0.1,
                        "queryOptimizationTimeMS" : 0.02
                    },
                    "indexLookupTimeMS" : 0,
                    "documentLoadTimeMS" : 387.44,
                    "vmExecutionTimeMS" : 432.93,
                    "runtimeExecutionTimes" : {
                        "queryEngineExecutionTimeMS" : 45.36,
                        "systemFunctionExecutionTimeMS" : 16.86,
                        "userDefinedFunctionExecutionTimeMS" : 0
                    },
                    "documentWriteTimeMS" : 0.13
                }
            }
        }
    ],
    "estimatedDelayFromRateLimitingInMilliseconds" : 0.0,
    "continuation" : {
        "hasMore" : false
    },
    "ok" : 1.0
}

retrievedDocumentCount (8618), (1) değerinden outputDocumentCount önemli ölçüde daha yüksektir ve bu da bu sorgunun belge taraması gerektirdiğini gösterir.

Gerekli dizinleri ekle

Diziyi pathsNotIndexed denetlemeli ve bu dizinleri eklemelisiniz. Bu örnekte ve yolları foodGroupdescription dizine alınmalıdır.

"pathsNotIndexed" : [ 
                    "foodGroup", 
                    "description"
                ]

Azure Cosmos DB'nin MongoDB API'sindeki en iyi dizin oluşturma yöntemleri MongoDB'den farklıdır. MongoDB için Azure Cosmos DB API'sinde bileşik dizinler yalnızca birden çok özelliğe göre verimli bir şekilde sıralaması gereken sorgularda kullanılır. Birden çok özellik üzerinde filtre içeren sorgularınız varsa, bu özelliklerin her biri için tek alan dizinleri oluşturmanız gerekir. Sorgu önkoşulları birden çok tek alan dizini kullanabilir.

Joker karakter dizinleri dizin oluşturmayı basitleştirebilir. MongoDB'den farklı olarak, joker dizinler sorgu koşullarında birden çok alanı destekleyebilir. Her özellik için ayrı bir dizin oluşturmak yerine tek bir joker karakter dizini kullanırsanız sorgu performansında bir fark olmayacaktır. Tüm özellikler için joker karakter dizini eklemek, tüm sorgularınızı iyileştirmenin en kolay yoludur.

Yazma veya okuma kullanılabilirliğini etkilemeden istediğiniz zaman yeni dizinler ekleyebilirsiniz. Dizin dönüştürme ilerleme durumunu izleyebilirsiniz.

Hangi toplama işlemlerinin dizini kullandığını anlama

Çoğu durumda, MongoDB için Azure Cosmos DB API'sindeki toplama işlemleri kısmen dizinleri kullanır. Genellikle sorgu altyapısı önce eşitlik ve aralık filtreleri uygular ve dizinleri kullanır. Bu filtreleri uyguladıktan sonra sorgu altyapısı ek filtreleri değerlendirebilir ve gerekirse toplama işlemini hesaplamak için kalan belgeleri yüklemeye başvurabilir.

Bir örnek aşağıda verilmiştir:

db.coll.aggregate( [
   { $match: { foodGroup: 'Fruits and Fruit Juices' } },
   {
     $group: {
        _id: "$foodGroup",
        total: { $max: "$version" }
     }
   }
] )

Bu durumda dizinler aşamayı $match iyileştirebilir. için foodGroup dizin eklemek sorgu performansını önemli ölçüde artırır. MongoDB'de olduğu gibi dizin kullanımını en üst düzeye çıkarmak için toplama işlem hattının olabildiğince erken bir bölümüne yerleştirmelisiniz $match .

Azure Cosmos DB'nin MongoDB API'sinde dizinler gerçek toplama için kullanılmaz ve bu durumda olur $max. üzerinde version dizin eklemek sorgu performansını iyileştirmez.

Alınan belge sayısının Çıktı Belge Sayısı'na eşit olduğu sorgular

retrievedDocumentCount değeri yaklaşık olarak değerine outputDocumentCounteşitse, sorgu altyapısının birçok gereksiz belgeyi taraması gerekmezdi.

Bölümler arası sorguları en aza indirme

Azure Cosmos DB, İstek Birimi ve veri depolama gereksinimleri arttıkça ayrı kapsayıcıları ölçeklendirmek için bölümleme kullanır. Her fiziksel bölümün ayrı ve bağımsız bir dizini vardır. Sorgunuzda kapsayıcınızın bölüm anahtarıyla eşleşen bir eşitlik filtresi varsa yalnızca ilgili bölümün dizinini denetlemeniz gerekir. Bu iyileştirme sorguya gereken toplam RU sayısını azaltır. Bölüm içi sorgular ile bölümler arası sorgular arasındaki farklar hakkında daha fazla bilgi edinin.

Çok sayıda sağlanan RU'nuz (30.000'den fazla) veya depolanan büyük miktarda veriniz (yaklaşık 100 GB'tan fazla) varsa, sorgu RU ücretlerinde önemli bir azalma görmek için büyük olasılıkla yeterince büyük bir kapsayıcınız vardır.

Her fiziksel bölümün shardInformation sorgu ölçümlerini anlamak için diziyi de kontrol edebilirsiniz. Benzersiz shardKeyRangeId değerlerin sayısı, sorgunun yürütülmesi gereken fiziksel bölüm sayısıdır. Bu örnekte sorgu dört fiziksel bölümde yürütüldü. Yürütmenin dizin kullanımından tamamen bağımsız olduğunu anlamak önemlidir. Başka bir deyişle, bölümler arası sorgular dizinleri kullanmaya devam edebilir.

  "shardInformation" : [ 
                    {
                        "activityId" : "42f670a8-a201-4c58-8023-363ac18d9e18",
                        "shardKeyRangeId" : "5",
                        "durationMS" : 24.3859,
                        "preemptions" : 1,
                        "outputDocumentCount" : 463,
                        "retrievedDocumentCount" : 463
                    }, 
                    {
                        "activityId" : "a8bf762a-37b9-4c07-8ed4-ae49961373c0",
                        "shardKeyRangeId" : "2",
                        "durationMS" : 35.8328,
                        "preemptions" : 1,
                        "outputDocumentCount" : 905,
                        "retrievedDocumentCount" : 905
                    }, 
                    {
                        "activityId" : "3754e36b-4258-49a6-8d4d-010555628395",
                        "shardKeyRangeId" : "1",
                        "durationMS" : 67.3969,
                        "preemptions" : 1,
                        "outputDocumentCount" : 1479,
                        "retrievedDocumentCount" : 1479
                    }, 
                    {
                        "activityId" : "a69a44ee-db97-4fe9-b489-3791f3d52878",
                        "shardKeyRangeId" : "0",
                        "durationMS" : 185.1523,
                        "preemptions" : 1,
                        "outputDocumentCount" : 867,
                        "retrievedDocumentCount" : 867
                    }
                ]

Sorgu gecikme süresini azaltan iyileştirmeler

Çoğu durumda, sorgu gecikmesi hala çok yüksek olduğunda RU ücreti kabul edilebilir. Aşağıdaki bölümlerde, sorgu gecikme süresini azaltmaya yönelik ipuçlarına genel bir bakış verilmiştir. Aynı sorguyu aynı veri kümesinde birden çok kez çalıştırırsanız, genellikle her seferinde aynı RU ücretine sahip olacaktır. Ancak sorgu gecikme süresi, sorgu yürütmeleri arasında farklılık gösterebilir.

Yakınlığı geliştirme

Azure Cosmos DB hesabından farklı bir bölgeden çalıştırılan sorgular, aynı bölgede çalıştırıldığından daha yüksek gecikme süresine sahip olur. Örneğin, masaüstü bilgisayarınızda kod çalıştırıyorsanız, gecikmenin, sorgunun Azure Cosmos DB ile aynı Azure bölgesindeki bir sanal makineden gelmesine kıyasla onlarca veya yüzlerce milisaniye daha yüksek (veya daha fazla) olmasını beklemelisiniz. Verilerinizi uygulamanıza yaklaştırabilmeniz için Azure Cosmos DB'de verileri genel olarak dağıtmak kolaydır.

Sağlanan aktarım hızını artırma

Azure Cosmos DB'de sağlanan aktarım hızınız İstek Birimleri (RU) cinsinden ölçülür. 5 RU aktarım hızı kullanan bir sorgunuz olduğunu varsayın. Örneğin, 1.000 RU sağlarsanız, bu sorguyu saniyede 200 kez çalıştırabilirsiniz. Yeterli aktarım hızı olmadığında sorguyu çalıştırmayı denediyseniz, Azure Cosmos DB, istekleri sınırlandırır. MongoDB için Azure Cosmos DB API'si, kısa bir süre bekledikten sonra bu sorguyu otomatik olarak yeniden dener. Kısıtlanmış istekler daha uzun sürer, bu nedenle sağlanan aktarım hızını artırmak sorgu gecikme süresini iyileştirebilir.

Bu değer estimatedDelayFromRateLimitingInMilliseconds , aktarım hızını artırırsanız olası gecikme süresi avantajlarına ilişkin bir anlayış sağlar.

Sonraki adımlar