2011-11-23 11 views
10

Używam serwera MongoDB (to dosłownie wszystko, co działa). Serwer ma 64 gb pamięci RAM i 16 rdzeni oraz 2 TB miejsca na dysku twardym do pracy.Nieuzasadnione powolne zapytanie MongoDB, mimo że zapytanie jest proste i dostosowane do indeksów

Struktura dokumentu

Baza posiada kolekcję domains z około 20 milionów dokumentów. Jest przyzwoita ilość danych w każdym dokumencie, ale dla naszych celów, dokument jest skonstruowany w taki sposób:

{ 
    _id: "abcxyz.com", 
    LastUpdated: <date>, 
    ... 
} 

Pole _id to nazwa domeny odwołuje się do dokumentu. Na LastUpdated znajduje się indeks rosnący. LastUpdated jest aktualizowany na setkach tysięcy rekordów dziennie. Zasadniczo za każdym razem, gdy nowe dane stają się dostępne dla dokumentu, dokument jest aktualizowany, a pole LastUpdated aktualizowane do aktualnej daty/czasu.

Query

mam mechanizm, który pobiera dane z bazy danych, więc może być indeksowany w indeksie Lucene. Pole LastUpdated jest kluczowym narzędziem do zgłaszania zmian wprowadzonych w dokumencie. W celu wyszukiwania dokumentów, które zostały zmienione i stronie przez tych dokumentów, mam następujące:

{ 
    LastUpdated: { $gte: ISODate(<firstdate>), $lt: ISODate(<lastdate>) }, 
    _id: { $gt: <last_id_from_previous_page> } 
} 

sort: { $_id:1 } 

Kiedy są zwracane żadne dokumenty, daty rozpoczęcia i zakończenia iść do przodu i „kotwica” pola _id jest resetowany . Ta konfiguracja jest tolerancyjna dla dokumentów z poprzednich stron, które zmieniły swoją wartość LastUpdated, tzn. Stronicowanie nie zostanie niepoprawnie zrekompensowane przez liczbę dokumentów na poprzednich stronach, które są obecnie technicznie nieaktualne na tych stronach.

Problem

Chcę idealnie wybrać około 25.000 dokumentów na raz, ale z jakiegoś powodu sam query (nawet jeśli tylko wybierając < 500 dokumentów) jest niezwykle powolny.

Zapytanie wpadłem było:

db.domains.find({ 
    "LastUpdated" : { 
     "$gte" : ISODate("2011-11-22T15:01:54.851Z"), 
     "$lt" : ISODate("2011-11-22T17:39:48.013Z") 
    }, 
    "_id" : { "$gt" : "1300broadband.com" } 
}).sort({ _id:1 }).limit(50).explain() 

To jest tak powolny, że w rzeczywistości wyjaśnić (w chwili pisania tego) został uruchomiony przez ponad 10 minut, a nie została jeszcze zakończona. Będę aktualizować to pytanie, jeśli kiedykolwiek się skończy, ale chodzi o to, że zapytanie jest bardzo powolne.

Co mogę zrobić? Nie mam najmniejszego pojęcia, jaki może być problem z zapytaniem.

EDYCJA Objaśnienie zakończyło się po 55 minutach. Oto ona:

{ 
    "cursor" : "BtreeCursor Lastupdated_-1__id_1", 
    "nscanned" : 13112, 
    "nscannedObjects" : 13100, 
    "n" : 50, 
    "scanAndOrder" : true, 
    "millis" : 3347845, 
    "nYields" : 5454, 
    "nChunkSkips" : 0, 
    "isMultiKey" : false, 
    "indexOnly" : false, 
    "indexBounds" : { 
      "LastUpdated" : [ 
        [ 
          ISODate("2011-11-22T17:39:48.013Z"), 
          ISODate("2011-11-22T15:01:54.851Z") 
        ] 
      ], 
      "_id" : [ 
        [ 
          "1300broadband.com", 
          { 

          } 
        ] 
      ] 
    } 
} 

Odpowiedz

0

Czy próbowałeś dodać dodawanie _id do indeksu kompozytowego. Ponieważ używasz go jako części kwerendy, czy nadal nie musisz wykonywać pełnego skanowania tabeli?

+0

Mam złożony indeks LastApdated (asc) i _id (desc). Czy to odpowiedni indeks do użycia? –

7

OK Rozwiązałem problem. Winowajcą była "scanAndOrder": true, co sugerowało, że indeks nie był używany zgodnie z przeznaczeniem. Prawidłowy indeks złożony ma najpierw pole pierwszego sortowania, a następnie pytane pola.

{ "_id":1, "LastUpdated":1 } 
+1

jak zmieniło się zużycie pamięci, gdy masz inny indeks z dodatkowym polem? – kommradHomer

+0

@kommradHomer Przepraszam, nie pamiętam; pytanie jest ponad trzy lata –

12

wpadł na bardzo podobnym problemem, a Indexing Advice and FAQ na Mongodb.org mówi, cytuję:

Zapytanie zakres musi być również ostatnia kolumna w indeksie

So jeśli masz klucze a, b i c oraz uruchom db.ensureIndex ({a: 1, b: 1, c: 1}), są to "wskazówki" w celu jak najlepszego wykorzystania indeksu:

Dobrze:

  • znaleźć (a = 1, b> 2)

  • znaleźć (a> 1 i < 10)

  • znaleźć (a> 1 i < 10) .sort ()

Źle:

  • znaleźć (a> 1, b = 2)

stosować tylko zapytania zakres lub sortowania na kolumnie. Dobre: ​​

  • znaleźć (a = 1, b = 2) .sort (C)

  • znaleźć (a = 1, b> 2)

  • znaleźć (a = 1, b> 2 b < 4)

  • znaleźć (a = 1, b> 2) .sort (b)

Zła:

  • znaleźć (a> 1, b> 2)

  • znaleźć (a = 1, b> 2) .sort (C)

nadzieję, że pomaga!

/J

+0

, ale w dokumentach mówi, że to nie ma zastosowania do mongodb 1.6.0+; i używam wersji 2.0.6 i nadal mam ten sam problem. –

+2

Cóż, to powinno, lub oni twierdzą, że po prostu łamią "prawa fizyki", jeśli chodzi o zapytania za pomocą B-drzew w ogóle. –

+0

używaliśmy indeksu jako "c, a, b" i robiąc find (a = x, b = y).sort (c), który zajmował około 1000 ms, a następnie użyłem indeksu "a, b, c", i zaczęto przyjmować 0 ms – kommradHomer