ventajas sistema programacion lenguaje gratis estructura empresa desventajas consultas complejas mongodb mongodb-indexes

sistema - mongodb wikipedia



Mongodb-rendimiento pobre cuando no hay resultados regresan (3)

Como JohnnyHK sugirió en los comentarios, y Oz123 señaló en su respuesta, el problema aquí parece ser un índice que ha crecido tanto que no funciona bien como índice. Creo que además del problema de expansión de categoría que ya se ha señalado, el orden de los campos en su índice crea problemas. Los índices compuestos se construyen de acuerdo con el orden de los campos , y poner el name después de categoriesIds hace que sea más costoso consultar el name .

Está claro que necesita ajustar sus índices. La forma exacta en que los ajusta depende de los tipos de consultas que espera admitir. En particular, no estoy seguro de si verá un mejor rendimiento de un índice compuesto de loc y name o si verá un mejor rendimiento de los índices individuales, uno para loc y otro para name . Los mismos Mongo son un poco vagos sobre cuándo es mejor usar un índice compuesto y cuándo es mejor usar índices individuales y confiar en la intersección de índices.

Mi intuición dice que los índices individuales funcionarán mejor, pero probaría ambos escenarios.

Si anticipa la necesidad de consultar por categoría también, sin los campos de name o loc que podrían limitar la consulta, probablemente sea mejor crear un índice de ID de categoriesIds separado.

Tengo una colección de Mongodb con aproximadamente 7 millones de documentos que representan lugares.

Ejecuto una consulta que busca lugares cuyo nombre comience con un prefijo cerca de una ubicación específica.

Tenemos un índice compuesto como se describe a continuación para acelerar la búsqueda.

Cuando la búsqueda de búsqueda encuentra una coincidencia (aunque solo sea una), la consulta se ejecuta muy rápidamente (~ 20 milisegundos). Pero cuando no hay coincidencia, la consulta puede tardar 30 segundos en ejecutarse.

Por favor asiste.

En detalle:

Cada lugar (geoData) tiene los siguientes campos:

"loc" - a GeoJSON point that represent the location "categoriesIds" - array of int ids "name" - the name of the placee

El siguiente índice está definido en esta colección:

{ "loc" : "2dsphere", "categoriesIds" : 1, "name" : 1 }

La consulta es:

db.geoData.find({ "loc":{ "$near":{ "$geometry":{ "type": "Point" , "coordinates": [ -0.10675191879272461 , 51.531600743186644] }, "$maxDistance": 5000.0 } }, "categoriesIds":{ "$in": [ 1 , 2 , 71 , 70 , 74 , 72 , 73 , 69 , 44 , 26 , 27 , 33 , 43 , 45 , 53 , 79] }, "name":{ "$regex": "^Cafe Ne"} })

Estadísticas de ejecución ( enlace a todo el resultado explicado )

"executionStats" : { "executionSuccess" : true, "nReturned" : 1, "executionTimeMillis" : 169, "totalKeysExamined" : 14333, "totalDocsExamined" : 1, "executionStages" : { "stage" : "GEO_NEAR_2DSPHERE", "nReturned" : 1, "executionTimeMillisEstimate" : 60, "works" : 14354, "advanced" : 1, "needTime" : 14351, "needFetch" : 0, "saveState" : 361, "restoreState" : 361, "isEOF" : 1, "invalidates" : 0, "keyPattern" : { "loc" : "2dsphere", "categoriesIds" : 1, "name" : 1 }, "indexName" : "loc_2dsphere_categoriesIds_1_name_1", "searchIntervals" : [ { "minDistance" : 0, "maxDistance" : 3408.329295346151, "maxInclusive" : false }, { "minDistance" : 3408.329295346151, "maxDistance" : 5000, "maxInclusive" : true } ], "inputStages" : [ { "stage" : "FETCH", "nReturned" : 1, "executionTimeMillisEstimate" : 20, "works" : 6413, "advanced" : 1, "needTime" : 6411, "needFetch" : 0, "saveState" : 361, "restoreState" : 361, "isEOF" : 1, "invalidates" : 0, "docsExamined" : 1, "alreadyHasObj" : 0, "inputStage" : { "stage" : "IXSCAN", "filter" : { "TwoDSphereKeyInRegionExpression" : true }, "nReturned" : 1, "executionTimeMillisEstimate" : 20, "works" : 6413, "advanced" : 1, "needTime" : 6411, "needFetch" : 0, "saveState" : 361, "restoreState" : 361, "isEOF" : 1, "invalidates" : 0, "keyPattern" : { "loc" : "2dsphere", "categoriesIds" : 1, "name" : 1 }, "indexName" : "loc_2dsphere_categoriesIds_1_name_1", "isMultiKey" : true, "direction" : "forward", "indexBounds" : { "loc" : [ "[/"2f1003230/", /"2f1003230/"]", "[/"2f10032300/", /"2f10032300/"]", "[/"2f100323000/", /"2f100323000/"]", "[/"2f1003230001/", /"2f1003230001/"]", "[/"2f10032300012/", /"2f10032300013/")", "[/"2f1003230002/", /"2f1003230002/"]", "[/"2f10032300021/", /"2f10032300022/")", "[/"2f10032300022/", /"2f10032300023/")", "[/"2f100323003/", /"2f100323003/"]", "[/"2f1003230031/", /"2f1003230031/"]", "[/"2f10032300311/", /"2f10032300312/")", "[/"2f10032300312/", /"2f10032300313/")", "[/"2f10032300313/", /"2f10032300314/")", "[/"2f1003230032/", /"2f1003230032/"]", "[/"2f10032300320/", /"2f10032300321/")", "[/"2f10032300321/", /"2f10032300322/")" ], "categoriesIds" : [ "[1.0, 1.0]", "[2.0, 2.0]", "[26.0, 26.0]", "[27.0, 27.0]", "[33.0, 33.0]", "[43.0, 43.0]", "[44.0, 44.0]", "[45.0, 45.0]", "[53.0, 53.0]", "[69.0, 69.0]", "[70.0, 70.0]", "[71.0, 71.0]", "[72.0, 72.0]", "[73.0, 73.0]", "[74.0, 74.0]", "[79.0, 79.0]" ], "name" : [ "[/"Cafe Ne/", /"Cafe Nf/")", "[/^Cafe Ne/, /^Cafe Ne/]" ] }, "keysExamined" : 6412, "dupsTested" : 0, "dupsDropped" : 0, "seenInvalidated" : 0, "matchTested" : 1 } }, { "stage" : "FETCH", "nReturned" : 0, "executionTimeMillisEstimate" : 40, "works" : 7922, "advanced" : 0, "needTime" : 7921, "needFetch" : 0, "saveState" : 261, "restoreState" : 261, "isEOF" : 1, "invalidates" : 0, "docsExamined" : 0, "alreadyHasObj" : 0, "inputStage" : { "stage" : "IXSCAN", "filter" : { "TwoDSphereKeyInRegionExpression" : true }, "nReturned" : 0, "executionTimeMillisEstimate" : 40, "works" : 7922, "advanced" : 0, "needTime" : 7921, "needFetch" : 0, "saveState" : 261, "restoreState" : 261, "isEOF" : 1, "invalidates" : 0, "keyPattern" : { "loc" : "2dsphere", "categoriesIds" : 1, "name" : 1 }, "indexName" : "loc_2dsphere_categoriesIds_1_name_1", "isMultiKey" : true, "direction" : "forward", "indexBounds" : { "loc" : [ "[/"2f1003230/", /"2f1003230/"]", "[/"2f10032300/", /"2f10032300/"]", "[/"2f100323000/", /"2f100323000/"]", "[/"2f1003230001/", /"2f1003230001/"]", "[/"2f10032300011/", /"2f10032300012/")", "[/"2f10032300012/", /"2f10032300013/")", "[/"2f1003230002/", /"2f1003230002/"]", "[/"2f10032300021/", /"2f10032300022/")", "[/"2f10032300022/", /"2f10032300023/")", "[/"2f100323003/", /"2f100323003/"]", "[/"2f1003230031/", /"2f1003230032/")", "[/"2f1003230032/", /"2f1003230032/"]", "[/"2f10032300320/", /"2f10032300321/")", "[/"2f10032300321/", /"2f10032300322/")", "[/"2f10032300322/", /"2f10032300323/")" ], "categoriesIds" : [ "[1.0, 1.0]", "[2.0, 2.0]", "[26.0, 26.0]", "[27.0, 27.0]", "[33.0, 33.0]", "[43.0, 43.0]", "[44.0, 44.0]", "[45.0, 45.0]", "[53.0, 53.0]", "[69.0, 69.0]", "[70.0, 70.0]", "[71.0, 71.0]", "[72.0, 72.0]", "[73.0, 73.0]", "[74.0, 74.0]", "[79.0, 79.0]" ], "name" : [ "[/"Cafe Ne/", /"Cafe Nf/")", "[/^Cafe Ne/, /^Cafe Ne/]" ] }, "keysExamined" : 7921, "dupsTested" : 0, "dupsDropped" : 0, "seenInvalidated" : 0, "matchTested" : 0 } } ] },

Estadísticas de ejecución al buscar "CafeNeeNNN" en lugar de "Cafe Ne" ( enlace a todo explica el resultado )

"executionStats" : { "executionSuccess" : true, "nReturned" : 0, "executionTimeMillis" : 2537, "totalKeysExamined" : 232259, "totalDocsExamined" : 162658, "executionStages" : { "stage" : "FETCH", "filter" : { "$and" : [ { "name" : /^CafeNeeNNN/ }, { "categoriesIds" : { "$in" : [ 1, 2, 26, 27, 33, 43, 44, 45, 53, 69, 70, 71, 72, 73, 74, 79 ] } } ] }, "nReturned" : 0, "executionTimeMillisEstimate" : 1330, "works" : 302752, "advanced" : 0, "needTime" : 302750, "needFetch" : 0, "saveState" : 4731, "restoreState" : 4731, "isEOF" : 1, "invalidates" : 0, "docsExamined" : 70486, "alreadyHasObj" : 70486, "inputStage" : { "stage" : "GEO_NEAR_2DSPHERE", "nReturned" : 70486, "executionTimeMillisEstimate" : 1290, "works" : 302751, "advanced" : 70486, "needTime" : 232264, "needFetch" : 0, "saveState" : 4731, "restoreState" : 4731, "isEOF" : 1, "invalidates" : 0, "keyPattern" : { "loc" : "2dsphere" }, "indexName" : "loc_2dsphere", "searchIntervals" : [ { "minDistance" : 0, "maxDistance" : 3408.329295346151, "maxInclusive" : false }, { "minDistance" : 3408.329295346151, "maxDistance" : 5000, "maxInclusive" : true } ], "inputStages" : [ { "stage" : "FETCH", "nReturned" : 44540, "executionTimeMillisEstimate" : 110, "works" : 102690, "advanced" : 44540, "needTime" : 58149, "needFetch" : 0, "saveState" : 4731, "restoreState" : 4731, "isEOF" : 1, "invalidates" : 0, "docsExamined" : 44540, "alreadyHasObj" : 0, "inputStage" : { "stage" : "IXSCAN", "filter" : { "TwoDSphereKeyInRegionExpression" : true }, "nReturned" : 44540, "executionTimeMillisEstimate" : 90, "works" : 102690, "advanced" : 44540, "needTime" : 58149, "needFetch" : 0, "saveState" : 4731, "restoreState" : 4731, "isEOF" : 1, "invalidates" : 0, "keyPattern" : { "loc" : "2dsphere" }, "indexName" : "loc_2dsphere", "isMultiKey" : false, "direction" : "forward", "indexBounds" : { "loc" : [ "[/"2f1003230/", /"2f1003230/"]", "[/"2f10032300/", /"2f10032300/"]", "[/"2f100323000/", /"2f100323000/"]", "[/"2f1003230001/", /"2f1003230001/"]", "[/"2f10032300012/", /"2f10032300013/")", "[/"2f1003230002/", /"2f1003230002/"]", "[/"2f10032300021/", /"2f10032300022/")", "[/"2f10032300022/", /"2f10032300023/")", "[/"2f100323003/", /"2f100323003/"]", "[/"2f1003230031/", /"2f1003230031/"]", "[/"2f10032300311/", /"2f10032300312/")", "[/"2f10032300312/", /"2f10032300313/")", "[/"2f10032300313/", /"2f10032300314/")", "[/"2f1003230032/", /"2f1003230032/"]", "[/"2f10032300320/", /"2f10032300321/")", "[/"2f10032300321/", /"2f10032300322/")" ] }, "keysExamined" : 102689, "dupsTested" : 0, "dupsDropped" : 0, "seenInvalidated" : 0, "matchTested" : 44540 } }, { "stage" : "FETCH", "nReturned" : 47632, "executionTimeMillisEstimate" : 250, "works" : 129571, "advanced" : 47632, "needTime" : 81938, "needFetch" : 0, "saveState" : 2556, "restoreState" : 2556, "isEOF" : 1, "invalidates" : 0, "docsExamined" : 47632, "alreadyHasObj" : 0, "inputStage" : { "stage" : "IXSCAN", "filter" : { "TwoDSphereKeyInRegionExpression" : true }, "nReturned" : 47632, "executionTimeMillisEstimate" : 230, "works" : 129571, "advanced" : 47632, "needTime" : 81938, "needFetch" : 0, "saveState" : 2556, "restoreState" : 2556, "isEOF" : 1, "invalidates" : 0, "keyPattern" : { "loc" : "2dsphere" }, "indexName" : "loc_2dsphere", "isMultiKey" : false, "direction" : "forward", "indexBounds" : { "loc" : [ "[/"2f1003230/", /"2f1003230/"]", "[/"2f10032300/", /"2f10032300/"]", "[/"2f100323000/", /"2f100323000/"]", "[/"2f1003230001/", /"2f1003230001/"]", "[/"2f10032300011/", /"2f10032300012/")", "[/"2f10032300012/", /"2f10032300013/")", "[/"2f1003230002/", /"2f1003230002/"]", "[/"2f10032300021/", /"2f10032300022/")", "[/"2f10032300022/", /"2f10032300023/")", "[/"2f100323003/", /"2f100323003/"]", "[/"2f1003230031/", /"2f1003230032/")", "[/"2f1003230032/", /"2f1003230032/"]", "[/"2f10032300320/", /"2f10032300321/")", "[/"2f10032300321/", /"2f10032300322/")", "[/"2f10032300322/", /"2f10032300323/")" ] }, "keysExamined" : 129570, "dupsTested" : 0, "dupsDropped" : 0, "seenInvalidated" : 0, "matchTested" : 47632 } } ] } },

Índices de la colección.

{ "0" : { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "wego.geoData" }, "1" : { "v" : 1, "key" : { "srcId" : 1 }, "name" : "srcId_1", "ns" : "wego.geoData" }, "2" : { "v" : 1, "key" : { "loc" : "2dsphere" }, "name" : "loc_2dsphere", "ns" : "wego.geoData", "2dsphereIndexVersion" : 2 }, "3" : { "v" : 1, "key" : { "name" : 1 }, "name" : "name_1", "ns" : "wego.geoData" }, "4" : { "v" : 1, "key" : { "loc" : "2dsphere", "categoriesIds" : 1, "name" : 1 }, "name" : "loc_2dsphere_categoriesIds_1_name_1", "ns" : "wego.geoData", "2dsphereIndexVersion" : 2 }, "5" : { "v" : 1, "key" : { "loc" : "2dsphere", "categoriesIds" : 1, "keywords" : 1 }, "name" : "loc_2dsphere_categoriesIds_1_keywords_1", "ns" : "wego.geoData", "2dsphereIndexVersion" : 2 } }

Enlace de estadísticas de colección


El orden de los campos en un índice compuesto es muy importante. Es difícil de diagnosticar sin tener acceso a los datos reales y los patrones de uso, pero esta clave puede aumentar las probabilidades de hacer coincidir (o no) el documento utilizando solo el índice:

{ "loc" : "2dsphere", "name" : 1, "categoriesIds" : 1 }


Voy a especular aquí un poco, y luego un comentario sobre su diseño.

Primero, cuando creas un índice en clave que tiene una matriz en un valor, creas un registro para cada elemento de la matriz:

Para indexar un campo que contiene un valor de matriz, MongoDB crea una clave de índice para cada elemento de la matriz.

Esto es de la propia documentación de MongoDB sobre indecies .

Por lo tanto, si su registro típico incluye más de una mano llena de categorías y tiene 7 millones de registros, su índice es enorme, y también tomará tiempo escanear el índice en sí para encontrar que el índice no contiene lo que está buscando. Aún es más rápido que un escaneo de colección, pero es extremadamente lento en comparación con la rapidez con la que se encuentra un registro existente.

Ahora, déjame comentar sobre el diseño de tu esquema. Esto es una cuestión de estilo, así que siéntete libre de ignorar esta parte.

Tienes un registro que podría estar en 17 categorías. Eso es un poco abrumador, y por abusar del término category . Una categoría es una división específica, una forma de asociar rápidamente una cosa con un grupo de cosas. ¿Qué es una cosa que pertenece a tantos grupos? Tomemos, por ejemplo, sus discos Cafe Ne . Supongo que en el mundo real, y recuerde que la programación y las aplicaciones son mejores cuando se resuelven los problemas del mundo real. Cafe Ne es un restaurante, un café, un bar de jazz, una cena. Es seguro que no es un garaje (a menos que, café signifique autos en un idioma que no conozco). Casi no puedo imaginar que sea un banco o una clínica dental. Tendría que hacer un gran esfuerzo, para encontrar más de 10 categorías significativas, que los usuarios busquen en un café.

Mi punto es que, aunque mongodb te permite diseñar cosas así, no significa que tengas que hacerlo. Intente reducir el número de categorías que tiene y las que busca, y tendrá un rendimiento mucho mejor.