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
@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
@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
@DarkAlchemy: problemem jest to, że to jest częścią większej procedury i chciałem najmniejszym kosztem skrócić ten jeden fragment ale okazało się, że jednak trzeba zmienić trochę więcej
@DarkAlchemy: u mnie to było 200tys wierszy ale odpytywanie o te dane teoretycznie może się wykonywać do paredziesięciu razy na sekunde (praktycznie do kilku razy)
@DarkAlchemy: a no i dane do tej tabeli są bardzo dynamiczne, jest pewne okno czasowe którego dotyczą ale praktycznie co sekunde moze pojawić się tam nowy wiersz
@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
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.
with
x as (
select type, value
SELECT
*,
Wartosc - SUM(Flaga) OVER (PARTITION BY Typ ORDER BY Wartosc ROWS UNBOUNDED PRECEDING) as Wynik
W ogóle, jaka baza?
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