2015-12-30 17 views
9

Więc kod jest bardzo prosty:Podmiot Framerowk Skip/Weź jest bardzo powolne, gdy liczba pominąć jest duży

var result = dbContext.Skip(x).Take(y).ToList(); 

Gdy x jest duży (~ 1.000.000), zapytanie jest bardzo powolny. y jest niewielka - 10, 20.

kodu SQL na to: (od SQL Profiler)

SELECT ... 
FROM ... 
ORDER BY ... 
OFFSET x ROWS FETCH NEXT y ROWS ONLY 

Pytanie brzmi, czy ktoś wie, jak przyspieszyć taką stronicowania? Dzięki.

+0

Co stanie się, gdy złożysz zamówienie przed pominięciem w kolumnie zawierającej indeks? – Shyju

+0

Do czego potrzebne są 1-milimetrowe rzędy? – ErikEJ

Odpowiedz

3

Myślę, że OFFSET .. FETCH jest bardzo przydatny podczas przeglądania pierwszych stron z dużych danych (co dzieje się bardzo często w większości aplikacji) i ma wadę wydajności przy wyszukiwaniu dużych stron z dużych danych.

Sprawdź to article, aby uzyskać więcej informacji dotyczących wydajności i alternatyw dla OFFSET .. FETCH.

Spróbuj zastosować tak wiele filtrów do danych przed zastosowaniem stronicowania, aby stronicowanie było wykonywane na mniejszym woluminie danych. Trudno sobie wyobrazić, że użytkownik nie chce nawigować w 1-milionowych wierszach.

+0

Dzięki za udostępnienie tego artykułu, to naprawdę pomaga. Oczywiście wynikowy zestaw danych powinien być znacznie mniejszy, ponieważ nie ma sensu nawigować po tych wszystkich rekordach. Właśnie znalazłem ten problem i zastanawiałem się, dlaczego tak się dzieje. – berliner

4

Nawigacja chociaż milion rekordów w bazie danych zawsze będzie powolna w porównaniu z innymi sposobami, baza danych musi "pomijać" milion rekordów, robi to, tworząc wynik w pamięci, a następnie odrzucając pierwsze miliony wierszy.

Czy zastanawiałeś się nad alternatywą nie-sql (solr, lucene, itp.), Przynajmniej po to, aby najpierw uzyskać identyfikatory swoich wierszy, a następnie za pomocą zapytania where in()?

Alternatywnie możesz mieć tabelę wyszukiwania (tabela z gotowaniem) w głównej tabeli z tylko minimalnymi danymi i identyfikatorami, więc możesz pominąć tę i uzyskać identyfikatory i zapytać o duży stół z tymi.

3

Masz rację, Pomiń(). Metoda Take() jest powolna na serwerze SQL. Kiedy zauważyłem, że zastosowałem inne podejście i działało dobrze. . Zamiast przy użyciu LINQ SKIP() Take() - który pisze kod pokazał -, to wyraźnie napisać SQL jako:

select top NTake ... from ... order by ... where orderedByValue > lastRetrievedValue 

ten działa szybko (biorąc pod uwagę Mam indeks na zamówiony przez kolumnę (-y)).

+0

To bardzo miłe obejście. Zrobię z tym kilka benchmarków. Dzięki. –

+0

Bardzo fajny pomysł. Ale po raz pierwszy lastRetrievedValue będzie zero –

+0

Ale jest pewien problem. Załóżmy, że istnieje kolumna, która może mieć te same wartości. ten czas orderedByValue> lastRetrievedValue przejmie od następnej większej wartości nie od miejsca, w którym zakończył się po raz ostatni. –

2

Może brakować jakiegoś indeksu na twojej tabeli (lub możesz mieć ich zbyt wiele), powodując, że sortowanie/filtrowanie SQL nie jest w stanie skutecznie pominąć wielu wierszy (lub w przypadku zbyt dużej liczby indeksów, powodując nie udało się wybrać dobrego indeksu dla danego zadania).

Spróbuj testowania zapytań SQL bezpośrednio:

  • sprawdzić jego rzeczywisty plan wykonania,
  • czek na brak wskazówek indeksu (może wymagać przepisać zapytanie jako non-dynamicznego zapytania sql, jeśli ef wydał niektóre dynamiczny kod zapytania),
  • czek na różnego rodzaju wycieki w temp db,
  • ...

Więc, krótko mówiąc, czekiem czy problem jest rzeczywiście kwestią Entity-Framework lub "czystym" problemem SQL.

Nota boczna: wydania EF: offset/fetch kwerendy stronicowane, tylko jeśli jest skonfigurowany dla dialektu SQL2012. Dla poprzednich dialektów używa zamiast tego row_number().

+0

Z [artykułu] (http://www.mssqlgirl.com/paging-function-performance-in-sql-server-2012.html) z @Alexei wynika, że ​​'numer_wiersza()' może działać o wiele lepiej niż 'OFFSET' -' FETCH' w twoim przypadku. Więc możesz również spróbować zmienić dialekt EF na "SQL 2008", żeby to sprawdzić. To nie byłby jednak miły hack, moim zdaniem. –

Powiązane problemy