Podział na strony i Struktura bytów

0

Pytanie

W swojej aplikacji mobilnej staram się usuwać dane z tabeli bazy danych programu SQL Server. Używam EF i staram się stosować podział na strony do zwiększenia wydajności. Muszę wyciągnąć dane z ostatniej pozycji w tabeli. dlatego, jeśli w tabeli 20 wierszy, potrzebuję do strony 0 identyfikatory 20, 19, 18, 17, 16, następnie do strony 1 identyfikatory 15, 14, 13, 12, 11 i tak dalej...

Problem w tym, że: a co, jeśli, dopóki użytkownik "A" pobiera dane z tabeli użytkownik "B" dodaje się wiersz? Jeśli użytkownik A otrzyma stronę 0 (tak, że identyfikatory 20, 19, 18, 17, 16), użytkownik "B" w tym samym momencie doda wiersz (tak, że identyfikator 21), za pomocą klasycznego zapytania użytkownik "A" do strony 1 otrzymuje identyfikatory 16, 15, 14, 13, 12... więc innym razem ID 16

Mój kod jest bardzo prosty:

int RecordsForPagination = 5; 
var list = _context.NameTable
                   .Where(my_condition)
                   .OrderByDescending(my_condition_for ordering)
                   .Skip (RecordsForPagination * Page)
                   .Take (RecordsForPagination)
                   .ToList();

Oczywiście Page to int, które pochodzą z interfejsu.

Jak mogę rozwiązać ten problem?

Znalazłem rozwiązanie, ale nie wiem, czy jest ono idealne. Mógłbym użyć

.SkipWhile(x => x.ID >= LastID) 

zamiast

.Skip (RecordsForPagination * Page)

i oczywiście LastID zawsze wywoływane z interfejsu.

Jak myślicie, czy zawsze z tym kodem dobra wydajność? Czy jest lepsze rozwiązanie?

entity-framework linq sql-server
2021-11-22 23:06:34
1

Najlepsza odpowiedź

1

Wpływ na wydajność będzie w dużej mierze zależeć od realizacji wskaźnika SQL i order by. Ale chodzi nie tyle o wydajności, ile o uzyskanie oczekiwanych rezultatów.

Przepełnienie stosu-świetny przykład, kiedy występuje taka ilość aktywności, że kiedy starasz się dojść do końca każdej strony, następna strona może zawierać wpisy ze strony, którą właśnie patrzył, bo podstawowy zestaw rekordów zmienił (dodano więcej rekordów).

Podnoszę tę kwestię, bo w systemie żywo to wspólne, a w niektórych przypadkach oczekiwane zachowanie. Jak deweloperzy, będziemy wdzięczni za dodatkowe koszty związane z próbami utrzymania jeden zestaw wyników, i uznajemy, że zwykle o wiele mniejsze znaczenie ma próba zapobieżenia coś, co wygląda jak kopia lustrzana przy powtarzaniu stron.

Często wystarczy wyjaśnić użytkownikom, dlaczego tak się dzieje, w wielu przypadkach są to wezmą

Jeśli dla ciebie było ważne, aby utrzymać miejsce w oryginalnym zestawie wyników, to należy ograniczyć zapytanie Where oferta, ale trzeba będzie uzyskać lub identyfikator, albo znacznik czasu w oryginalnej odpowiedzi. W twoim przypadku próbujesz użyć LastIDale aby uzyskać ostatniego identyfikatora, wymagany jest oddzielny własne żądanie, bo oferta orderby wpłynie na niego.

Naprawdę nie można użyć .SkipWhile(x => x.ID >= LastID) do tego, ponieważ przepustkę-jest to szeregowy proces, na który wpływa kolejność, a on wyłącza się w pierwszym egzemplarzu, który obliczany jest wyrazem falsedlatego, jeśli twoje zamówienie nie opiera się na Idtwoja przepustka natomiast może prowadzić do pomijania żadnych wpisów.

int RecordsForPagination = 5; 
int? MaxId = null;
...
var query = _context.NameTable.Where(my_condition);
// We need the Id to constraint the original search
if (!MaxId.HasValue)
    MaxId = query.Max(x => x.ID);

var list = query.Where(x => x.ID <= MaxId)
                .OrderByDescending(my_condition_for ordering)
                .Skip(RecordsForPagination * Page)
                .Take(RecordsForPagination);
                .ToList();

Zazwyczaj łatwiej filtrować według czasu, tak jak to wiadomo od klienta bez powrotu do bazy danych, ale w zależności od realizacji filtrowanie według dat może być mniej skuteczne.

2021-11-22 23:55:04

Moim zamiarem nie było wyodrębnić lastID z BAZY danych (bo, jak powiedział, na to wpłynęła by sama baza danych). mój zamiar składać w następujący sposób: - Interfejs pobiera stronę 0, a wynik-identyfikatory 20, 19, 18, 17, 16 - Interfejs pobiera stronę 1 i przekazuje backend dwa parametry: Strona 1 i ostatni identyfikator z poprzedniej strony (w tym przypadku ostatni = 16) -> w ten sposób, wynikiem będą identyfikatory 15, 14, 13, 12, 11... i tak dalej. mój angielski nie jest idealny... mówimy jedno i to samo?
user1106897

@user1106897 Metoda, na który powołuje się Chris, nazywa się podziałem zestawu kluczy na strony i zazwyczaj o wiele lepiej, niż podział na wierszach, o czym wy mówicie
Charlieface

To również bardzo ważne dla wydajności: podział na strony wierszami jest bardzo nieefektywne, tak jak wszystkie poprzednie polecenia trzeba za każdym razem odczytywać. Podczas gdy pompowanie przez klucz (lub według czasu (w tym przypadku) jest bardzo skuteczna, jeśli jest wspierający indeks
Charlieface

Charlie Face dziękuję bardzo za link, bardzo wdzięczny. Postaram się skorzystać z rad
user1106897

Dziękuję @Charlieface informacja o wydajności więcej powinno brzmieć tak: "zapomnij o wydajności, pomijanie(według identyfikatora) nie rozwiąże problemu, jeśli zmień zamówienie" Świetny link też!
Chris Schaller

W innych językach

Ta strona jest w innych językach

Русский
..................................................................................................................
Italiano
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................