Wpis z mikrobloga

#sql #bazydanych #programowanie

Mam tabele w takiej postaci (nazwijmy ją "Tabela"):
A 1 0
A 2 1
A 3 1
A 4 0
A 5 0
B 1 0
B 2 0
B 3 0
B 4 1

Nazwę pierwszą kolumnę "Typem", drugą "Wartością", a trzecią "Flagą".
Moim zadaniem jest przetransformować tabele tak, że dla danego wiersza muszę odjąć od wartości tyle ile jest wierszy o tym samym typie, mniejszej wartości i fladze=1. Czyli wynikiem byłoby:

A 1
A 2
A 2 (-1, bo jeden wiersz "powyżej miał flage=1)
A 2 (-2, bo dwa wiersze "powyżej" miały flage=1)
A 3 (-2, bo dwa wiersze "powyżej" miały flage=1)
B 1
B 2
B 3
B 4

Użyłem słowa "powyżej", bo w tym przykładzie faktycznie są one powyżej dla łatwiejszego zobrazowania problemu.
Chciałbym to zrobić jak najbardziej możliwie optymalnie pod względem czasu. Aktualnie od drugiej kolumny odejmuje coś takiego i jest zdecydowanie za wolne:
Coalesce(SUM(CASE WHEN Flaga = 1 THEN 1 ELSE 0 END) OVER
(PARTITION BY Typ ORDER BY Wartość
ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0)

Próbowałem też odjąć:
SELECT COUNT(*) FROM temp where temp.Typ = Tabela.Typ and temp.Wartość < Tabela.Wartość and Tabela.Flaga = 1
ale to było jeszcze wolniejsze xD

Może wy będziecie mieli jakieś lepsze pomysły.
  • 11
  • Odpowiedz
  • Otrzymuj powiadomienia
    o nowych komentarzach

spoko, tak myslalem ze moze nie byc za dobrze z tym cross joinem. daj znac jak cos wykombinujesz, ciekawy jestem jakie jest optymalne rozwiazanie
  • Odpowiedz
@DarkAlchemy: Dzisiaj jeszcze próbowałem oba, indeks też i niestety nie polepszało i zdecydowałem się dodać trigger w tabeli wejściowej aby od razu zmieniał dane na takie jakich potrzebuję na wyjściu
  • Odpowiedz
via Wykop Mobilny (Android)
  • 0
@TenAnonToKlopoty: na moim serwerze testowym, dla miliona wierszy, z indeksem, zapytanie wykonuje się w ~15 sekund, z czego ~12 sekund to samo rzucanie wyników do SSMS, silnik swoje zadanie kończy po niecałych 3 sekundach
  • Odpowiedz
via Wykop Mobilny (Android)
  • 0
@TenAnonToKlopoty: dobra to rozumiem teraz po co tak. Jeszcze jest dziwna sztuczka którą możesz użyć jak robisz na SQL Server w wersji 2016 lub wyżej.
Tworzysz tabelę tymczasową z jedną kolumną, wrzucasz tam jedną wartość (np. kolumna D--a i wartość INT = 1) i... Zakładasz na niej CLUSTERED COLUMNSTORE INDEX
Potem robisz CROSS APPLY do swojej tabeli w zapytaniu i jest opcja, że wtedy wymusisz na silniku użycie Batch Mode
  • Odpowiedz