2009-10-02 7 views
8

Używamy ORM, który wykonuje wywołanie z .NET do przechowywanej procedury sp_executesql programu SQL Server.Zapytanie SQL spowalnia z kodem .NET, ale nie interakcyjnie

Kiedy przechowywany proc zostaje wywołany z .NET, otrzymujemy wyjątek timeout.

Patrząc na Profiler, widzę, że wykonanie zapytania zajmuje naprawdę dużo czasu.

Kwerenda jest w istocie:

exec sp_executesql N'SELECT DISTINCT 
FROM [OurDatabase].[dbo].[Contract] [LPLA_1]) [LPA_L1] 
LEFT JOIN [OurDatabase].[dbo].[Customer] [LPA_L2] ON [LPA_L2].[Customer_ID]=[LPA_L1].[CustomerId] AND [LPA_L2].[Data]=[LPA_L1].[Data]) 
WHERE ((((([LPA_L1].[DealerId] = @DealerId1)) 
AND ([LPA_L2].[Last_Name] = @LastName2))))',N'@DealerId1 varchar(18),@LastName2 varchar(25)',@DealerId1='1234',@LastName2='SMITH' 

Mylące część dla mnie jest taka: Jeśli mogę skopiować i wkleić kwerendę, która jest odmierzanie w SQL Management Studio i wykonać go interaktywnie, wykonuje dobrze.

Czy ktoś wie, dlaczego to samo zapytanie trwałoby znacznie dłużej podczas wykonywania przez kod .NET? (Mogę to odtworzyć - kwerenda wykonana z kodu konsekwentnie kończy się, a zapytanie wykonywane interaktywnie konsekwentnie działa poprawnie.)

Każda pomoc jest doceniana. Dzięki!

+0

Ile linii danych wracasz? Jeśli istnieją tysiące linii, to może to zająć trochę czasu, aby przepchnąć przewód do komputera, oczekując wyniku z powrotem. – Miles

+0

Czy zapytanie zwraca dużo danych? Czy istnieje jakakolwiek transmisja danych między serwerem a klientem biorącym udział w przypadku programu, który nie występuje w trybie interaktywnym? – quosoo

+0

Trzy w naszym przypadku testowym. Ponadto, DealerID i Last_Name mają indeksy. –

Odpowiedz

0

Czy dealId lub Nazwisko nvarchar (inaczej wpisane niż parametry varchar)?

Może to spowodować konwersję całych indeksów. Jeśli uważasz, że tak jest, zostaw komentarz, a ja wyjaśnię bardziej szczegółowo.

+0

Nie, są to obie varcary w bazie danych, niestety. –

4

Jedną z rzeczy, które widziałem kilka razy, jest to, że masz niedopasowanie między typami nvarchar i varchar dla parametru zapytania w indeksowanym polu. Może się tak zdarzyć, jeśli użyjesz varchar w bazie danych i nie ustawisz jawnie typu twojego parametru w .Net, który domyślnie przyjmie nvarchar.

W takim przypadku serwer Sql wybiera bardziej poprawną opcję niż opcję o lepszej wydajności. Zamiast po prostu konwertować parametr na varchar, który byłby zawężającą konwersją, która mogłaby potencjalnie utracić informacje, baza danych będzie zmuszona przekształcić każdą wartość dla tej kolumny w tabeli na nvarchar (co gwarantuje sukces bez utraty informacji) . Nie tylko jest to powolne, ale serwer Sql nie będzie już mógł korzystać z tego indeksu. Nie trzeba dodawać, że wykonanie zapytania zajmie znacznie więcej czasu.

+0

Dlaczego ma to znaczenie, że kwerenda jest uruchamiana z .NET zamiast z SQL Mgmt Studio? –

+0

Czy przeczytałeś mój post? Kiedy tworzysz parametry dla twojego obiektu sqlcommand w .Net (nawet jeśli ta część jest ukryta przez orm) i nie mówisz wprost, jakie są typy tych parametrów, .Net wybierze dla ciebie i może wybrać błąd. W rezultacie nie jest to dokładnie to samo zapytanie. –

+0

Tak, ale AlexWalker działa w SQL Mgmt Studio zapytanie wzięte z profilera ==> to dokładnie to samo zapytanie, które SQL Server uruchomi ostatecznie, niezależnie od twórcy (.NET lub Mgmt. Studio). O ile połączenie nie jest skonfigurowane inaczej ... Mam przeczucie, że połączenie jest tym, co robi różnicę. –

1

Mam ten sam problem, procedura wykonana z domeny .net, która zajmuje zbyt dużo czasu (i nie zwraca wielu wierszy). Wysyłam ciąg do sql: "wykonaj stored_procedure @ parameter1 = value1" i skopiuj to i uruchom na sql management studio, ale tam wszystko działa dobrze. W tym przypadku jest tak, że w moim zapytaniu po prostu dodajemy lub usuwamy LETTER z wartości parametru, aby to spowodować. Jestem bardzo zmieszany.

Dla informacji używam pełnotekstowych tabel indeksowych i tymczasowych, ale tak jak powiedziałem, SAME QUERY (i jestem pewien) działa doskonale w studiu zarządzania sql.

1

Po prostu miałem ten sam problem.

Przebudowanie indeksów rozwiązało problem.

Być może problem leży w typie parametrów będących nvarchar vs index, który znajduje się w kolumnie varchar ...?

1

Myślę, że to dlatego, że sp_executelsql ma na celu ponowne wykorzystanie skompilowanych planów zapytań, więc nie powoduje ponownej detekcji parametrów, gdy ponownie trafi to samo zapytanie, co kończy się zastosowaniem planu, który może być bardzo powolny (wyjaśnić, dlaczego wolniejszy plan zapytania) z aktualnymi wartościami parametrów.wydaje się, że sp_executesql używa innej metody do wyboru indeksów i najwyraźniej jest to zepsuta metoda w porównaniu z zapytaniem tekstowym.

Czym różni się Aktualizacja Tabeli dla "Firma (tabela)" pod sp_executesql jest podawana przez łańcuch zagnieżdżonych pętli, podczas gdy zapytanie tekstowe jest podawane przez łańcuch dopasowań hash. Konstrukcja widoków wydaje się identyczna między dwiema wersjami (czego bym się spodziewał). Niestety, pozostała część jest bardzo złożona i wydaje się, że robią radykalnie różne rzeczy w środku; nawet wyciągnięcie "rzeczywistego" planu wykonania nie daje rzeczywistych czasów wykonania dla różnych pod-komponentów zapytania. Naprawdę, nie widzę żadnego powodu, dla którego sp_executesql mógłby wybierać coś inaczej, ale niezawodnie konstruuje znacznie wolniejszy plan.

Sniffowanie parametrów jest rozwiązaniem tego problemu, więc powinieneś zmienić nazwy parametrów lub nawet zamienić nazwy kolumn w miejscu, gdzie klauzula powodująca sp_executesql odtworzenie planu kwerendy zamiast używania starego wolnego planu, oczywiście jest to nie jest rozwiązaniem, ale nie będzie tak długo przechowywać w pamięci wolniejszego planu.

Pozdrawiam.

+0

Dziękuję, to wygląda na prawdziwe –

1

Oto co znalazłem. Mam BARDZO złożony zapisany proces, który zawsze liczy informacje i umieszcza dane w macierzy z ośmioma kolumnowymi 17 wierszami, ponieważ jest ona wywoływana/uruchamiana przez Crystal Reports co miesiąc. Baza danych prod była na szalonym szybkim serwerze 96 GB! Ostatnio został zmniejszony do wirtualnej maszyny o pojemności 32 GB. Podczas zmniejszania - powodowało to, że aplikacja działała wolniej na wiele sposobów - aż do dodania kilku indeksów.

Następnie nadszedł czas miesiąca, aby uruchomić ten 17-wierszowy matrycowy raport miesięczny ... i jak można sobie wyobrazić, upłynął limit czasu!

Wywołanie proc było dość proste - 3 parametry. Data początkowa, data zakończenia i dzielnica do filtrowania - wartość zerowa równa się WSZYSTKIM. 2 daty zostały przekazane z Crystal Reports jako postać, a te zapisane parametry PROC były następnie używane w całym tym szalonym zapisanym proc.

Każdy z 17 wierszy - w zasadzie używa instrukcji WITH i szalonych połączeń, aby znaleźć wiersze danych przed zliczeniem/obróceniem wyników ... co NIE jest ważne w tym artykule.

Więc to jest uproszczone ....

CREATE PROCEDURE [dbo].[prcMonthlyStats] 
@bDate   datetime 
,@eDate   datetime 
,@districtStr varchar(120) 
AS 
BEGIN 
SET NOCOUNT ON; 

...

--the @bDate and @eDate params were DIRECTLY used throughout the 2000 lines of SQL, 
--to filter data inside and out of WITH statements and various other selects! 
-- 
--TIMES OUT! 

...

CREATE PROCEDURE [dbo].[prcMonthlyStats] 
@bDateStr  datetime 
,@eDateStr  datetime 
,@districtStr varchar(120) 
AS 
BEGIN 
SET NOCOUNT ON; 

--FIX! Declare 2 date time variables and simply assign the 2 date time parameters to them. 
DECLARE @bDate  datetime 
DECLARE @eDate  datetime 
DECLARE @district varchar(120) 

--SET THE VARIABLES FROM THE PARAMETERS PASSED IN! 
SET @bDate = @bDateStr 
SET @eDate = @eDateStr 
SET @district = @districtStr 
..... 

--PRESTO! The optimizer could once again use indexes as it should. 

Więc morał z tej historii jest - optymalizator było był w stanie zrobić to, wykorzystując czasy decyzyjne.