![]() |
![]() |
![]() ![]()
Post
#1
|
|
Grupa: Zarejestrowani Postów: 14 Pomógł: 0 Dołączył: 4.09.2013 Ostrzeżenie: (0%) ![]() ![]() |
Witam,
Mam problem w odpytaniu Bazy danych w sposób „elegancki”, już tłumaczę o co chodzi. Dane: (IMG:http://imageshack.com/a/img827/9602/ncvm.jpg) Zadanie: Wyszukaj pracowników zarabiających najmniej na danym etacie. Rozwiązanie, którego bym oczekiwał i uważam za eleganckie powinno mieć postać: SELECT nazwisko FROM pracownicy WHERE ( Etat , Placa_pod ) IN (SELECT Etat, MIN(Placa_pod) FROM pracownicy GROUP BY etat); Niestety nie działa ono na MS SQL. Rozwiązanie, które działa ale jest wg. mnie gorsze (nieeleganckie) ma postać: SELECT dbo.Pracownicy.Nazwisko, dbo.Pracownicy.Imie FROM dbo.Pracownicy INNER JOIN (SELECT MIN(Placa_Pod) AS Min, Etat FROM dbo.Pracownicy AS Pracownicy_1 GROUP BY Etat) AS P_1 ON dbo.Pracownicy.Placa_Pod = P_1.Min AND dbo.Pracownicy.Etat = P_1.Etat Czy któryś z szanownych forumowiczów ma pomysł na rozwiązanie bez użycia JOIN ? Z góry dziękuję Morf. Witam ponownie, po nocnych przemyśleniach: SELECT Nazwisko, Imie FROM dbo.Pracownicy AS T1 WHERE (Placa_Pod = (SELECT MIN(Placa_Pod) AS Low FROM dbo.Pracownicy WHERE (Etat = T1.Etat))) Poziom elegancji 7 / 10 i dodatkowy punkcik za bark JOIN czyli 8 /10 :-) w zasadzie jest OK chyba, że... Pozdrawiam Morf |
|
|
![]() |
![]()
Post
#2
|
|
Grupa: Zarejestrowani Postów: 282 Pomógł: 89 Dołączył: 12.04.2011 Ostrzeżenie: (0%) ![]() ![]() |
Z odpowiednimi indeksami rozwiązanie klasyczne jest wystarczająco szybkie dla stosunkowo niedużej bazy danych, a zapewne taka jest baza pracowników, bo nawet biorąc pod uwagę wszystkich zatrudnionych na naszych uczelniach pracowników mielibyśmy ilość rekordów rzędu 100k, a to jest liczba, którą może obsłużyć testowy serwer postawiony na leciwym laptopie. Oczywiście zakładając prawidłowe zaindeksowanie, bo bez indeksów nawet przy tej niewielkiej ilości danych serwer może się zmęczyć.
Dopiero gdy dane idą w miliony trzeba myśleć o rozwiązaniach dedykowanych dla silnika i wykorzystujących specyfikę rozkładu danych, mówiąc wcześniej o takim rozwiązaniu dla sql servera z wykorzystaniem CTE i CROSS APPLY chodziło mi o coś w tym stylu:
Czyli wykorzystanie rekurencji CTE do szybkiego znalezienia z indeksu wszystkich różnych etatów a następnie CROSS APPLY by w zależnym podzapytaniu móc umieścić własne TOP i ORDER BY, dzięki czemu dostajemy dla każdego etatu wykorzystując ten sam indeks najniższą płacę, co przy dość zaawansowanym optymalizatorze sql servera pozwala uniknąć pełnego skanu indeksu (a skan całej tabeli to w ogóle byłby horror), a zamiast tego szukamy tylko tyle ile mamy różnych etatów ( czyli w miarę ograniczona, można nawet założyć stała ilość - nawet O(log(N)) jest przecież dużo gorsze niż O(1)). Polecam do testowania na nieco większej bazie, dla ułatwienia:
Mamy tutaj 10M losowych rekordów dla 100 różnych etatów i prawidłowy indeks, z trzecim członem dla ewentualnego rozstrzygania remisów w płacach wg najniższego id. Samo tworzenie tabeli zajmuje kilka-kilkanaście minut na starym kompie, ale zapytanie wciąż pozostaje w obszarze milisekund. Dla porównania klasyczne rozwiązanie powinno trwać kilka sekund. |
|
|
![]() ![]() |
![]() |
Aktualny czas: 7.10.2025 - 19:44 |