Tengo más de 300 mil registros en una colección en Mongo.

Al ejecutar esta consulta muy simple:

db.myCollection.find().limit(5);

Se toma sólo unos pocos milisegundos.

Pero cuando uso saltar en la consulta:

db.myCollection.find().skip(200000).limit(5)

No va a devolver nada… funciona para los minutos y no devuelve nada.

Cómo hacerlo mejor?

InformationsquelleAutor Radek Simko | 2011-08-29

3 Comentarios

  1. 66

    De MongoDB documentación:

    De Paginación Costos

    Lamentablemente saltar puede ser muy costoso y requiere que el servidor a pie desde el principio de la colección, o índice, para obtener el offset/saltar posición antes de que se pueda regresar a la página de datos (límite). Como el número de la página aumenta omitir va a ser más lento y más cpu, y posiblemente IO obligado, con las más grandes colecciones.

    Gama basada en paginación proporciona un mejor uso de los índices, pero no le permiten saltar a una página específica.

    Que tienes que hacerte una pregunta: ¿con qué frecuencia usted necesita 40000th página? Ver también este artículo;

    • es un ÍNDICE, ésta debe ser instantánea, en el peor de esto es que si tienes 1 millón de documentos, y saltar 10 millones que todavía tardará más de un minuto, esto es difícil de entender, no mongo saber en todo momento cómo muchos de los documentos de una colección ? pero mi punto principal es, ¿por qué es lenta para obtener la enésima documento ? no es por eso que utilizamos bases de datos en primer lugar ?
  2. 88

    Un enfoque para este problema, si tienes grandes cantidades de documentos y se muestran en ordenados orden (no estoy seguro de lo útil skip es que si no estás), sería el uso de la clave de clasificación para seleccionar la siguiente página de resultados.

    Así que si usted comienza con

    db.myCollection.find().limit(100).sort({created_date:true});

    y, a continuación, extraiga la fecha de creación de la última documento devuelto por el cursor en una variable max_created_date_from_last_result, se puede obtener la siguiente página con la mucho más eficiente (suponiendo que tiene un índice en created_date) consulta

    db.myCollection.find({created_date : { $gt : max_created_date_from_last_result } }).limit(100).sort({created_date:true}); 
    • Esto parece realmente buena. Por qué no puedo ver más a la gente lo que sugiere esto?
    • Bueno, es limitada en la que sólo puede ir una página hacia adelante o hacia atrás en el tiempo, en lugar de saltar a una página específica, pero para este uso limitado caso creo que funciona bien.
    • Idea genial. Si no se preocupan realmente de una especie (excepto para este propósito), y no desea ordenar o crear un índice, parece que tal vez usted podría saltar un paso y tomar ventaja de la ObjectId (_id) campo que será indexado…es posible identificadores de objeto obtener reciclados, pero de nuevo eso no importa en este caso.
    • He encontrado esta respuesta que utiliza un mecanismo similar a los anteriores: stackoverflow.com/a/9704204/1015147 Que podría ser útil.
    • Este enfoque debe utilizarse con precaución, ya que se hacen de los resultados que se omite si tienen el mismo created_date como max_created_date_from_last_result. Consulte sammaye.wordpress.com/2012/05/25/…, que ofrece la solución de utilizar un compuesto índice de _id y la marca de hora.
    • Este es un enfoque razonable, pero no perfecta, ya que no se puede saltar de las páginas. Una limitación que veo, lo que si los registros están ordenados por nombre, ejemplo: product.name. Estoy realmente sorprendido de no ver el verdadero apoyo para skip en MangoDB, este es un interruptor para mí.

  3. 2

    Me pareció eficiente para combinar los dos conceptos juntos (ambos a saltar límite y encontrar+límite). El problema con skip+límite es pobre rendimiento cuando usted tiene un montón de documentos (especialmente grandes docs). El problema con encontrar+límite es que no se puede saltar a cualquier página. Quiero ser capaz de paginas sin hacerlo de forma secuencial.

    Las medidas que se toman son:

    1. Crear un índice basado en cómo desea ordenar tus documentos, o simplemente utilizar el valor predeterminado _id índice (que es lo que he usado)
    2. Saber el valor inicial, el tamaño de página y la página a la que desea saltar
    3. Proyecto de + saltar + límite el valor que debería comenzar a partir de
    4. Encontrar + límite de la página de resultados del

    Se ve aproximadamente como este si quiero llegar a la página 5432 de 16 registros (en javascript):

    let page = 5432;
    let page_size = 16;
    let skip_size = page * page_size;
    
    let retval = await db.collection(...).find().sort({ "_id": 1 }).project({ "_id": 1 }).skip(skip_size).limit(1).toArray();
    let start_id = retval[0].id;
    
    retval = await db.collection(...).find({ "_id": { "$gte": new mongo.ObjectID(start_id) } }).sort({ "_id": 1 }).project(...).limit(page_size).toArray();

    Esto funciona debido a un salto en un proyectado índice es muy rápido, incluso si va a saltar millones de registros (que es lo que estoy haciendo). si ejecuta explain("executionStats"), todavía tiene un gran número de totalDocsExamined pero debido a la proyección en un índice, es muy rápido (esencialmente, los datos blob nunca son examinados). A continuación, con el valor para el inicio de la página en la mano, usted puede obtener la siguiente página muy rápidamente.

    • He probado con un par de medio millón de registros, pero las proyecciones agrega más tiempo a la consulta

Dejar respuesta

Please enter your comment!
Please enter your name here