Jest to najprostszy przykład, z którym mogę odtworzyć problem. Jako taki wygląda trochę wymyślnie, ale znosić mnie.Zaskakujące zachowanie ponownego przypisywania zmiennej dla każdego wiersza w wybranym
declare @t table(number int)
insert into @t values (1), (2)
declare @sum bigint = 0
select @sum = @sum + number
from (select top 2 number from @t order by number) subquery
order by number desc
select @sum
Here's the query on the data explorer.
Spodziewam się, że to zwróci 3, suma wartości w tabeli @t
. Zamiast tego jednak, zwraca 1.
wykonując jedną z następujących czynności spowoduje zapytanie do prawidłowego powrotu 3:
- zrobić
@t.number
i@sum
mają ten sam typ (poprzez@sum
int
lub@t.number
siębigint
). - usuwając zewnętrzną
order by
- wyjmowania wewnętrznej
order by
- wytwarzaniu obu
order by
s rodzaju w tym samym kierunku przez dodaniedesc
wewnętrznej jednej lub usunięcia jej z zewnętrznego jednego - usuwania podkwerendę (czyli po prostu wybierając
from @t
)
Żadna z tych rzeczy nie uderza mnie jako coś, co powinno zmienić zachowanie tego zapytania.
Zamiana zlecenia sortowania (malejąco w podzapytania, rosnąco na zewnątrz) dokona zwrotu zapytania 2 zamiast 1.
Podobnie dzieje się z ciągami zamiast liczb, więc to nie jest ograniczone do int
i bigint
.
Dzieje się tak zarówno SQL Server 2014 i 2016, a raczej
Microsoft SQL Server 2014 - 12.0.2000.8 (X64)
Feb 20 2014 20:04:26
Copyright (c) Microsoft Corporation
Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 10586:)
i
Microsoft SQL Server 2016 (RTM-CU1) (KB3164674) - 13.0.2149.0 (X64)
Jul 11 2016 22:05:22
Copyright (c) Microsoft Corporation
Enterprise Edition: Core-based Licensing (64-bit) on Windows Server 2012 R2 Standard 6.3 <X64> (Build 9600:)
(przy czym ten ostatni badacz danych).
Co się dzieje?
Niezawodny sposób przypisania sumy to: "SELECT @ sum = SUMA (liczba) OD ...". Wykonywanie zadania w "SELECT", gdy zaangażowane jest wiele wierszy, wymaga kłopotów - zasadniczo pytasz optymalizatora, żeby Cię zepsuł, jeśli znajdzie jakiś sprytny sposób oceny zapytania. Słyszałem, jak ludzie mówią, że to nie działa, nie powinno działać, będzie działało w szczególnych okolicznościach lub nawet, że * gwarantuje * działanie w pewnych okolicznościach, ale niezawodne źródła są rzadkością. To może, ale nie musi być błąd optymalizatora, ale biorąc pod uwagę przepisanie powinno być pierwszą drogą ataku. –
@JeroenMostert Używam sumy jako prostego przykładu. Jak już powiedziałem, jest to trochę wymyślne. – balpha
Zdaję sobie z tego sprawę, ale ogólna rada jest ważna. Znalezienie sposobu na przepisanie przypisania wiersz po wierszu do czegoś opartego na zestawie jest twoim najlepszym pomysłem (chociaż bez utraty wydajności lub (horroru) wprowadzenie kursorów może być trudnym zadaniem). –