Dzielenie na strony
Stronicowanie odnosi się do pobierania wyników na stronach, a nie wszystkich jednocześnie; Zazwyczaj odbywa się to w przypadku dużych zestawów wyników, w których jest wyświetlany interfejs użytkownika, który umożliwia użytkownikowi przejście do następnej lub poprzedniej strony wyników.
Ostrzeżenie
Niezależnie od używanej metody stronicowania zawsze upewnij się, że zamówienie jest w pełni unikatowe. Jeśli na przykład wyniki są uporządkowane tylko według daty, ale może istnieć wiele wyników z tą samą datą, wyniki można pominąć podczas stronicowania, ponieważ są one uporządkowane inaczej w dwóch zapytaniach stronicowania. Kolejność według daty i identyfikatora (lub dowolnej innej unikatowej właściwości lub kombinacji właściwości) sprawia, że kolejność jest w pełni unikatowa i pozwala uniknąć tego problemu. Należy pamiętać, że relacyjne bazy danych domyślnie nie stosują żadnych zamówień, nawet w kluczu podstawowym.
Stronicowanie przesunięcia
Typowym sposobem implementacji stronicowania z bazami danych jest użycie elementu Skip i Take (OFFSET i LIMIT w języku SQL). Biorąc pod uwagę rozmiar strony 10 wyników, trzecią stronę można pobrać z platformą EF Core w następujący sposób:
var position = 20;
var nextPage = context.Posts
.OrderBy(b => b.PostId)
.Skip(position)
.Take(10)
.ToList();
Niestety, chociaż ta technika jest bardzo intuicyjna, ma również pewne poważne wady:
- Baza danych musi nadal przetwarzać pierwsze 20 wpisów, nawet jeśli nie zostaną one zwrócone do aplikacji; Powoduje to prawdopodobnie znaczne obciążenie obliczeniowe, które zwiększa się wraz z liczbą pominiętych wierszy.
- Jeśli jakiekolwiek aktualizacje są wykonywane współbieżnie, stronicowanie może spowodować pominięcie niektórych wpisów lub wyświetlenie ich dwa razy. Jeśli na przykład wpis zostanie usunięty, ponieważ użytkownik przechodzi ze strony 2 do 3, cały zestaw wyników "przesuwa się w górę", a jeden wpis zostanie pominięty.
Stronicowanie zestawu kluczy
Zalecaną alternatywą dla stronicowania opartego na przesunięciach — czasami nazywaną stronicacją zestawu kluczy lub stronicacjąopartą na wyszukiwaniu — jest po prostu użycie WHERE klauzuli do pomijania wierszy zamiast przesunięcia. Oznacza to, że należy pamiętać odpowiednie wartości z ostatniego pobranego wpisu (zamiast przesunięcia) i poprosić o kolejne wiersze po tym wierszu. Na przykład przy założeniu, że ostatni wpis na ostatniej pobranej stronie miał wartość identyfikatora 55, po prostu wykonalibyśmy następujące czynności:
var lastId = 55;
var nextPage = context.Posts
.OrderBy(b => b.PostId)
.Where(b => b.PostId > lastId)
.Take(10)
.ToList();
Przy założeniu, że indeks jest zdefiniowany w metodzie PostId, to zapytanie jest bardzo wydajne, a także nie jest wrażliwe na żadne współbieżne zmiany w niższych wartościach identyfikatorów.
Stronicowanie zestawu kluczy jest odpowiednie dla interfejsów stronicowania, w których użytkownik przechodzi do przodu i do tyłu, ale nie obsługuje dostępu losowego, gdzie użytkownik może przejść do dowolnej konkretnej strony. Stronicowanie dostępu losowego wymaga użycia stronicowania przesunięcia, jak wyjaśniono powyżej; z powodu niedociągnięć stronicowania przesunięcia należy dokładnie rozważyć, czy w przypadku użycia jest naprawdę wymagane losowe stronicowanie dostępu lub czy nawigacja na następnej/poprzedniej stronie jest wystarczająca. Jeśli konieczne jest stronicowanie dostępu losowego, niezawodna implementacja może użyć stronicowania zestawu kluczy podczas nawigacji do następnej/poprzedniej strony i przesunięcia nawigacji podczas przechodzenia do dowolnej innej strony.
Wiele kluczy stronicowania
W przypadku korzystania z stronicowania zestawu kluczy często jest konieczne zamówienie przez więcej niż jedną właściwość. Na przykład następujące zapytanie stronicuje według daty i identyfikatora:
var lastDate = new DateTime(2020, 1, 1);
var lastId = 55;
var nextPage = context.Posts
.OrderBy(b => b.Date)
.ThenBy(b => b.PostId)
.Where(b => b.Date > lastDate || (b.Date == lastDate && b.PostId > lastId))
.Take(10)
.ToList();
Dzięki temu następna strona zostanie wybrana dokładnie tam, gdzie zakończyła się poprzednia strona. W miarę dodawania większej liczby kluczy porządkowania można dodać dodatkowe klauzule.
Uwaga
Większość baz danych SQL obsługuje prostszą i wydajniejszą wersję powyższych, używając wartości wierszy: WHERE (Date, Id) > (@lastDate, @lastId). Program EF Core nie obsługuje obecnie wyrażania tego w zapytaniach LINQ. Jest to śledzone przez środowisko #26822.
Indeksy
Podobnie jak w przypadku innych zapytań, prawidłowe indeksowanie ma kluczowe znaczenie dla dobrej wydajności: upewnij się, że indeksy mają miejsce, które odpowiadają kolejności stronicowania. Jeśli kolejność jest uporządkowana przez więcej niż jedną kolumnę, można zdefiniować indeks na tych wielu kolumnach; jest to nazywane indeksem złożonym.
Aby uzyskać więcej informacji, zobacz stronę dokumentacji w indeksach.
Zasoby dodatkowe
- Aby dowiedzieć się więcej na temat niedociągnięć stronicowania opartego na przesunięciach i stronicowania zestawu kluczy, zobacz ten wpis.
- Sesja standupu społeczności danych platformy .NET , w której omawiamy stronicowanie i pokaz wszystkich powyższych pojęć.
- Techniczna głęboka prezentacja nurkowa porównująca przesunięcie i stronicowanie zestawu kluczy. Chociaż zawartość dotyczy bazy danych PostgreSQL, ogólne informacje są prawidłowe również dla innych relacyjnych baz danych.
- Aby uzyskać rozszerzenia na platformie EF Core, które upraszczają stronicowanie zestawu kluczy, zobacz MR. EntityFrameworkCore.KeysetPagination i MR. AspNetCore.Pagination.