Usar índices para classificar os resultados da query
Nesta página
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 MB de memória para um estágio de execução de pipeline, o MongoDB gravará automaticamente arquivos temporárias em disco, a menos que essa consulta especifique { allowDiskUse: false }
. Se o servidor precisar de mais de 100 MB de memória do sistema para a operação de block block sort , o MongoDB retornará um erro, a menos que essa consulta especifique cursor.allowDiskUse()
. Para obter 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.
Classificar com um índice de campo único
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 } )
Classificar em Vários Campos
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}
.
Prefixo de classificação e índice
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 | Index Prefix |
---|---|
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.
Classificação e subconjunto sem prefixo de um índice
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 | Index Prefix |
---|---|
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.
Ordem de Classificação dos Índices
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 classificação ascendente compara os menores elementos da array de acordo com a ordem de classificação do tipo de BSON.
Uma classificação decrescente compara os maiores elementos da array de acordo com a ordem de classificação inversa do tipo BSON.
Operadores de query de comparação , como
$lt
e$gt
, realizam comparações em arrays lexicograficamente.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 é de1
e2
.Uma comparação de uma array vazia (por exemplo,
[ ]
) considera a array vazia como menor que um valor denull
ou um valor de campo ausente.Uma comparação de uma array aninhada (por exemplo,
[[1, 2], [3, 4]]
) compara qualquer array após a array mais externa lexicograficamente.
Consulte o exemplo declassificação de índice .
Uso do Índice e Agrupamento
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.
Exemplos
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 classificação ascendente compara os menores elementos da array de acordo com a ordem de classificação do tipo de BSON.
Uma classificação decrescente compara os maiores elementos da array de acordo com a ordem de classificação inversa do tipo BSON.
Operadores de query de comparação , como
$lt
e$gt
, realizam comparações em arrays lexicograficamente.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 é de1
e2
.Uma comparação de uma array vazia (por exemplo,
[ ]
) considera a array vazia como menor que um valor denull
ou um valor de campo ausente.Uma comparação de uma array aninhada (por exemplo,
[[1, 2], [3, 4]]
) compara qualquer array após a array mais externa lexicograficamente.
Tipos numéricos (Int32, Longo, Decimal128, Double) são equivalentes em comparação com outros tipos.
Dentro do tipo Numbers BSON, tipos numéricos são ordenados:
Int32
Long
Decimal128
Double