Użycie danych buforowanych na etapie sortowania z przepełnieniem przekracza wewnętrzny limit


85

Korzystanie z kodu:

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

print all_reviews[0]
print all_reviews[2000000]

Licznik drukuje 2043484i drukuje all_reviews[0].

Jednak podczas drukowania pojawia all_reviews[2000000]się błąd:

pymongo.errors.OperationFailure: błąd bazy danych: błąd runnera: przepełnienie buforowane użycie danych na etapie sortowania 33554495 bajtów przekracza wewnętrzny limit 33554432 bajtów

Jak sobie z tym radzę?

Odpowiedzi:


118

Przekraczasz limit 32 MB podczas sortowania w pamięci:

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

Dodaj indeks do pola sortowania. Dzięki temu MongoDB może przesyłać strumieniowo dokumenty do Ciebie w posortowanej kolejności, zamiast próbować ładować je wszystkie do pamięci na serwerze i sortować w pamięci przed wysłaniem ich do klienta.


7
Lepiej jest zadeklarować indeks, aby nie trzeba było sortować w pamięci RAM: szybsze i bardziej niezawodne, ograniczone użycie pamięci RAM zamiast potencjalnie nieograniczone. Jeśli nalegasz, zamień swoje „find” na agregację (która może użyć 100 MB pamięci RAM do sortowania) i ustaw opcję allowDiskUse: true, aby nakazać strukturze agregacji rozlanie się na dysk, jeśli przekroczy 100 MB pamięci RAM. Spodziewaj się poważnego spadku wydajności w porównaniu do zadeklarowania odpowiedniego indeksu. docs.mongodb.org/manual/reference/operator/aggregation/sort/ ...
A. Jesse Jiryu Davis,

31
Właściwie można to zmienić. Trzeba uruchomić polecenie: db.adminCommand({setParameter: 1, internalQueryExecMaxBlockingSortBytes: <limit in bytes>}). Źródło: askubuntu.com/questions/501937/ ...
kumarharsh

6
Warto zauważyć dla użytkowników mangusty, że ustawienie index: true na rekwizycie w schemacie naprawi ten problem ... mongoose przejdzie przez wszystkie twoje schematy i upewni się, że pola są w rzeczywistości indeksami przed uruchomieniem aplikacji ... to znaczy chyba, że wyłączasz to zachowanie za pomocą mySchema.set ('autoIndex', false);
Benjamin Conant

2
Utworzyłem indeks na polu sortowania, ale nadal daje mi ten błąd "Operacja sortowania wykorzystała więcej niż maksymalne 33554432 bajty pamięci RAM" może być spowodowane tym, że stosuję operację dopasowania przed sortowaniem i zgodnie z dokumentem mongo, jeśli używasz dopasowania przed sortowaniem operacja pominie indeks i przeprowadzi sortowanie w pamięci po wszystkich dopasowanych rekordach.
Amol Suryawanshi

11
Jeśli jest to akceptowana odpowiedź, to powinna zawierać informację, jak dodać indeks.
Philipp Ludwig

45

Jak powiedział kumar_harshw sekcji komentarzy, chciałbym dodać kolejny punkt.

Możesz wyświetlić bieżące użycie bufora za pomocą poniższego polecenia w adminbazie danych:

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

Ma domyślną wartość 32 MB (33554432 bajtów) W tym przypadku brakuje danych w buforze, więc możesz zwiększyć limit bufora o zdefiniowaną przez siebie optymalną wartość, na przykład 50 MB, jak poniżej:

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

Możemy również ustawić ten limit na stałe za pomocą poniższego parametru w pliku konfiguracyjnym mongodb:

setParameter=internalQueryExecMaxBlockingSortBytes=309715200

Mam nadzieję że to pomoże !!!

Note: To polecenie jest obsługiwane tylko po wersji 3.0 +


W jaki sposób można ustawić ten limit na stałe w pliku konfiguracyjnym? Mam maszynę z pamięcią 1 TB dedykowaną do mongo i chciałbym ją na stałe podkręcić.
Samantha Atkins

@SamanthaAtkins Zaktualizowałem odpowiedź, aby ustawić ją na stałe w pliku konfiguracyjnym.
JERRY

@JERRY gdzie ustawić na stałe w szynach. Szyny 5 / mongoid.yml?
Prateep Kul

Znalazłem to. uruchom na moim terminalu z: mongod i postępuj zgodnie z instrukcją zocada.com/setting-mongodb-users-beginners-guide
Prateep Kul

24

rozwiązany z indeksowaniem

db_handle.ensure_index([("reviewDate", pymongo.ASCENDING)])

pamiętaj, aby nie używać rzadkiego indeksu, są one ignorowane, jeśli posortujesz według każdego dokumentu
Charly Koza

15

Jeśli chcesz uniknąć tworzenia indeksu (np. Chcesz po prostu szybko sprawdzić dane), możesz użyć agregacji z wykorzystaniem dysku:

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

(Nie wiem jednak, jak to zrobić w pymongo).


W pymongo byłoby db_handle.aggregate(pipe, allowDiskUse=True). Zobacz to pytanie, aby uzyskać więcej informacji!
Genarito

3

Składnia JavaScript API dla indeksu:

db_handle.ensureIndex({executedDate: 1})

2

W moim przypadku konieczne było poprawienie niezbędnych indeksów w kodzie i odtworzenie ich:

rake db:mongoid:create_indexes RAILS_ENV=production

Ponieważ przepełnienie pamięci nie występuje, gdy istnieje potrzebny indeks pola.

PS Wcześniej musiałem wyłączyć błędy przy tworzeniu długich indeksów:

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

Może być również potrzebny 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() } )
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.