2017-12-22 175 views
5

Mam podstawową siatkę z włączonym stronicowaniem w mojej aplikacji internetowej. Ta siatka jest zapełniana danymi SQL za pośrednictwem interfejsu Web API z wykorzystaniem Dapper. W moim kontrolerze API uruchamiam dwa osobne zapytania: jeden do wyodrębnienia wierszy (które są wyświetlane w mojej siatce) i jeden do uzyskania całkowitej liczby rekordów (które będą wyświetlane w moich kontrolkach stronicowania). I to działa. Jednak staram się zoptymalizować moje zapytania.Czy mogę pobrać wiersze stronicowane i liczbę całkowitą w jednym zapytaniu?

My pierwsze zapytanie, które wyodrębnia wierszy, zwraca tylko 50 rzędów w czasie (przy użyciu OFFSET i FETCH, uzyskując przywoławcze

SELECT DISTINCT T_INDEX.* 
FROM T_INDEX 
INNER JOIN T_INDEXCALLER ON T_INDEX.IndexId = T_INDEXCALLER.IndexId 
WHERE... --a fairly complex WHERE statement 
ORDER BY CallTime DESC 
OFFSET (@offset) ROWS FETCH NEXT 50 ROWS ONLY 

Drugie zapytanie wydobywa liczbę wszystkich rzędach ale wykorzystuje te same stoły, te same przyłącza, a tym samym WHERE klauzuli.

SELECT COUNT(DISTINCT T_INDEX.IndexId) 
FROM T_INDEX 
INNER JOIN T_INDEXCALLER ON T_INDEX.IndexId = T_INDEXCALLER.IndexId 
WHERE... --the same fairly complex WHERE statement 

Jak powiedziałem, to działa i t około 2,5 sekundy na jedno zapytanie, łącznie 5+ sekund. Opóźnienie to nie koniec świata, za wszelką cenę, ale chciałbym skrócić ten czas o połowę.

Chciałem wiedzieć, czy istnieje sposób na odzyskanie 50 wierszy i, aby uzyskać całkowitą liczbę WSZYSTKICH wierszy w ramach jednego zapytania. Zdaję sobie sprawę, że te dwa pytania robią dwie odrębne rzeczy. Ale moim zdaniem jest to, że "może" być sposobem na dostosowanie tych dwóch zapytań i połączenie ich w jedno, ponieważ tabele, łączenia i klauzula WHERE są identyczne między tymi dwoma.

Odpowiedz

1

Można dać tego zapytania spróbować:

SELECT * 
FROM (
    SELECT *, COUNT(*) OVER() AS cnt 
    FROM (
     SELECT DISTINCT T_INDEX.*, 
     FROM T_INDEX 
     INNER JOIN T_INDEXCALLER ON T_INDEX.IndexId = T_INDEXCALLER.IndexId 
     WHERE... --a fairly complex WHERE statement 
    ) AS t1) AS t2 
ORDER BY CallTime DESC 
OFFSET (@offset) ROWS FETCH NEXT 50 ROWS ONLY 

można uprościć powyższe zapytanie w zależności od tego, co określa odrębny rekord w tabeli wynikowej.

+0

Myślę, że to może być to, czego szukam. Podczas mojej pierwszej pary wygląda na to, że działa świetnie. Zamierzam zrobić jeszcze kilka poprawek. –

0
SELECT DISTINCT T_INDEX.*, 
     (SELECT COUNT(DISTINCT T_INDEX.IndexId) FROM T_INDEX 
      INNER JOIN T_INDEXCALLER ON T_INDEX.IndexId = 
      T_INDEXCALLER.IndexIdAS) AS TotalCount 
FROM T_INDEX 
INNER JOIN T_INDEXCALLER ON T_INDEX.IndexId = T_INDEXCALLER.IndexId 
WHERE... --a fairly complex WHERE statement 
ORDER BY CallTime DESC 
OFFSET (@offset) ROWS FETCH NEXT 50 ROWS ONLY 
+0

Hmmm, intrygujące.Ale otrzymuję '1' dla' TotalCount' dla każdego wiersza –

+0

, czego dokładnie potrzebujesz? Jak poprosiłeś o całkowitą liczbę rekordów –

+0

Suma rekordów. Jak w sumie rekordów dla całego zestawu danych. –

0

Proponuję inne rozwiązanie: nie rób tego ślepej optymalizacji.

Po prostu starasz się mieć szczęście - to nierozsądne.

Nie robią tego samego i dlatego mogą być zoptymalizowane indywidualnie. Ale ważniejsze jest to, że oba zapytania zostały wykonane dla 2.5 sekund, co wygląda dziwnie dla zapytań za pomocą prostego połączenia i prostego zadania polegającego na uzyskaniu 50 records lub count all. Wiem, że zależy to od wielkości tabel i sprzętu twojego serwera, ale wciąż.

Sądzę, że możesz zoptymalizować oba i nie będzie potrzeby "scalania" ich w jedno.

Najpierw przyjrzę się planowi wykonania zapytania. Jestem prawie pewien, że można go znacznie przyspieszyć. Dodaj plany zapytań do swojego pytania.

Ale nawet bez pytania już mam kilka pytań:

  • dlaczego distinct?
  • Czy masz indeks na T_INDEX.CallTime?
+0

Doceniam twoją opinię. I tak, jestem pewien, że istnieje sposób na zoptymalizowanie moich zapytań za pomocą innych metod. To jest strzał w ciemno, że tak powiem. Aby odpowiedzieć na twoje pytania, używam wyrazu "odrębny" z powodu sprzężenia w moim zapytaniu. Istnieje tam relacja jeden-do-wielu i pobieram wiersze nadrzędne, gdzie dowolny z wierszy potomnych pasuje do klauzuli "where". I chcę liczbę wierszy nadrzędnych, a nie wierszy podrzędnych. –

+0

Nie mam indeksu na 'T_INDEX.CallTime'. Spróbuję to dodać. –

+0

Aby jeszcze bardziej skomplikować sprawę, wykonuję wyszukiwanie pseudo-pełnotekstowe (przy użyciu sortowania binarnego) w wierszach potomnych, co jest głównym powodem, dla którego chcę się dowiedzieć, czy mogę zapytać tylko raz, aby uzyskać to, czego potrzebuję. Istnieje około miliona wierszy w 'T_INDEXCALLER'. –