Solución de problemas de consultas al usar Azure Cosmos DB for MongoDB
SE APLICA A: MongoDB
Este artículo le guía por un enfoque recomendado general para la solución de problemas con las consultas en Azure Cosmos DB. Aunque no debe tener en cuenta los pasos descritos en este artículo como una defensa completa contra posibles problemas de consulta, hemos incluido aquí las sugerencias de rendimiento más comunes. Use este artículo como punto de partida para la solución de problemas con las consultas lentas o costosas en la API para MongoDB de Azure Cosmos DB. Si usa Azure Cosmos DB for NoSQL, consulte el artículo Guía de solución de problemas de consultas de API para NoSQL.
Las categorías de las optimizaciones de consulta en Azure Cosmos DB son las siguientes:
- Optimizaciones que reducen el cargo por unidades de solicitud (RU) de la consulta
- Optimizaciones que solo reducen la latencia
Al reducir el cargo por RU de una consulta, normalmente se reducirá la latencia.
En este artículo se ofrecen ejemplos que se pueden volver a crear mediante el conjunto de datos nutrition.
Nota:
En este artículo se da por supuesto que está usando la cuenta de API de Azure Cosmos DB para MongoDB con la versión 3.6 y versiones posteriores. Algunas consultas que funcionan de manera deficiente en la versión 3.2 han mejorado significativamente en la versión 3.6. Para actualizar a la versión 3.6, presente una solicitud de soporte técnico.
Uso del comando $explain para obtener métricas
Al optimizar una consulta en Azure Cosmos DB, el primer paso es siempre obtener el cargo por RU de la consulta. Como directriz aproximada, debe explorar las maneras de reducir el cargo por RU para consultas con cargos mayores que 50 RU.
Además de obtener el cargo por RU, debe usar el comando $explain
para obtener las métricas de uso de las consultas y los índices. Este es un ejemplo en el que se ejecuta una consulta y se usa el comando $explain
para mostrar las métricas de uso de las consultas y los índices:
Comando $explain:
db.coll.find({foodGroup: "Baby Foods"}).explain({"executionStatistics": true })
Salida:
{
"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
}
La salida del comando $explain
es larga y contiene información detallada acerca de la ejecución de la consulta. Sin embargo, en general, hay algunas secciones en las que se debe centrar al optimizar el rendimiento de las consultas:
Métrica | Descripción |
---|---|
timeInclusiveMS |
Latencia de consulta de back-end. |
pathsIndexed |
Muestra los índices usados por la consulta. |
pathsNotIndexed |
Muestra los índices que la consulta podría haber usado, si están disponibles. |
shardInformation |
Resumen del rendimiento de las consultas de una partición física determinada. |
retrievedDocumentCount |
Número de documentos cargados por el motor de consultas. |
outputDocumentCount |
Número de documentos devueltos en los resultados de la consulta. |
estimatedDelayFromRateLimitingInMilliseconds |
Latencia de consulta adicional estimada debido a la limitación de velocidad. |
Después de obtener las métricas de consulta, compare el retrievedDocumentCount
con el de outputDocumentCount
de la consulta. Use esta comparación para identificar las secciones pertinentes a las que se hará referencia en este artículo. retrievedDocumentCount
es el número de documentos que el motor de consulta necesita cargar. El outputDocumentCount
es el número de documentos necesarios para los resultados de la consulta. Si el retrievedDocumentCount
es significativamente mayor que el de outputDocumentCount
, habrá al menos una parte de la consulta que no haya podido usar el índice y haya tenido que realizar un examen.
Consulte las secciones siguientes para entender las optimizaciones de consulta pertinentes para su escenario.
El cargo por RU de la consulta es demasiado elevado
El recuento de documentos recuperados es significativamente mayor que el de documentos de salida
Recuento de documentos recuperados aproximadamente igual al de documentos de salida
El cargo por RU de la consulta es aceptable, pero la latencia sigue siendo demasiado elevada
Consultas en las que el recuento de documentos recuperados supera el de documentos de salida
El retrievedDocumentCount
es el número de documentos que el motor de consulta necesitaba cargar. El outputDocumentCount
es el número de documentos que devuelve la consulta. Si el retrievedDocumentCount
es significativamente mayor que el de outputDocumentCount
, habrá al menos una parte de la consulta que no haya podido usar el índice y haya tenido que realizar un examen.
A continuación se muestra un ejemplo de consulta de examen que el índice no sirvió completamente:
Comando $explain:
db.coll.find(
{
$and : [
{ "foodGroup" : "Cereal Grains and Pasta"},
{ "description" : "Oat bran, cooked"}
]
}
).explain({"executionStatistics": true })
Salida:
{
"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) es significativamente mayor que outputDocumentCount
(1), lo que implica que esta consulta requirió un examen del documento.
Inclusión de los índices necesarios
Debe comprobar la matriz pathsNotIndexed
y agregar estos índices. En este ejemplo, las rutas de acceso foodGroup
y description
deben indexarse.
"pathsNotIndexed" : [
"foodGroup",
"description"
]
Los procedimientos recomendados de indexación en la API para MongoDB de Azure Cosmos DB son diferentes de MongoDB. En la API para MongoDB de Azure Cosmos DB, los índices compuestos solo se usan en consultas que necesitan ordenar de forma eficaz por varias propiedades. Si tiene consultas con filtros en varias propiedades, debe crear índices de campo único para cada una de estas propiedades. Los predicados de consulta pueden usar varios índices de campo único.
Los índices de caracteres comodín pueden simplificar la indexación. A diferencia de MongoDB, los índices de caracteres comodín pueden admitir varios campos en predicados de consulta. No habrá ninguna diferencia en el rendimiento de las consultas si se usa un solo índice de caracteres comodín en lugar de crear un índice independiente para cada propiedad. Agregar un índice de caracteres comodín para todas las propiedades es la forma más fácil de optimizar todas las consultas.
Puede agregar nuevos índices en cualquier momento, sin que ello afecte a la disponibilidad de la escritura o la lectura. Puede realizar el seguimiento del progreso de transformación del índice.
Obtención de información sobre qué operaciones de agregación usan el índice
En la mayoría de los casos, las operaciones de agregación en la API para MongoDB de Azure Cosmos DB usarán índices parcialmente. Normalmente, el motor de consultas aplicará primero los filtros de igualdad y de intervalo, y usará índices. Después de aplicar estos filtros, el motor de consultas puede evaluar los filtros adicionales y recurrir a la carga de los documentos restantes para calcular el agregado, si es necesario.
Este es un ejemplo:
db.coll.aggregate( [
{ $match: { foodGroup: 'Fruits and Fruit Juices' } },
{
$group: {
_id: "$foodGroup",
total: { $max: "$version" }
}
}
] )
En este caso, los índices pueden optimizar la fase $match
. La adición de un índice para foodGroup
mejorará significativamente el rendimiento de las consultas. Al igual que en MongoDB, debe colocar $match
tan pronto como sea posible en la canalización de agregación para maximizar el uso de los índices.
En la API para MongoDB de Azure Cosmos DB, los índices no se usan para la agregación real, que en este caso es $max
. La adición de un índice en version
no mejorará el rendimiento de la consulta.
Consultas en las que el recuento de documentos recuperados es igual al de documentos de salida
Si el retrievedDocumentCount
es aproximadamente igual al de los outputDocumentCount
, significa que el motor de consulta no tuvo que examinar muchos documentos innecesarios.
Minimización de las consultas con particiones cruzadas
Azure Cosmos DB usa particiones para escalar contenedores individuales a medida que aumentan las necesidades de almacenamiento de datos y las unidades de solicitud. Cada partición física tiene un índice independiente. Si la consulta tiene un filtro de igualdad que coincide con la clave de partición del contenedor, solo tendrá que comprobar el índice de la partición pertinente. Esta optimización reduce el número total de RU que requiere la consulta. Obtenga más información sobre las diferencias entre las consultas en particiones y las consultas entre particiones.
Si tiene un gran número de RU aprovisionadas (más de 30 000) o una gran cantidad de datos almacenados (más de aproximadamente 100 GB), es probable que tenga un contenedor lo suficientemente grande como para ver una reducción significativa en los cargos de las RU de consulta.
Puede comprobar la matriz shardInformation
para comprender las métricas de consulta de cada partición física individual. El número de valores de shardKeyRangeId
únicos es el número de particiones físicas en las que la consulta debía ejecutarse. En este ejemplo, la consulta se ejecutó en cuatro particiones físicas. Es importante comprender que la ejecución es completamente independiente del uso de índices. Es decir, las consultas entre particiones pueden seguir usando índices.
"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
}
]
Optimizaciones que reducen la latencia de las consultas
En muchos casos, el cargo por RU podría ser aceptable cuando la latencia de consulta sigue siendo demasiado alta. En las secciones siguientes se ofrece información general con sugerencias para reducir la latencia de las consultas. Si ejecuta la misma consulta varias veces en el mismo conjunto de datos, normalmente tendrá el mismo cargo por RU cada vez. Sin embargo, la latencia de las consultas podría variar entre una ejecución y otra.
Mejora de la proximidad
Las consultas que se ejecutan desde una región distinta de aquella de la cuenta de Azure Cosmos DB tendrán una latencia mayor que si se ejecutaran desde la misma región. Por ejemplo, si ejecutara código en el equipo de escritorio, debería esperar que la latencia fuera decenas o cientos (o más) de milisegundos más que si la consulta proviniera de una máquina virtual dentro de la misma región de Azure que Azure Cosmos DB. Es fácil distribuir datos globalmente en Azure Cosmos DB para asegurarse de que puede acercar los datos a la aplicación.
Aumento de la capacidad de proceso aprovisionada
En Azure Cosmos DB, el rendimiento aprovisionado se mide en unidades de solicitud (RU). Supongamos que tiene una consulta que consume 5 RU de rendimiento. Por ejemplo, si aprovisiona 1000 RU, podrá ejecutar esa consulta 200 veces por segundo. Si intentó ejecutar la consulta cuando no había suficiente rendimiento disponible, Azure Cosmos DB limitará la velocidad de las solicitudes. La API para MongoDB de Azure Cosmos DB volverá a intentar automáticamente esta consulta tras una breve espera. Las solicitudes limitadas tardan más, por lo que aumentar el rendimiento aprovisionado puede mejorar la latencia de las consultas.
El valor estimatedDelayFromRateLimitingInMilliseconds
da la sensación de posibles ventajas de latencia si aumenta el rendimiento.
Pasos siguientes
- Solución de problemas de rendimiento de consultas (API para NoSQL)
- Evitar la limitación de velocidad con SSR
- Administración de la indexación en la API de Azure Cosmos DB para MongoDB
- ¿Intenta planear la capacidad de una migración a Azure Cosmos DB? Para ello, puede usar información sobre el clúster de bases de datos existente.
- Si lo único que sabe es el número de núcleos virtuales y servidores del clúster de bases de datos existente, lea sobre el cálculo de unidades de solicitud mediante núcleos o CPU virtuales.
- Si conoce las tasas de solicitudes típicas de la carga de trabajo de la base de datos actual, obtenga información sobre el cálculo de unidades de solicitud mediante la herramienta de planeamiento de capacidad de Azure Cosmos DB.