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:

  1. 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.
  2. 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