Nivel 3 · 30 min
Optimización de Queries
La optimización de queries en MongoDB requiere entender cómo el query planner selecciona planes de ejecución, cómo leer la salida de explain() y cuándo las queries se sirven desde índices vs full collection scans.
explain() y Planes de Ejecución
El método explain() revela cómo MongoDB ejecuta una query. Tres niveles de verbosidad: queryPlanner (selección de plan, sin ejecución), executionStats (ejecuta la query, devuelve estadísticas), allPlansExecution (ejecuta todos los planes candidatos, costoso). Stages clave: COLLSCAN = full collection scan, sin índice usable. IXSCAN = índice usado: revisá keysExamined vs nReturned. FETCH aparece después de IXSCAN cuando se deben cargar documentos para campos proyectados. SORT aparece cuando el sort no puede satisfacerse por el orden del índice.
Query Planner y Cache
Cuando múltiples índices podrían satisfacer una query, el query planner ejecuta planes candidatos en paralelo (período de prueba) y selecciona el ganador basándose en cuál retorna los primeros 101 resultados más rápido. El plan ganador se cachea por query shape (la estructura de la query, sin valores literales). El caché se invalida cuando: se agrega o elimina un índice, las estadísticas de la colección cambian significativamente, mongod se reinicia. Usá db.collection.getPlanCache().list() para inspeccionar planes cacheados.
Covered Queries y Proyecciones
Una covered query se satisface íntegramente desde datos del índice: MongoDB nunca lee los documentos actuales. Requisitos: todos los campos del filtro de query están en el índice, todos los campos proyectados están en el índice (y _id está excluido o en el índice). Cuando es covered, explain() no muestra el stage FETCH. Index hint fuerza al planner a usar un índice específico: db.collection.find(query).hint(indexName). Útil para testing o cuando el planner toma una decisión incorrecta.
Code example
// Basic explain\ndb.users.find({email: '[email protected]}).explain('executionStats')\n\n// Key fields to check in explain output:\n// executionStats.totalDocsExamined vs totalKeysExamined vs nReturned\n// queryPlanner.winningPlan.stage: COLLSCAN or IXSCAN\n// queryPlanner.winningPlan.inputStage.stage: FETCH (not covered)\n\n// Force a specific index (for testing)\ndb.users.find({email: '[email protected]}).hint({email: 1})