Mam raport, który pokazuje liczbę zdarzeń z ostatnich 12 godzin, pogrupowanych według godziny. Brzmi dość łatwo, ale mam problem z włączeniem płyt, które pokrywają luki.
Oto przykładowa tabela:
Event
(
EventTime datetime,
EventType int
)
Dane wyglądają tak:
'2012-03-08 08:00:04', 1
'2012-03-08 09:10:00', 2
'2012-03-08 09:11:04', 2
'2012-03-08 09:10:09', 1
'2012-03-08 10:00:17', 4
'2012-03-08 11:00:04', 1
Muszę utworzyć zestaw wyników, który ma jeden rekord na każdą godzinę z ostatnich 12 godzin, niezależnie od tego, czy w tej godzinie miały miejsce zdarzenia.
Zakładając, że aktualny czas to „2012-03-08 11:00:00”, raport pokaże (z grubsza):
Hour EventCount
---- ----------
23 0
0 0
1 0
2 0
3 0
4 0
5 0
6 0
7 0
8 1
9 3
10 1
Wymyśliłem rozwiązanie, które wykorzystuje tabelę, która ma jeden rekord na każdą godzinę dnia. Udało mi się uzyskać wyniki, których szukałem, stosując UNION i trochę skomplikowaną logikę przypadków w klauzuli where, ale miałem nadzieję, że ktoś ma bardziej eleganckie rozwiązanie.
źródło
Tabele Tally mogą być używane do takich rzeczy. Mogą być bardzo wydajne. Utwórz tabelę podsumowań poniżej. Stworzyłem tabelę podsumowań z tylko 24 wierszami dla twojego przykładu, ale możesz ją utworzyć z dowolną liczbą elementów, które chcesz dopasować do innych celów.
Zakładam, że twoja tabela nazywa się dbo.tblEvents, uruchom zapytanie poniżej. Wierzę, że tego właśnie szukasz:
Myślę, że zasługują na poniższe linki, myślę, że po raz pierwszy to spotkałem:
http://www.sqlservercentral.com/articles/T-SQL/62867/
http://www.sqlservercentral.com/articles/T-SQL/74118/
źródło
Po pierwsze przepraszam za opóźnienie w odpowiedzi od moich ostatnich komentarzy.
Temat pojawił się w komentarzach, że użycie rekurencyjnego CTE (odtąd rCTE) działa wystarczająco szybko z powodu małej liczby wierszy. Choć może się tak wydawać, nic nie może być dalsze od prawdy.
ZBUDUJ TALLY TALLY I FUNKCJĘ TALLY
Zanim zaczniemy testowanie, musimy zbudować fizyczny zestaw tabel z odpowiednim indeksem klastrowym i funkcją Tally w stylu Itzika Ben-Gana. Zrobimy to wszystko w TempDB, aby przypadkowo nie upuścić nikogo.
Oto kod do zbudowania Tally Table i moja obecna produkcyjna wersja cudownego kodu Itzika.
Nawiasem mówiąc ... zauważ, że zbudowałeś Tally Table z milionem i jednym wierszem i dodał do niego Indeks klastrowany w około sekundę. Wypróbuj TO z rCTE i zobacz, jak długo to potrwa! ;-)
ZBUDUJ NIEKTÓRE DANE TESTOWE
Potrzebujemy również danych testowych. Tak, zgadzam się, że wszystkie funkcje, które zamierzamy przetestować, w tym rCTE, działają w milisekundach lub krócej dla zaledwie 12 wierszy, ale to pułapka, w którą wpada wiele osób. Później porozmawiamy o tej pułapce, ale na razie pozwala symulować wywoływanie każdej funkcji 40 000 razy, czyli o tym, ile razy niektóre funkcje w moim sklepie są wywoływane w ciągu 8 godzin. Wyobraź sobie, ile razy takie funkcje mogą być wywoływane w dużym sklepie detalicznym online.
Oto kod do zbudowania 40 000 wierszy z losowymi datami, z których każdy ma numer wiersza wyłącznie do celów śledzenia. Nie poświęciłem czasu, żeby robić godziny całymi godzinami, bo to nie ma znaczenia.
ZBUDUJ NIEKTÓRE FUNKCJE, ABY WYKONAĆ RZECZ GODZINY 12-GODZINNEJ
Następnie przekonwertowałem kod rCTE na funkcję i utworzyłem 3 inne funkcje. Wszystkie zostały utworzone jako wysokowydajne iTVF (funkcje cenione w tabeli wbudowanej). Zawsze możesz powiedzieć, ponieważ iTVF nigdy nie mają w sobie POCZĄTKU, jak Scalar lub mTVF (Multi-instrukcja Table Valued Functions).
Oto kod do zbudowania tych 4 funkcji ... Nazwałem je po metodzie, której używają, a nie po tym, co robią, aby ułatwić ich identyfikację.
ZBUDUJ WIĄZKĘ TESTOWĄ, ABY TESTOWAĆ FUNKCJE
Na koniec potrzebujemy uprzęży testowej. Sprawdzam linię bazową, a następnie testuję każdą funkcję w identyczny sposób.
Oto kod uprzęży testowej ...
W powyższej uprzęży testowej należy zauważyć, że przetaczam wszystkie dane wyjściowe do zmiennych „wyrzucanych”. Chodzi o to, aby pomiary wydajności były jak najczystsze, bez żadnych wyników wypaczania dysku lub ekranu.
SŁOWO OSTRZEŻENIE DOTYCZĄCE USTAWIONEJ STATYSTYKI
Również ostrzeżenie dla przyszłych testerów ... NIE WOLNO używać USTAWIEŃ STATYSTYKI podczas testowania funkcji skalarnych lub mTVF. Można go bezpiecznie używać tylko w funkcjach iTVF, takich jak te w tym teście. Udowodniono, że SET STATISTICS sprawia, że funkcje SCALAR działają setki razy wolniej niż w rzeczywistości bez nich. Tak, próbuję przechylić kolejny wiatrak, ale to byłby cały „szalony post o długości artykułów i nie mam na to czasu. Mam artykuł na stronie SQLServerCentral.com, który mówi o tym wszystkim, ale nie ma sensu zamieszczać tutaj linku, ponieważ ktoś może się na to zgiąć.
WYNIKI TESTU
Oto wyniki testu, gdy uruchamiam test uprzęży na moim małym laptopie i5 z 6 GB pamięci RAM.
„WYBÓR PODSTAWY”, który wybiera tylko dane (każdy wiersz utworzony 12 razy, aby zasymulować ten sam wolumen zwrotu), pojawił się dokładnie w 1/5 sekundy. Cała reszta pojawiła się w około kwadrans. Cóż, wszystko oprócz tej cholernej funkcji rCTE. Zajęło to 4 i 1/4 sekundy lub 16 razy dłużej (1600% wolniej).
I spójrz na logiczne odczyty (pamięć IO) ... rCTE pochłonął ogromną liczbę 2 960 000 (prawie 3 MILIONY odczytów), podczas gdy inne funkcje zużyły tylko około 82 100. Oznacza to, że rCTE zużył ponad 34,3 razy więcej IO pamięci niż jakakolwiek inna funkcja.
MYŚLI ZAMKNIĘTE
Podsumujmy. Metoda rCTE do wykonania tej „małej” 12-rzędowej rzeczy wykorzystała 16 TIMES (1600%) więcej procesora (i czasu trwania) i 34,3 TIMES (3430%) więcej IO pamięci niż jakakolwiek inna funkcja.
Heh ... Wiem co myślisz. „Wielka sprawa! To tylko jedna funkcja”.
Tak, zgadzam się, ale ile masz innych funkcji? Ile masz innych miejsc poza funkcjami? A czy masz jakieś z tych, które działają z więcej niż 12 rzędami w każdym przebiegu? I czy jest jakaś szansa, że ktoś, kto szuka metody, może skopiować ten kod rCTE na coś znacznie większego?
Ok, czas być tępy. Nie ma absolutnie żadnego sensu, aby ludzie uzasadniali kod pod względem wydajności tylko z powodu rzekomej ograniczonej liczby wierszy lub użycia. Z wyjątkiem sytuacji, gdy kupujesz skrzynkę MPP za być może miliony dolarów (nie wspominając o kosztach przepisywania kodu, aby działał na takiej maszynie), nie możesz kupić maszyny, która uruchamia kod 16 razy szybciej (SSD wygrał też tego nie robię ... wszystkie te rzeczy były w wysokiej pamięci, kiedy to testowaliśmy). Wydajność jest w kodzie. Dobra wydajność jest w dobrym kodzie.
Czy potrafisz sobie wyobrazić, czy cały kod działał „tylko” 16 razy szybciej?
Nigdy nie usprawiedliwiaj złego lub kwestionowanego wydajności kodu przy małej liczbie wierszy, a nawet przy niskim zużyciu. Jeśli to zrobisz, być może będziesz musiał pożyczyć jeden z wiatraków, o który byłem oskarżony o przechylanie, aby utrzymać wystarczająco chłodne procesory i dyski. ;-)
SŁOWO W SŁOWIE „TALLY”
Tak! Zgadzam się. Semantycznie rzecz biorąc, tablica wyników zawiera liczby, a nie „liczby”. W moim oryginalnym artykule na ten temat (nie był to oryginalny artykuł na temat techniki, ale był to mój pierwszy), nazwałem go „Tally” nie ze względu na to, co zawiera, ale z powodu tego, co robi… używane do „liczenia” zamiast zapętlania i „liczenia” czegoś to „liczenie” czegoś. ;-) Nazwij to, co chcesz ... Tabela liczb, tabela liczników, tabela sekwencji, cokolwiek. Nie obchodzi mnie to. Dla mnie „Tally” ma bardziej pełne znaczenie, a będąc dobrym leniwym DBA, zawiera tylko 5 liter (2 są identyczne) zamiast 7 i łatwiej jest powiedzieć dla większości ludzi. Jest to również „liczba pojedyncza”, która jest zgodna z moją konwencją nazewnictwa dla tabel. ;-) To' jest to również, jak nazwał to artykuł, który zawierał stronę z książki z lat 60. Zawsze będę nazywał to „Tally Table” i nadal będziesz wiedział, co ja lub ktoś inny znaczy. Unikam też notacji węgierskiej jak zarazy, ale nazwałem funkcję „fnTally”, abym mógł powiedzieć „Cóż, gdybyś użył efektywnej funkcji Tally, którą ci pokazałem, nie miałbyś problemu z wydajnością”, gdyby nie była Naruszenie HR. ;-) bez faktycznego naruszenia HR. ;-) bez faktycznego naruszenia HR. ;-)
Bardziej martwi mnie to, że ludzie uczą się korzystać z niego właściwie, zamiast uciekać się do rzeczy takich jak rCTE podważające wydajność i inne formy ukrytego RBAR.
źródło
Będziesz potrzebować
RIGHT JOIN
swoich danych z zapytaniem zwracającym jeden rekord na każdą potrzebną godzinę.Zobacz to na kilka sposobów, aby uzyskać numery wierszy, które możesz następnie odjąć jako godziny od bieżącej godziny.
W Oracle hierarchiczne zapytanie na dual wygeneruje wiersze:
źródło