O uso de dados em buffer do estágio de classificação de estouro excede o limite interno

85

Usando o código:

all_reviews = db_handle.find().sort('reviewDate', pymongo.ASCENDING)
print all_reviews.count()

print all_reviews[0]
print all_reviews[2000000]

A contagem é impressa 2043484e impressa all_reviews[0].

No entanto, ao imprimir all_reviews[2000000], recebo o erro:

pymongo.errors.OperationFailure: erro do banco de dados: Erro do executor: O uso de dados em buffer do estágio de classificação de estouro de 33554495 bytes excede o limite interno de 33554432 bytes

Como faço para lidar com isso?

sheetal_158
fonte

Respostas:

119

Você está atingindo o limite de 32 MB em uma classificação na memória:

https://docs.mongodb.com/manual/reference/limits/#Sort-Operations

Adicione um índice ao campo de classificação. Isso permite que o MongoDB transmita documentos para você em ordem de classificação, em vez de tentar carregá-los todos na memória do servidor e classificá-los na memória antes de enviá-los ao cliente.

A. Jesse Jiryu Davis
fonte
7
Melhor declarar um índice para que você não precise classificar na RAM: mais rápido e mais confiável, uso de RAM limitado em vez de potencialmente ilimitado. Se você insistir, transforme seu "find" em uma agregação (que pode usar 100 MB de RAM para classificar) e defina allowDiskUse: true para informar a estrutura de agregação para vazar para o disco se exceder 100 MB de RAM. Espere uma grave penalidade de desempenho em comparação com apenas declarar um índice apropriado. docs.mongodb.org/manual/reference/operator/aggregation/sort/…
A. Jesse Jiryu Davis
32
Na verdade, ele pode ser alterado. Você precisa executar o comando: db.adminCommand({setParameter: 1, internalQueryExecMaxBlockingSortBytes: <limit in bytes>}). Fonte: askubuntu.com/questions/501937/…
kumarharsh
6
É bom observar para os usuários do mangusto que definir index: true no prop em seu esquema corrigirá esse problema ... o mongoose examinará todos os seus esquemas e garantirá que os campos sejam de fato índices antes de iniciar o aplicativo ... ou seja, a menos você desativa esse comportamento com mySchema.set ('autoIndex', false);
Benjamin Conant
2
Eu criei um índice no campo de classificação, mas ele ainda me dando este erro "A operação de classificação usou mais do que o máximo de 33554432 bytes de RAM" pode ser porque estou aplicando a operação de correspondência antes da classificação e de acordo com o mongo doc se você usar correspondência antes da classificação operação ele irá negligenciar o índice e realizar na classificação da memória em todos os registros correspondentes.
Amol Suryawanshi
11
Se esta for a resposta aceita, deve incluir informações sobre como adicionar um índice.
Philipp Ludwig
46

Como disse kumar_harshna seção de comentários, gostaria de acrescentar outro ponto.

Você pode ver o uso atual do buffer usando o comando abaixo no adminbanco de dados:

> use admin
switched to db admin
> db.runCommand( { getParameter : 1, "internalQueryExecMaxBlockingSortBytes" : 1 } )
{ "internalQueryExecMaxBlockingSortBytes" : 33554432, "ok" : 1 }

Ele tem um valor padrão de 32 MB (33554432 bytes) . Nesse caso, você está ficando sem dados do buffer, então pode aumentar o limite do buffer com seu próprio valor ideal definido, por exemplo, 50 MB conforme abaixo:

>  db.adminCommand({setParameter: 1, internalQueryExecMaxBlockingSortBytes:50151432})
{ "was" : 33554432, "ok" : 1 }

Também podemos definir esse limite permanentemente pelo parâmetro abaixo no arquivo de configuração mongodb:

setParameter=internalQueryExecMaxBlockingSortBytes=309715200

Espero que isto ajude !!!

Note: Este comando suporta apenas após a versão 3.0 +

JERRY
fonte
Qual é a maneira de definir este limite permanentemente no arquivo de configuração? Tenho uma máquina de memória de 1 TB dedicada ao mongo e gostaria de ativá-la permanentemente.
Samantha Atkins
@SamanthaAtkins Eu atualizei a resposta para definir isso permanentemente no arquivo de configuração.
JERRY
@JERRY onde definir permanentemente nos trilhos. Rails 5 / mongoid.yml?
Prateep Kul
Eu encontrei. corra no meu terminal com: mongod e siga o manual zocada.com/setting-mongodb-users-beginners-guide
Prateep Kul
24

resolvido com indexação

db_handle.ensure_index([("reviewDate", pymongo.ASCENDING)])
sheetal_158
fonte
certifique-se de não usar um índice esparso, eles são ignorados se você classificar em todos os documentos
Charly Koza
15

Se você deseja evitar a criação de um índice (por exemplo, deseja apenas uma verificação rápida e suja para explorar os dados), pode usar a agregação com o uso do disco:

all_reviews = db_handle.aggregate([{$sort: {'reviewDate': 1}}], {allowDiskUse: true})

(Não tenho certeza de como fazer isso em pymongo, no entanto).

poroszd
fonte
Em pymongo seria db_handle.aggregate(pipe, allowDiskUse=True). Veja esta pergunta para mais informações!
Genarito
3

Sintaxe da API JavaScript para o índice:

db_handle.ensureIndex({executedDate: 1})
wytten
fonte
2

No meu caso, foi necessário corrigir os índices necessários no código e recriá-los:

rake db:mongoid:create_indexes RAILS_ENV=production

Como o estouro de memória não ocorre quando há um índice de campo necessário.

PS Antes disso, eu tinha que desabilitar os erros ao criar índices longos:

# mongo
MongoDB shell version: 2.6.12
connecting to: test
> db.getSiblingDB('admin').runCommand( { setParameter: 1, failIndexKeyTooLong: false } )

Também pode ser necessário reIndex:

# mongo
MongoDB shell version: 2.6.12
connecting to: test
> use your_db
switched to db your_db
> db.getCollectionNames().forEach( function(collection){ db[collection].reIndex() } )
Shilovk
fonte