2015-08-12 41 views
7

Konsekwentnie byłem w stanie odtworzyć poważny problem z parametryzacją z ColdFusion 10, który zapytał SQL Server 2008 R2 i byłby zainteresowany poznaniem tego, co inni otrzymują. Kod znajduje się poniżej.Powtarzalny problem z wydajnością CFQUERYPARAM w Coldfusion 10

Co robi test? Tworzy tabelę ze 100 rzędami. Kolumna danych jest pusta we wszystkich oprócz jednego. Następnie uruchamia zapytanie Coldfusion 10 razy, w połowie używając cfqueryparam, a w połowie używając prostego łańcucha. Zwraca listę z czasem odpowiedzi dla każdego. Po uruchomieniu tego, oprócz początkowych wywołań, sparametryzowane zapytanie działa znacznie wolniej (o około 10-100 razy).

Co się dzieje w SQL Server? Nie widzę różnicy w serwerze SQL. W obu przypadkach pamięć podręczna planu wskazuje praktycznie identyczne plany (jeden jest oczywiście sparametryzowany), a profiler pokazuje szybkie odpowiedzi dla obu. Jednak Coldfusion zmaga się ze sparametryzowanym zapytaniem.

Co rozwiązuje problem? Co ciekawe, jeśli zmienię varchar na nvarchar, problem zniknie. Lub jeśli przeniesię niepuste na początek, obie odpowiedzi są powolne (zobacz rysunek). Jeśli zrobię wszystkie rekordy puste lub niepuste, to znowu problem nie istnieje. To musi być mieszanka. Nie mogę odtworzyć problemu w CF9, ale nie wypróbowałem CF11.

<cfset datasource="yourdatasource" /> 
<cfquery name="createdata" datasource="#datasource#"> 
    --EMPTY PREVIOUS TESTS 
    IF OBJECT_ID('aaatest', 'U') IS NOT NULL 
    BEGIN 
     TRUNCATE TABLE aaatest; 
     DROP TABLE aaatest; 
    END 

    --CREATE TABLE TO CONTAIN DATA 
    CREATE TABLE [dbo].[aaatest](
     [id] [int] NOT NULL, 
     [somedata] [varchar](max) NULL, 
     [somekey] [int] NOT NULL 
    ) ON [PRIMARY]; 

    --INSERT 100 ROWS WITH 99 BLANK AND 1 NON-BLANK 
    WITH datatable AS (
     SELECT 1 id 
     UNION all 
     SELECT id + 1 
     FROM datatable 
     WHERE id + 1 <= 100 
    ) 
    INSERT INTO aaatest(id,somekey,somedata) 
    SELECT id,1,case when id=99 then 'A' else '' end 
    FROM datatable; 
</cfquery> 

<cfset results=[] /> 
<cfloop from="1" to="10" index="n"> 
    <!--- use parameters for every other test ---> 
    <cfset useParameters = (n mod 2 is 0) /> 
    <cfquery name="myquery" datasource="#datasource#" result="result"> 
     SELECT somedata 
     FROM aaatest 
     WHERE somekey= 
     <cfif useParameters> 
      <cfqueryparam value="1" CFSQLType="CF_SQL_INTEGER" /> 
     <cfelse> 
      1 
     </cfif> 
    </cfquery> 
    <!--- store results with parameter test marked with a P ---> 
    <cfset arrayAppend(results,(useParameters?'P':'')&result.executiontime) /> 
</cfloop> 

<cfdump var="#results#" /> 
+0

Spójrz na plan wykonania dla każdej wersji testu i sprawdź, czy rzuci to światło na scenę? –

+0

Zrobiłem. Opróżniłem pamięć podręczną planów i uruchomiłem te dwa zapytania. Było tam dwóch. Były identyczne, z wyjątkiem jednego sparametryzowanego. Wspomniałem również, że profiler pokazuje SQL działający identycznie. Jest to albo ColdFusion albo interfejs bazy danych. Powinienem jednak dodać, że kiedy test jest uruchamiany z .NET, wszystko jest w porządku (prawdopodobnie używa tego samego ODBC - chociaż oczywiście nie jest to Java). – Raspin

+3

Zwykle używam 'cf_sql_numeric'. Wydaje się, że twój test jest szybszy. Btw. jak czytasz pamięci podręczne planu z SQL Server? –

Odpowiedz

2

ODPOWIEDŹ - Jak potwierdził @Raspin w komentarzach, ustawienie NOCOUNT ON rozwiązuje problemy.

oryginalne Sugestie:

To może być trop. Nie zajmujesz się INDEKSEM, ale moim zdaniem SQL musi wykonać konwersję danych. I nie sądzę, by to ważne z kilku rzędach tak, ale ja też nie pomyśli, że masz ten problem:

Slow query with cfqueryparam searching on indexed column containing hashes

Co może się dziać tam jest to ustawienie w ColdFusion, jeżeli administrator cfqueryparam wysyła varchary jako Unicode lub nie. Jeśli to ustawienie nie jest zgodne z ustawieniem kolumny (w twoim przypadku, jeśli to ustawienie jest włączone), wówczas MS SQL nie użyje tego indeksu.

Inną rzeczą, którą chciałbym zasugerować próbując, jest owinięcie twojego całego oświadczenia SELECT w oświadczeniu IF. Moim zdaniem jest to, że może spotkać się w taki sposób, że SQL nie uważa, że ​​może ponownie wykorzystać plan zapytania. Oznacza to, że utrata wydajności jest w rzeczywistości ponowną kompilacją:

<cfloop from="1" to="10" index="n"> 
    <cfset useParameters = (n mod 2 is 0) /> 
    <cfif useParameters> 
     <cfquery name="myquery" datasource="#datasource#" result="result"> 
     SELECT somedata 
     FROM aaatest 
     WHERE somekey= <cfqueryparam value="1" CFSQLType="CF_SQL_INTEGER" /> 
     </cfquery> 
    <cfelse> 
     <cfquery name="myquery" datasource="#datasource#" result="result"> 
     SELECT somedata 
     FROM aaatest 
     WHERE somekey= 1 
     </cfquery> 
    </cfif> 

    <cfset arrayAppend(results,(useParameters?'P':'')&result.executiontime) /> 
</cfloop> 
+0

Cóż, właśnie próbowałem obu. Zmiana ustawienia ASCII/Unicod i zmiana instrukcji IF.Żaden nie robi różnicy na powyższym teście. Ale najnowsze jest to, że wciąż czekam na Adobe. Milczeli, zamknęli bilet i nie odpowiedzieli na żadne e-maile. W tej chwili jestem persona non grata. – Raspin

+1

Ponieważ jest to sterownik sieciowy, niektóre myśli: (1) możesz wypróbować ciąg połączenia, który używał TCP/IP zamiast nazwanych potoków, (2) dodać SET NOCOUNT ON - to zmieni to, co przechodzi przez przewód, może pracujesz nad tym, co trafisz. (3) Zastanawiam się, co dzieje się z zestawem danych, który jest zwracany, ale nie czytany. Być może są one "w kolejce" w sterowniku i powinieneś spróbować czytać zbiory danych, ponieważ są one zwracane. –

+0

Możesz dodać swój komentarz jako odpowiedź, aby go oznaczyć. SET NOCOUNT ON rzeczywiście to naprawia. Muszę przyznać, że na początku miałem wątpliwości, ale przetestowanie zajęło mi tylko kilka sekund. Rzeczywiście wydaje się, że unika się tego problemu. Kto wie, co się dzieje z kierowcą, ale wyraźnie jest szczęśliwszy bez liczby rzędów! Dodam do naszej bazy kodu i mam nadzieję, że nie spowoduje to żadnych niespodzianek. Dzięki. – Raspin