Jest powolny, ponieważ musi zlokalizować górne offset
wierszy i zeskanuj następne 100. Żadna ilość optymalizacji nie zmieni tego, gdy masz do czynienia z dużymi przesunięciami.
Dzieje się tak, ponieważ Twoje zapytanie dosłownie instruuje silnik DB do odwiedzania wielu wierszy za pomocą offset 3900000
-- to 3,9 mln rzędów. Nie ma wielu opcji, aby to nieco przyspieszyć.
Superszybka pamięć RAM, dyski SSD itp. Pomogą. Ale zyskasz tylko stały czynnik, robiąc to, co oznacza, że po prostu kopiesz puszkę w dół, aż osiągniesz wystarczająco duże przesunięcie.
Upewnienie się, że stół mieści się w pamięci, a dużo więcej do stracenia, również pomoże przez większy stały współczynnik — z wyjątkiem pierwszego razu. Ale może to nie być możliwe przy wystarczająco dużej tabeli lub indeksie.
Upewnienie się, że wykonujesz skanowanie tylko z indeksem, będzie działać do pewnego stopnia. (Patrz odpowiedź velisa; ma to wiele zalet.) Problem polega na tym, że ze względów praktycznych można myśleć o indeksie jako o tabeli przechowującej lokalizację dysku i pola indeksowane. (Jest bardziej zoptymalizowany, ale jest to rozsądne pierwsze przybliżenie.) Przy wystarczającej liczbie wierszy nadal będziesz mieć problemy z odpowiednio większym przesunięciem.
Próba przechowywania i utrzymywania dokładnej pozycji rzędów również jest kosztownym podejściem (sugeruje to np. benjist). Chociaż jest to technicznie wykonalne, ma ograniczenia podobne do tych, które wynikają z używania MPTT ze strukturą drzewa:zyskasz znacznie na odczytach, ale skończysz z nadmiernymi czasami zapisu, gdy węzeł zostanie wstawiony, zaktualizowany lub usunięty w taki sposób, że duże fragmenty danych muszą zostać zaktualizowane razem.
Miejmy nadzieję, że jest to bardziej jasne, że nie ma żadnej prawdziwej magicznej kuli, gdy masz do czynienia z tak dużymi przesunięciami. Często lepiej przyjrzeć się alternatywnym podejściom.
Jeśli tworzysz strony na podstawie identyfikatora (lub pola daty lub dowolnego innego indeksowanego zestawu pól), potencjalną sztuczką (używaną na przykład przez blogspot) byłoby sprawienie, aby zapytanie zaczynało się w dowolnym punkcie indeksu.
Innymi słowy, zamiast:
example.com?page_number=[huge]
Zrób coś takiego:
example.com?page_following=[huge]
W ten sposób zachowujesz ślad, gdzie jesteś w indeksie, a zapytanie staje się bardzo szybkie, ponieważ może skierować się prosto do właściwego punktu początkowego bez przedzierania się przez miliard wierszy:
select * from foo where ID > [huge] order by ID limit 100
Naturalnie tracisz możliwość skakania m.in. strona 3000. Ale zastanów się szczerze:kiedy ostatnio przeskoczyłeś do ogromnego numeru strony w witrynie zamiast od razu przejść do jej miesięcznych archiwów lub skorzystać z pola wyszukiwania?
Jeśli przeglądasz strony, ale chcesz w jakikolwiek sposób zachować przesunięcie strony, innym podejściem jest zabronienie używania większej liczby stron. To nie jest głupie:to właśnie robi Google z wynikami wyszukiwania. Podczas wyszukiwania zapytania Google podaje szacunkową liczbę wyników (możesz uzyskać rozsądną liczbę za pomocą explain
), a następnie pozwoli Ci przejrzeć kilka tysięcy najlepszych wyników – nic więcej. Robią to między innymi ze względu na wydajność — dokładnie tę, na którą się natkniesz.