2015-08-12 2 views
7

Я последовательно смог воспроизвести серьезную проблему производительности параметризации с Coldfusion 10 с запросом SQL Server 2008 R2 и было бы интересно узнать, что получают другие. Код ниже.Воспроизводимая проблема производительности CFQUERYPARAM в Coldfusion 10

Что делает тест? Он создает таблицу со 100 строками. Столбец данных пуст во всех, кроме одного. Затем он запускает запрос Coldfusion 10 раз, наполовину используя cfqueryparam и половину, используя простую строку. Он возвращает список с временем отклика для каждого. Когда я запускаю это, помимо начальных вызовов, параметризованный запрос выполняется намного медленнее (примерно в 10-100 раз).

Что происходит в SQL Server? Я не вижу различий в SQL-сервере. В обоих случаях кеш плана указывает практически идентичные планы (один, очевидно, параметризуется), и профайлер показывает быстрые ответы для обоих. Однако Coldfusion борется с параметризованным запросом.

В чем проблема? Любопытно, что если я изменю varchar на nvarchar, проблема исчезнет. Или, если я перемещаю непустую в начало, то оба ответа медленны (go figure). Если я сделаю все записи пустыми или не пустыми, то опять проблема не будет. Это должно быть смесь. Я не могу воспроизвести проблему в CF9, но не пробовал 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

Просмотрите план выполнения каждой версии теста и посмотрите, не проливает ли свет на сцену? –

+0

сделал. Я очистил кэш плана и выполнил эти два запроса. Там было двое. Они были идентичны, кроме того, что они были параметризованы. Я также упомянул, что профайлер показывает, что SQL работает одинаково. Это либо ColdFusion, либо интерфейс базы данных. Тем не менее, я должен добавить, что, когда тест запускается из .NET, все в порядке (это, вероятно, использует тот же ODBC - хотя, очевидно, не Java). – Raspin

+3

Обычно я использую 'cf_sql_numeric'. Кажется, что ваш тест быстрее. Btw. как вы читаете план кеши с SQL Server? –

ответ

2

ОТВЕТ - Как было подтверждено @Raspin в комментариях, установка NOCOUNT ON устраняет проблемы.

Оригинальные Предложения:

Это может быть ключом. Вы не имеете дело с INDEX, но я думаю, что SQL должен выполнить преобразование данных. Я не думаю, что было бы важно, так мало строк, но я не думаю, что вы бы эту проблему:

Slow query with cfqueryparam searching on indexed column containing hashes

Что может быть происходит, есть установка в ColdFusion администратора, если cfqueryparam отправляет varchars как unicode или нет. Если этот параметр не соответствует настройке столбца (в вашем случае, если этот параметр включен), MS SQL не будет использовать этот индекс.

Другой вещь, которую я бы предложил попробовать это обертывание всего SELECT заявления в IF заявления. Моя мысль заключается в том, что, возможно, это происходит так, что SQL не считает возможным повторное использование плана запросов. Это означает, что ваша потеря производительности на самом деле является перекомпиляцией:

<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

Ну, я только что попробовал оба. Изменение настройки High ASCII/Unicod и перемещение оператора IF.Не имеет значения и для теста выше. Но последнее здесь, я все еще жду от Adobe. Они поехали без звука, закрыли мой билет и не ответили на электронные письма. Кажется, я в настоящее время персоной нон грата. – Raspin

+1

Поскольку это сетевой драйвер, некоторые мысли: (1) вы можете попробовать строку подключения, которая будет использовать TCP/IP вместо именованных каналов, (2) добавить SET NOCOUNT ON - это изменит то, что проходит через провод, возможно, обойти любую проблему, с которой вы сталкиваетесь. (3) Интересно, что происходит с набором данных, который возвращается, но не читается. Возможно, они «очереди» в драйвере, и вы должны попробовать прочитать данные, когда они будут возвращены. –

+0

Ну, вы можете добавить свой комментарий в качестве ответа, чтобы я мог его отметить. SET NOCOUNT ON действительно исправляет это. Должен признаться, что сначала у меня были сомнения, а всего несколько секунд, чтобы проверить. Действительно, похоже, что это не проблема. Кто знает, что происходит с водителем, но ясно, что это счастливее без подсчета строк! Я добавлю к нашей базе кода и надеюсь, что это не создаст никаких непредвиденных обстоятельств. Благодарю. – Raspin

Смежные вопросы