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#" />
Spójrz na plan wykonania dla każdej wersji testu i sprawdź, czy rzuci to światło na scenę? –
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
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? –