2010-01-11 15 views
5

W naszej bazy danych SQL Server 2005 (testowane przy użyciu Management Studio z DBCC FREEPROCCACHE i DBCC DROPCLEANBUFFERS), następujące stwierdzenie jest szybko (~ 0.2s czasie kompilacji, ~ czas 0.1s wykonanie):Prevent ADO.NET z użyciem sp_executesql

SELECT ... FROM ... WHERE a = 1 AND b = '' ... 

następujące oświadczenie jest jednak powolny (~ 0.2s czasie kompilacji, 7-11s czas realizacji):

exec sp_executesql N'SELECT ... FROM ... WHERE a = @a AND b = @b ...', N'@a int, @b nvarchar(4000), ...', @a=1, @b=N'', ... 

SQL Server wybiera inny plan wykonania, chociaż zapytania są równe. Ma to sens, ponieważ w pierwszym przypadku SQL Server ma rzeczywiste wartości a, b i wszystkie pozostałe dostępne parametry i może użyć statystyk do stworzenia lepszego planu. Wygląda na to, że plan zapytania dla konkretnych wartości parametrów jest o wiele lepszy od o wiele lepszy od i zdecydowanie przewyższa wszelkie korzyści związane z wydajnością "buforowania planu zapytań".

Teraz moje pytanie: ADO.NET zawsze wydaje się wykorzystywać drugą opcję (sp_executesql) podczas wykonywania kwerend parametrycznych, które zwykle sens (plan zapytania buforowanie, etc.). W naszym przypadku jednak to zabija wydajność. Tak, czy istnieje jakiś sposób, aby zarówno

  • siły ADO.NET użyć czegoś innego niż sp_executesql (czyli coś, gdzie analizator zapytań SQL Server wykonuje rzeczywiste wartości parametrów pod uwagę) lub
  • siły SQL Server dokonać ponownej krystalizacji planu zapytania SQL przekazanego do sp_executesqlbiorąc pod uwagę wartości parametrów?

I proszę nie mów mi, że musiał wrócić do brzydkich, starych, niebezpiecznych sql = "WHERE b = " + quoteAndEscape(parameterB) ...

Uruchamianie SQL w procedurze przechowywanej ma znaczenia (powolny, zi bez WITH RECOMPILE) . Nie opublikowałem aktualnej instrukcji SQL, ponieważ jest ona dość złożona (dołącza się do wielu tabel, w tym podelektronów i agregacji).

+0

Konwersja do procedury przechowywanej jest tak powolna jak zapytanie adhoc? To jest BARDZO dziwne zachowanie, więc muszę zapytać: czy jesteś pewien? –

+0

@Rubens - dlaczego tak mówisz? Jaką przewagę wydajności ma procedura składowana oferowana w buforowanej, skompilowanej, sparametryzowanej kwerendzie adhoc? –

+0

Tak, jestem pewien. Dlaczego powinien być szybszy? Czas kompilacji jest nieznacznie mały (0,2 s) w porównaniu do czasu wykonania (7-11s). – Heinzi

Odpowiedz

4

Starego wątku wiem, ale ja po prostu znaleźć go przez googlowania prawie dokładnie to samo zdanie! Miałem dokładnie ten sam problem (zapytanie bardzo szybko działało w Management Studio przy użyciu parametrów, ale potem bardzo powoli za pośrednictwem ADO.Net) i replikowało problem, uruchamiając zapytanie w Management Studio przez "exec sp_execute". Dwa plany wykonania były bardzo różne, nawet z podpowiedzią dotyczącą optymalizacji dla zapytania, więc zamiast tego zrobiłem wstępny wybór niektórych danych do tabeli tymczasowej. To wydawało się robić różnicę, a biorąc pod uwagę, że twoje zapytanie jest złożone, może to bardzo dobrze wpłynąć na twoją sprawę - nie jestem pewien, jak to działało, ale wydawało się, że plan wykonania został line nawet przy użyciu sp_execute.

+0

Dokładnie to właśnie wykonaliśmy: podziel zapytanie na mniejsze za pomocą tabel tymczasowych ('# ...'), aby uniemożliwić optymalizatorowi kwerend wybór złego planu. – Heinzi

2

Mógłbyś spróbować OPTIMIZE FOR query hint który (cytat):

zobowiązuje optymalizator kwerendy do używania szczególną wartość dla zmiennej lokalnej gdy kwerenda jest kompilowany i zoptymalizowane. Ta wartość jest używana tylko podczas optymalizacji zapytań, a nie podczas wykonywania zapytań, a nie jako . Optymalizacji dla może przeciwdziałać parametrów detekcji zachowanie optymalizatora lub mogą być wykorzystywane podczas tworzenia planu prowadzi

2

Uważam, że problem ma do czynienia z pomocą typ VARCHAR danych w bazie danych. SQL Server wydaje się nie używać określonego indeksu, jeśli parametr where jest zadeklarowany jako NVARCHAR.

Można jednak zmienić kolumnę bazy danych na NVARCHAR (zwiększyłoby to oczywiście rozmiar), a następnie poprawiłaby się wydajność indeksu.

Obecnie mam ten problem z LINQ i może rzeczywiście trzeba powrócić do za pomocą procedur przechowywanych, aby ominąć to.

Kwestia ta jest szczegółowo wyjaśnione w this Microsoft Connect discussion

+0

Po przeczytaniu godzin, problemy z wąchaniem parametrów, ustawieniem parametru ARITHABORT, itp. ... to jest mój problem, nie ustawiłem wprost parametrów w moim zapytaniu i zostały one przekazane jako nvarchar, i mam varchar w bazie danych. Dzięki – Juan

0

Chciałbym przenieść zapytanie do procedury składowanej, a następnie w komendzie podać command.CommandType = CommandType.StoredProcedure.

Nie tworzy sp_executesql i nie zwiększa wydajności