Czy powinienem używać LINQ Skip()
i Take()
metody do stronicowania, czy zaimplementować własne stronicowanie za pomocą zapytania SQL?
Który jest najbardziej wydajny? Dlaczego miałbym wybierać jedną z nich?
Używam SQL Server 2008, ASP.NET MVC i LINQ.
sql
sql-server
asp.net-mvc
linq-to-sql
pagination
Serce z kamienia
źródło
źródło
Odpowiedzi:
Próbując dać ci krótką odpowiedź na twoje wątpliwości, jeśli wykonasz
skip(n).take(m)
metody na linq (z SQL 2005/2008 jako serwerem bazy danych), twoje zapytanie będzie używaćSelect ROW_NUMBER() Over ...
instrukcji, z jakoś bezpośrednim stronicowaniem w silniku SQL.Podając przykład, mam tabelę db o nazwie
mtcity
i napisałem następujące zapytanie (działa również z linq do encji):Wynikowe zapytanie będzie wyglądać następująco:
Jest to dostęp do danych w oknie (całkiem fajny, bo będzie zwracał dane od samego początku i będzie miał dostęp do tabeli, o ile zostaną spełnione warunki). Będzie to bardzo podobne do:
Z wyjątkiem tego, że to drugie zapytanie zostanie wykonane szybciej niż wynik linq, ponieważ będzie używał wyłącznie indeksu do tworzenia okna dostępu do danych; Oznacza to, że jeśli potrzebujesz filtrowania, filtrowanie powinno znajdować się (lub musi znajdować się) na liście jednostek (tam, gdzie tworzony jest wiersz), a także należy utworzyć kilka indeksów, aby utrzymać dobrą wydajność.
A co jest lepsze?
Jeśli masz dość solidną organizację pracy w swojej logice, implementacja właściwego sposobu SQL będzie skomplikowana. W takim przypadku LINQ będzie rozwiązaniem.
Jeśli możesz obniżyć tę część logiki bezpośrednio do SQL (w procedurze składowanej), będzie jeszcze lepiej, ponieważ możesz zaimplementować drugie zapytanie, które ci pokazałem (używając indeksów) i zezwolić SQL na wygenerowanie i przechowywanie planu wykonania zapytanie (poprawiające wydajność).
źródło
Spróbuj użyć
aby uzyskać wiersze od 501 do 600 na serwerze SQL, bez ładowania ich do pamięci. Zauważ, że składnia ta stała się dostępna z SQL Server 2012 tylko
źródło
Podczas gdy LINQ-to-SQL wygeneruje
OFFSET
klauzulę (prawdopodobnie emulowaną przy użyciu,ROW_NUMBER() OVER()
jak wspominali inni ), istnieje zupełnie inny, znacznie szybszy sposób wykonywania stronicowania w języku SQL. Jest to często nazywane „metodą wyszukiwania”, jak opisano w tym wpisie na blogu .Wartości
@previousScore
i@previousPlayerId
są odpowiednimi wartościami ostatniego rekordu z poprzedniej strony. Pozwala to na pobranie „następnej” strony. JeśliORDER BY
kierunek jest takiASC
, po prostu użyj>
zamiast tego.Przy użyciu powyższej metody nie można od razu przejść do strony 4 bez wcześniejszego pobrania poprzednich 40 rekordów. Ale często i tak nie chcesz skakać tak daleko. Zamiast tego otrzymujesz znacznie szybsze zapytanie, które może być w stanie pobierać dane w stałym czasie, w zależności od indeksowania. Ponadto Twoje strony pozostają „stabilne”, bez względu na to, czy zmieniają się podstawowe dane (np. Na stronie 1, gdy jesteś na stronie 4).
Jest to najlepszy sposób implementacji stronicowania, na przykład podczas leniwego ładowania większej ilości danych w aplikacjach internetowych.
Uwaga, „metoda wyszukiwania” jest również nazywana stronicowaniem zestawu kluczy .
źródło
LinqToSql automatycznie skonwertuje .Skip (N1) .Take (N2) do składni TSQL. W rzeczywistości każde „zapytanie”, które wykonujesz w Linq, jest po prostu tworzeniem zapytania SQL w tle. Aby to przetestować, po prostu uruchom program SQL Profiler podczas działania aplikacji.
Metodologia pomiń / przyjmij bardzo dobrze się sprawdziła dla mnie i innych z tego, co przeczytałem.
Z ciekawości, jaki masz typ zapytania ze stronicowaniem, które Twoim zdaniem jest bardziej wydajne niż polecenie skip / take Linq?
źródło
Używamy CTE opakowanego w Dynamic SQL (ponieważ nasza aplikacja wymaga dynamicznego sortowania danych po stronie serwera) w ramach procedury składowanej. Jeśli chcesz, mogę podać podstawowy przykład.
Nie miałem okazji spojrzeć na T / SQL, który tworzy LINQ. Czy ktoś może opublikować próbkę?
Nie używamy LINQ ani bezpośredniego dostępu do tabel, ponieważ wymagamy dodatkowej warstwy bezpieczeństwa (pod warunkiem, że dynamiczny SQL nieco to łamie).
Coś takiego powinno załatwić sprawę. Możesz dodać sparametryzowane wartości parametrów itp.
źródło
sp_executesql
masz możliwość przekazywania parametrów w bezpieczny sposób, npEXECUTE sp_executesql 'WITH myCTE AS ... WHERE Col4=@p1) ...', '@p1 nvarchar(max)', @ValueForCol4
. : . Bezpieczny w tym kontekście oznacza, że jest odporny na iniekcje SQL - możesz przekazać każdą możliwą wartość wewnątrz zmiennej@ValueForCol4
- nawet'--'
, a zapytanie nadal będzie działać!SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN @CampoId = 1 THEN Id WHEN @CampoId = 2 THEN field2 END)
ROW_NUMBER() OVER()
emulacja przesunięcia. Zobacz też: 4guysfromrolla.com/webtech/042606-1.shtmlW programie SQL Server 2008:
W t0 są wszystkie rekordy, w t1 są tylko te, które odnoszą się do tej strony
źródło
Podejście, które podaję, to najszybsza paginacja, jaką może osiągnąć serwer SQL. Przetestowałem to na 5 milionach płyt. To podejście jest o wiele lepsze niż „OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY” zapewniane przez SQL Server.
źródło
możesz jeszcze bardziej poprawić wydajność, sprawdź to
jeśli użyjesz from w ten sposób, da to lepszy efekt:
powód: ponieważ używasz klasy where w tabeli CityEntities, która wyeliminuje wiele rekordów przed dołączeniem do MtCity, więc 100% pewności, że zwiększy wydajność wielokrotnie ...
W każdym razie odpowiedź rodrigoelp jest bardzo pomocna.
Dzięki
źródło
@p0
a dokładniej@p1
pochodzęMożesz zaimplementować stronicowanie w ten prosty sposób, przekazując PageIndex
źródło
W 2008 roku nie możemy używać Skip (). Take ()
Droga jest następująca:
źródło