es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Informando Todas las Bases de Datos con sus Tamaños de Colección en MongoDB.

Estoy tratando de encontrar todas las colecciones en cada base de datos de MongoDB cuyo tamaño sea superior a 1GB e imprimir el nombre de la base de datos, el nombre de la colección y el tamaño de la colección.

Escribí un javascript para ello, funciona en mongo que tiene menos bases de datos pero apaga el mongo mientras intenta ejecutar el script en producción. Parece que la consulta no es óptima en cuanto a rendimiento.

Aquí está el javascript que escribí:

db.getMongo().getDBNames().forEach(function(dbName){
    db.getMongo().getDB(dbName).getCollectionNames().forEach(function(collName){
        var coll = db.getMongo().getDB(dbName).getCollection(collName);
        var collSize = coll.stats(1024*1024*1024).storageSize;
        if (collSize > 1) {
            print(dbName + ":" + collName + ":" + collSize);
        }
    })
})

¿Hay alguna manera de mejorarlo?

Gracias.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, existen algunas formas de mejorar el rendimiento de la consulta. Aquí hay algunas sugerencias:

    1. Utilice el marco de agregación en lugar de iterar sobre cada colección una por una. Esto se puede hacer utilizando el método “aggregate” en el objeto “db”. Aquí hay un ejemplo de consulta que debería lograr el mismo resultado:
    db.adminCommand({
      aggregate: "system.namespaces",
      pipeline: [
        // Filtrar las colecciones no-cap y de sistema
        { $match: { name: { $not: /(\.|\$)/ } } },
        // Proyectar solo los campos relevantes y calcular el tamaño en GB
        {
          $project: {
            dbName: { $substr: ["$name", 0, { $indexOfBytes: ["$name", "."] }] },
            collName: { $substr: ["$name", { $add: [{ $indexOfBytes: ["$name", "."] }, 1] }, -1] },
            sizeGB: { $divide: [ "$stats.storageSize", 1073741824 ] },
          }
        },
        // Filtrar las colecciones menores de 1GB
        { $match: { sizeGB: { $gt: 1 } } }
      ]
    }).result.forEach(function(doc) {
      print(doc.dbName + ":" + doc.collName + ":" + doc.sizeGB);
    });
    
    1. Utilice el comando “listDatabases” en lugar de “getDBNames”. Esto puede reducir el número de consultas realizadas al servidor. Aquí hay una versión actualizada del código original:
    db.adminCommand({ listDatabases: 1 }).databases.forEach(function(dbinfo) {
      db.getSiblingDB(dbinfo.name).getCollectionInfos().forEach(function(collinfo) {
        var collSize = collinfo.sizeOnDisk / 1024 / 1024 / 1024;  // sizeOnDisk está en bytes
        if (collSize > 1) {
          print(dbinfo.name + ":" + collinfo.name + ":" + collSize);
        }
      });
    });
    

    Tenga en cuenta que este código asume que todas las colecciones no son capaces, de lo contrario deberá agregar un paso de filtrado similar al que se encuentra en el ejemplo de agregación.

    1. Ejecute la consulta en lotes más pequeños. Esto se puede hacer dividiendo la lista de bases de datos en segmentos más pequeños y procesándolos por separado. Aquí hay un ejemplo:
    var CHUNK_SIZE = 10;
    
    var dbnames = db.getMongo().getDBNames();
    for (var i = 0; i < dbnames.length; i += CHUNK_SIZE) {
      var chunk = dbnames.slice(i, i + CHUNK_SIZE);
      chunk.forEach(function(dbName) {
        db.getSiblingDB(dbName).getCollectionInfos().forEach(function(collinfo) {
          var collSize = collinfo.sizeOnDisk / 1024 / 1024 / 1024;
          if (collSize > 1) {
            print(dbName + ":" + collinfo.name + ":" + collSize);
          }
        });
      });
    }
    

    Este código procesa 10 bases de datos a la vez, lo que debería reducir la carga en el servidor y evitar que se bloquee. Ajuste la variable “CHUNK_SIZE” según sea necesario.

Comments are closed.