Menu Docs

Página inicial do DocsDesenvolver aplicaçõesManual do MongoDB

Usar índices para classificar os resultados da query

Nesta página

  • Classificar com um índice de campo único
  • Classificar em Vários Campos
  • Ordem de Classificação dos Índices
  • Uso do Índice e Agrupamento
  • Exemplos

Como os índices contêm registros ordenados, o MongoDB pode obter os resultados de uma classificação a partir de um índice que inclua os campos de classificação. O MongoDB pode usar vários índices para dar suporte a uma operação de classificação se a classificação usar os mesmos índices que o predicado da query.

Se o MongoDB não puder usar um índice ou índices para obter a ordem de classificação, o MongoDB deverá executar uma operação de classificação de bloqueio nos dados. Uma classificação de bloqueio indica que o MongoDB deve consumir e processar todos os documentos de entrada para a classificação antes de retornar os resultados. As classificações de bloqueio não bloqueiam operações simultâneas na coleção ou no banco de dados.

A partir do MongoDB 6.0, se o servidor exigir mais de 100 megabytes de memória para um estágio de execução do pipeline, o MongoDB gravará automaticamente arquivos temporários em disco, a menos que essa consulta especifique { allowDiskUse: false }. Se o servidor precisar de mais de 100 megabytes de memória do sistema para a operação de block sort, o MongoDB retornará um erro, a menos que essa consulta especifique cursor.allowDiskUse(). Para detalhes, consulte allowDiskUseByDefault.

As operações de classificação que usam um índice geralmente têm melhor desempenho do que os ordenadores bloqueantes.

Observação

Quando você classifica com base em um campo de array indexado com um índice de várias chaves, o plano de query inclui um estágio de ordenador bloqueante, a menos que os dois itens a seguir sejam verdadeiros:

  • Os limites do índice para todos os campos de classificação são [MinKey, MaxKey].

  • Nenhum limite de qualquer campo indexado por várias chaves tem o mesmo prefixo de caminho que o padrão de classificação.

Se um índice ascendente ou descendente estiver em um único campo, a operação de classificação do campo poderá estar em qualquer direção.

Por exemplo, crie um índice ascendente no campo a para uma coleção records:

db.records.createIndex( { a: 1 } )

Este índice pode gerar a ordem crescente em a:

db.records.find().sort( { a: 1 } )

O índice também pode suportar a seguinte classificação descendente no a atravessando o índice em ordem inversa:

db.records.find().sort( { a: -1 } )

Crie um índice composto para oferecer suporte à classificação em vários campos.

Você pode especificar uma classificação em todas as chaves do índice ou em um subconjunto; no entanto, as chaves de classificação devem ser listadas na mesma ordem em que aparecem no índice. Por exemplo, um padrão de chave de índice { a: 1, b: 1 } pode oferecer suporte a uma classificação em { a: 1, b: 1 } mas não em { b: 1, a: 1 }.

Para que uma query use um índice composto para uma classificação, a direção de classificação especificada para todas as chaves no documento cursor.sort() deve corresponder ao padrão de chave do índice ou ao inverso do padrão de chave do índice. Por exemplo, um padrão de chave de índice { a: 1, b: -1 } pode oferecer suporte a uma classificação em { a: 1, b: -1 } e { a: -1, b: 1 } mas não em { a: -1, b: -1 } ou {a: 1, b: 1}.

Se as chaves de classificação corresponderem às chaves de índice ou a um prefixo de índice, o MongoDB poderá utilizar o índice para classificar os resultados da query. Um prefixo de um índice composto é um subconjunto que consiste em uma ou mais chaves no início do padrão da chave do índice.

Por exemplo, crie um índice composto na coleção data:

db.data.createIndex( { a:1, b: 1, c: 1, d: 1 } )

Em seguida, os seguintes são prefixos desse índice:

{ a: 1 }
{ a: 1, b: 1 }
{ a: 1, b: 1, c: 1 }

As seguintes operações de query e classificação utilizam os prefixos de índice para classificar os resultados. Essas operações não precisam classificar o resultado definido na memória.

Exemplo
Prefixo de índices
db.data.find().sort( { a: 1 } )
{ a: 1 }
db.data.find().sort( { a: -1 } )
{ a: 1 }
db.data.find().sort( { a: 1, b: 1 } )
{ a: 1, b: 1 }
db.data.find().sort( { a: -1, b: -1 } )
{ a: 1, b: 1 }
db.data.find().sort( { a: 1, b: 1, c: 1 } )
{ a: 1, b: 1, c: 1 }
db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } )
{ a: 1, b: 1 }

Considere o exemplo a seguir, no qual as chaves de prefixo do índice aparecem tanto no predicado da query quanto na classificação:

db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } )

Nesses casos, o MongoDB pode usar o índice para recuperar os documentos em ordem especificada pela classificação. Como o exemplo mostra, o prefixo do índice no predicado da query pode ser diferente do prefixo na classificação.

Um índice pode oferecer suporte a operações de classificação em um subconjunto sem prefixo do padrão de chave de índice. Para fazer isso, a query deve incluir condições de igualdade em todas as chaves de prefixo que precedem as chaves de classificação.

Por exemplo, a coleção data tem o seguinte índice:

{ a: 1, b: 1, c: 1, d: 1 }

As seguintes operações podem utilizar o índice para obter a ordem de classificação:

Exemplo
Prefixo de índices
db.data.find( { a: 5 } ).sort( { b: 1, c: 1 } )
{ a: 1 , b: 1, c: 1 }
db.data.find( { b: 3, a: 4 } ).sort( { c: 1 } )
{ a: 1, b: 1, c: 1 }
db.data.find( { a: 5, b: { $lt: 3} } ).sort( { b: 1 } )
{ a: 1, b: 1 }

Como mostra a última operação, somente os campos de índice que precedem o subconjunto de classificação devem ter condições de igualdade no documento de query. Os outros campos de índice podem especificar outras condições.

Se a query não especificar uma condição de igualdade em um prefixo de índice que precede ou se sobrepõe com a especificação de classificação, a operação não utilizará o índice de forma eficiente. Por exemplo, as seguintes operações especificam um documento de classificação de { c: 1 }, mas os documentos de query não contêm correspondências de igualdade nos campos de índice anteriores a e b:

db.data.find( { a: { $gt: 2 } } ).sort( { c: 1 } )
db.data.find( { c: 5 } ).sort( { c: 1 } )

Essas operações não usarão eficientemente o índice { a: 1, b: 1, c: 1, d: 1 } e podem nem mesmo usar o índice para recuperar os documentos.

Uma coleção de documentos indexados pode ter vários tipos de dados no campo chave.

  • Quando um índice tem uma chave com vários tipos de dados, o índice é classificado de acordo com a ordem de classificação dos tipos de BSON.

  • Em comparações de arrays:

    • Uma comparação menor que, ou uma classificação ascendente, compara os menores elementos da array de acordo com a ordem de classificação do tipo de BSON.

    • Uma comparação maior que, ou uma classificação decrescente, compara os maiores elementos da array de acordo com a ordem de classificação inversa do tipo BSON.

    • Ao comparar um campo cujo valor é uma matriz de um elemento (por exemplo, [ 1 ]) com campos não-array (por exemplo, 2), a comparação é de 1 e 2.

    • Uma comparação de uma array vazia (exemplo, [ ]) considera a array vazia como menor que um valor de null ou um valor de campo ausente.

Veja oexemplo de classificação de índice .

Para usar um índice para comparações de strings, uma operação também deve especificar o mesmo agrupamento. Ou seja, um índice com ordenação não pode suportar uma operação que executa comparações de strings nos campos indexados se a operação especificar uma ordenação diferente.

Aviso

Porque os índices configurados com agrupamento usam ICU. chaves de agrupamento para obter a ordem de classificação, chaves de índice com reconhecimento de agrupamento pode ser maior do que as chaves de índice para índices sem agrupamento.

Por exemplo, a coleta myColl possui um índice em um campo de sequência category com o código do idioma de ordenação "fr".

db.myColl.createIndex( { category: 1 }, { collation: { locale: "fr" } } )

A seguinte operação de consulta, que especifica o mesmo agrupamento que o índice, pode usar o índice:

db.myColl.find( { category: "cafe" } ).collation( { locale: "fr" } )

No entanto, a seguinte operação de consulta, que por padrão usa o agrupador binário "simples", não pode usar o índice:

db.myColl.find( { category: "cafe" } )

Para um índice composto em que as chaves de prefixo do índice não são strings, matrizes e documentos incorporados, uma operação que especifica um agrupamento diferente ainda pode usar o índice para dar suporte a comparações nas chaves de prefixo do índice.

Por exemplo, a coleta myColl possui um índice composto nos campos numéricos score e price e no campo de string category; o índice é criado com a localidade de ordenação "fr" para comparações de strings:

db.myColl.createIndex(
{ score: 1, price: 1, category: 1 },
{ collation: { locale: "fr" } } )

As operações a seguir, que usam agrupamento binário "simple" para comparações de strings, podem usar o índice:

db.myColl.find( { score: 5 } ).sort( { price: 1 } )
db.myColl.find( { score: 5, price: { $gt: NumberDecimal( "10" ) } } ).sort( { price: 1 } )

A operação a seguir, que usa agrupamento binário "simple" para comparações de strings no campo category indexado, pode usar o índice para preencher apenas a parte score: 5 da query:

db.myColl.find( { score: 5, category: "cafe" } )

Importante

As correspondências com chaves de documentos, incluindo chaves de documentos incorporadas, usam uma comparação binária simples. Isto significa que uma query para uma chave como "foo.bár" não corresponderá à chave "foo.bar", independente do valor definido para o parâmetro de força.

O exemplo a seguir demonstra a classificação quando as chaves de índice têm os mesmos tipos ou tipos diferentes.

Crie a coleção keyTypes:

db.keyTypes.insertMany( [
{ seqNum: 1, seqType: null, type: "null" },
{ seqNum: 29, seqType: null, type: "null" },
{ seqNum: 2, seqType: Int32("10"), type: "Int32" },
{ seqNum: 28, seqType: Int32("10"), type: "Int32" },
{ seqNum: 3, seqType: Long("10"), type: "Long" },
{ seqNum: 27, seqType: Long("10"), type: "Long" },
{ seqNum: 4, seqType: Decimal128("10"), type: "Decimal128" },
{ seqNum: 26, seqType: Decimal128("10"), type: "Decimal128" },
{ seqNum: 5, seqType: Double("10"), type: "Double" },
{ seqNum: 25, seqType: Double("10"), type: "Double" },
{ seqNum: 6, seqType: String("10"), type: "String" },
{ seqNum: 24, seqType: String("10"), type: "String" },
{ seqNum: 7, seqType: [ "1", "2", "3" ], type: "Array" },
{ seqNum: 23, seqType: [ "1", "2", "3" ], type: "Array" },
{ seqNum: 8, seqType: [ [1], [2], [3] ], type: "Array" },
{ seqNum: 22, seqType: [ [1], [2], [3] ], type: "Array " },
{ seqNum: 9, seqType: [ 1, 2, 3 ], type: "Array" },
{ seqNum: 21, seqType: [ 1, 2, 3 ], type: "Array" },
{ seqNum: 10, seqType: true, type: "Boolean" },
{ seqNum: 11, seqType: new Timestamp(), type: "Timestamp" },
{ seqNum: 12, seqType: new Date(), type: "Date" },
{ seqNum: 13, seqType: new ObjectId(), type: "ObjectId" },
] )

Criar índices no número de sequência ( seqNum ) e tipo de sequência ( seqType ) campos:

db.keyTypes.createIndex( { seqNum: 1 } )
db.keyTypes.createIndex( { seqType: 1 } )

Faça a query da coleção usando find(). O documento de projeção, { _id: 0 }, suprime o campo _id na exibição de saída.

db.keyTypes.find( {}, { _id: 0 } )

Os documentos são devolvidos na ordem de inserção:

{ seqNum: 1, seqType: null, type: 'null' },
{ seqNum: 29, seqType: null, type: 'null' },
{ seqNum: 2, seqType: 10, type: 'Int32' },
{ seqNum: 28, seqType: 10, type: 'Int32' },
{ seqNum: 3, seqType: Long("10"), type: 'Long' },
{ seqNum: 27, seqType: Long("10"), type: 'Long' },
{ seqNum: 4, seqType: Decimal128("10"), type: 'Decimal128' },
// Output truncated

O índice de número de sequência ( seqNum ) tem valores do mesmo tipo. Utilize o índice seqNum para a query da collection keyTypes:

db.keyTypes.find( {}, { _id: 0 } ).sort( { seqNum: 1} )

As seqNum chaves são inteiros. Os documentos são devolvidos em ordem numérica:

{ seqNum: 1, seqType: null, type: 'null' },
{ seqNum: 2, seqType: 10, type: 'Int32' },
{ seqNum: 3, seqType: Long("10"), type: 'Long' },
{ seqNum: 4, seqType: Decimal128("10"), type: 'Decimal128' },
{ seqNum: 5, seqType: 10, type: 'Double' },
{ seqNum: 6, seqType: '10', type: 'String' },
{ seqNum: 7, seqType: [ '1', '2', '3' ], type: 'Array' },
// Output truncated

O índice do tipo de sequência ( seqType ) tem valores de diferentes tipos. Utilize o índice seqType para a query da collection keyTypes:

db.keyTypes.find( {}, { _id: 0 } ).sort( { seqType: 1} )

Os documentos são devolvidos em Ordem de classificação do tipo BSON:

{ seqNum: 1, seqType: null, type: 'null' },
{ seqNum: 29, seqType: null, type: 'null' },
{ seqNum: 9, seqType: [ 1, 2, 3 ], type: 'Array' },
{ seqNum: 21, seqType: [ 1, 2, 3 ], type: 'Array' },
{ seqNum: 2, seqType: 10, type: 'Int32' },
{ seqNum: 28, seqType: 10, type: 'Int32' },
{ seqNum: 3, seqType: Long("10"), type: 'Long' },
{ seqNum: 27, seqType: Long("10"), type: 'Long' },
{ seqNum: 4, seqType: Decimal128("10"), type: 'Decimal128' },
{ seqNum: 26, seqType: Decimal128("10"), type: 'Decimal128' },
{ seqNum: 5, seqType: 10, type: 'Double' },
{ seqNum: 25, seqType: 10, type: 'Double' },
{ seqNum: 7, seqType: [ '1', '2', '3' ], type: 'Array' },
{ seqNum: 23, seqType: [ '1', '2', '3' ], type: 'Array' },
{ seqNum: 6, seqType: '10', type: 'String' },
{ seqNum: 24, seqType: '10', type: 'String' },
{ seqNum: 8, seqType: [ [ 1 ], [ 2 ], [ 3 ] ], type: 'Array' },
{ seqNum: 22, seqType: [ [ 1 ], [ 2 ], [ 3 ] ], type: 'Array ' },
{
seqNum: 13,
seqType: ObjectId("6239e3922604d5a7478df071"),
type: 'ObjectId'
},
{ seqNum: 10, seqType: true, type: 'Boolean' },
{
seqNum: 12,
seqType: ISODate("2022-03-22T14:56:18.100Z"),
type: 'Date'
},
{
seqNum: 11,
seqType: Timestamp({ t: 1647960978, i: 1 }),
type: 'Timestamp'
}
  • Em comparações de arrays:

    • Uma comparação menor que, ou uma classificação ascendente, compara os menores elementos da array de acordo com a ordem de classificação do tipo de BSON.

    • Uma comparação maior que, ou uma classificação decrescente, compara os maiores elementos da array de acordo com a ordem de classificação inversa do tipo BSON.

    • Ao comparar um campo cujo valor é uma matriz de um elemento (por exemplo, [ 1 ]) com campos não-array (por exemplo, 2), a comparação é de 1 e 2.

    • Uma comparação de uma array vazia (exemplo, [ ]) considera a array vazia como menor que um valor de null ou um valor de campo ausente.

  • Tipos numéricos (Int32, Longo, Decimal128, Duplo) são equivalentes em comparação com outros tipos.

  • Dentro do tipo Numbers BSON, tipos numéricos são ordenados:

    • Int32

    • Longo

    • Decimal128

    • Duplo

← Crie índices para oferecer suporte a suas queries