Pracuję nad Coldfusion/MS SQL od lat i jest to jeden z najdziwniejszych problemów, jakie widziałem. Sam problem został rozwiązany, ale tak naprawdę nie rozumiem, co się stało; to pytanie jest próbą uzyskania jasnego obrazu prawdopodobnej przyczyny.Powolne działanie zapytania, CF 9 i MSSQL 2008; skorumpowany plan wykonania?
Problem
w stabilnym środowisku produkcyjnym bez powodu, jeden zapytanie rozpoczyna powrót w około 1000-1500 MS (około 10 razy mniejsza niż zwykle). Udało mi się wyizolować go do tego:
<cfquery datasource="#ds#" name="query">
select 1
from eLearning.v_courseCompletion cc
where
cc.memberIncId = <cfqueryparam value="3" cfsqltype="cf_sql_integer"> and
cc.courseId = <cfqueryparam value="25" cfsqltype="cf_sql_integer"> and
cc.currentCourseCompleted = 1
</cfquery>
Co dziwne jest to zachowanie jest poważniejsza, gdy wewnątrz pętli, nawet gdy pojawia się pojedyncza iteracja, jak w poniższym przykładzie:
<cfloop from="1" to="1" index="i">
<cfquery datasource="#ds#" name="query">
select 1
from eLearning.v_courseCompletion cc
where
cc.memberIncId = <cfqueryparam value="3" cfsqltype="cf_sql_integer"> and
cc.courseId = <cfqueryparam value="25" cfsqltype="cf_sql_integer"> and
cc.currentCourseCompleted = 1
</cfquery>
</cfloop>
Powinno to być dokładnie takie samo jak powyżej, prawda? Pętla nie powinna wywoływać żadnego efektu, ale zamiast tego test ten działa około 10 razy wolniej, powracając pomiędzy 7 000-16 000 ms. W ten sposób wykryto problem; kwerenda (zakopana w metodzie obiektowej) była wywoływana z treści pętli, jeśli pętla iterowała więcej niż 5 lub 6 razy, po przekroczeniu limitu czasu żądania.
Dla mnie oznaczało to problem po stronie Coldfusion, ale ponowne uruchomienie usługi, a nawet maszyny, nic nie dało.
Tymczasem, gdy zostałem odizolowany, zauważyłem, że wprowadzenie jakiejkolwiek zmiany w samym zapytaniu spowodowało powrót wydajności do oczekiwanego poziomu, około 150-190 ms. Np
- Zmiana wybrane obszary (tj.
select *
) - Usuwanie alias tabeli (
cc
) - Wymiana albo
<cfqueryparam>
z wartością inline - usuwając wszelkie warunków
Każda z tych zmian "naprawiła" problem, ale przy uruchomieniu pierwotnego zapytania powrócił problem z wydajnością.
Rozwiązanie
W tym momencie domyśliłem plan wykonania kwerendy użytkownika została uszkodzona lub coś zrobił some Googling i pobiegł DBCC FREEPROCCACHE
przeciwko serwera DB. Ten naprawił problem natychmiast. Wielki, problem rozwiązany ....
Pytanie
Od tego czasu jednak, zrobiłem trochę więcej badań i konsensusu wydaje się, że plany wykonawcze „nie zostaną uszkodzone”. Istnieje some talk z similar problems występujące w procedurach składowanych i parameter sniffing, ale nie używam tutaj żadnych sp-sów. Wybieramy jednak dość skomplikowany widok (eLearning.v_courseCompletion
) z zagnieżdżonymi złączeniami. Czy to jest problem?
W zasadzie, co właściwie się tutaj wydarzyło? Jak mogę to powtórzyć?
.. a czym do diabła jest połączenie z pętlami w CF?!?
Wersje
- Coldfusion 9.0.2.282541 (64 bit)
- SQL Server Express 10.50.4297 (64 bit)
- Oba serwery są Win Server 2008 R2 Datacenter (64 bit)
Ah fantastycznie, to ma wiele sensu. Każdy wgląd w to, dlaczego uruchamianie go z pętli (nawet 1 iteracja) tak mocno wpłynęłoby na wydajność? Dzięki – Molomby
Nie, pętla nie brzmi jak sprawca. Chciałbym obwiniać inne okoliczności, które zapewnia pętla, takie jak zmienna indeksowa lub coś, co sprawia, że pętla wydaje się być winna. Ponadto prawie zawsze można uciec, nie uruchamiając cfquery w pętli. Bardzo rzadko kiedy to ma sens. –
Dzięki za kontynuację, ale zapewniam was, że nie ma nic więcej w pętli, która mogłaby (powinna?) Być przyczyną tego; bloki kodu zamieszczone powyżej są prosto z moich przypadków testowych (plus 'getTickCount()' przed i po). Zmienna indeksu pętli (lub elementu) nie jest w ogóle odwoływana przez zapytanie i nie ma w nim nic więcej. Prawdopodobnie coś idzie w szał podczas kompilacji pętli do Java? Jeśli uda mi się odtworzyć problem, wykopię się nieco głębiej. – Molomby