Stránkování a Entity Framework

0

Otázka

Ve své mobilní aplikaci, snažím se načíst data z tabulky z mé databáze serveru SQL Server. Používám EF a zkuste použít stránkování pro lepší výkon. Potřebuji načíst data z poslední prvek tabulky. takže pokud má tabulka 20 řádků, potřebuji, pro stránku 0, Id 20, 19, 18, 17, 16 pak pro stránka 1 Id 15, 14, 13, 12, 11 a tak dále...

Problém je tento: co když, zatímco uživatel "A" stahování dat z tabulky, uživatel "B" přidat řádek? Pokud uživatel "A" získat Stránky 0 (takže Id 20, 19, 18, 17, 16), a uživatel "B" ve stejné chvíli přidat řádek (takže ID 21), s klasickým dotazu, uživatel "A" pro stránku 1 bude mít IDs 16, 15, 14, 13, 12... takže další čas, ID 16

Můj kód je velmi jednoduchý:

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

Samozřejmě Page je int, které přicházejí z rozhraní.

Jak mohu vyřešit problém?

Našel jsem řešení, ale nevím, jestli je to ideální. Hodila by

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

místo

.Skip (RecordsForPagination * Page)

a samozřejmě LastID vždy je odeslána z rozhraní.

Myslíte si, že výkon je vždy dobré s tímto kódem? Je tam lepší řešení?

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

Nejlepší odpověď

1

Výkon dopadů bude záviset výrazně na SQL Index realizace a klauzuli order by. Ale není to tolik otázka o výkon, jako o získání očekávaných výsledků.

Přetečení zásobníku je skvělé například tam, kde je objem činnosti tak, že když se dostanete na konec každé stránky, další stránka může obsahovat záznamy ze stránky, kterou si jen prohlížet, protože podkladové sady záznamů nezměnilo (další příspěvky byly přidány)

Připomínám to proto, že v živém systému je všeobecně známo, a v některých případech očekávané chování. Jako vývojáři jsme ocenit přidané režijní náklady se snaží udržet jednu sadu výsledků a uznat, že tam je obvykle mnohem nižší hodnotu, ve snaze, aby se zabránilo to, co vypadá jako duplicity , jak budete iterovat stránky.

To je dost často vysvětlit uživatelům, proč k tomu dochází, v mnoha případech budou to akceptovat

Pokud je to pro tebe důležité udržovat místo v originální sadu výsledků, pak byste se měli omezit na dotaz s Where klauzule, ale budete muset získat buď Id nebo časové razítko v původním dotazu. Ve vašem případě se pokoušíte použít LastID, ale na poslední ID by vyžadovalo samostatný dotaz na to vlastní, protože řadit podle doložky bude mít vliv na to.

Můžete opravdu použít .SkipWhile(x => x.ID >= LastID) pro tento, protože přeskočit je sekvenční proces, který je ovlivněn pořádku a je dis-zabývá prvního stupně, že výraz vyhodnocen false,, takže, pokud vaše objednávka není založena na Id, vaše přeskočit, když by výsledek je přeskakování vůbec žádné záznamy.

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();

To je obecně jednodušší, pro filtr o bod v čase, jak je to známé z klienta bez kruhové cesty k DB, ale v závislosti na implementaci filtrování na data mohou být méně efektivní.

2021-11-22 23:55:04

Mým záměrem nebylo získat LastID z DB (protože, jak jste řekl, to by byla ovlivněna Db). můj záměr byl tento: - Frontend načtení Stránky 0 a výsledkem jsou Id 20, 19, 18, 17, 16 - Frontend načíst Stránku 1 a předat backend dva param: Strana 1 a LastID z předchozí Stránku (v tomto případě LastID = 16) -> takže výsledek bude IDs 15, 14, 13, 12, 11... a tak dále. moje angličtina není perfektní... říkáme to samé?
user1106897

@user1106897 technika Chris týká, se nazývá sady klíčů Stránkování, a je obecně mnohem lepší, než stránkování po řádcích, což je to, co jste mluví o
Charlieface

Je to moc , je to také otázka výkonu: stránkování po řádcích je vysoce neefektivní jako všechny předchozí řádky je třeba číst pokaždé. Vzhledem k tomu, že stránkování pomocí klíče (nebo čas v tomto případě) je vysoce efektivní, pokud je podporující index
Charlieface

Charlieho obličej děkuji moc za odkaz, opravdu ocenil. Pokusím se použít rady
user1106897

Díky @Charlieface výkon poznámka byla spíš měl být "zapomenout na výkon, SkipWhile(podle id) nevyřeší problém, pokud změníte pořadí" Skvělý odkaz!
Chris Schaller

V jiných jazycích

Tato stránka je v jiných jazycích

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