我一直能够通过Coldfusion 10查询SQL Server 2008 R2来重现严重的参数化性能问题,并且有兴趣知道其他人得到了什么。代码如下。
测试的作用是什么? 它创建一个包含100行的表。除一个数据列外,数据列均为空白。然后它运行Coldfusion查询10次,一半使用cfqueryparam,一半使用简单的字符串。它返回一个列表,其中包含每个响应时间。当我运行它时,除了初始调用之外,参数化查询的运行速度要慢得多(大约10-100次)。
SQL Server中发生了什么? 我可以看到SQL服务器没有区别。在这两种情况下,计划缓存指示几乎相同的计划(一个显然是参数化的),并且剖析器显示两者的快速响应。但是,Coldfusion在参数化查询中苦苦挣扎。
什么解决了这个问题? 奇怪的是,如果我将varchar更改为nvarchar,问题就会消失。或者如果我将非空白移动到开头,则两个响应都很慢(如图所示)。如果我将所有记录留空或非空白,那么问题就不存在了。它必须是混合物。我不能在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 :(得分:2)
答案 - 正如@Raspin在评论中所确认,设置NOCOUNT ON
可解决问题。
原始建议:
这可能是一个线索。你没有处理INDEX,但我的想法是SQL必须进行数据转换。我不认为这几行很重要,但我也不认为你会遇到这个问题:
Slow query with cfqueryparam searching on indexed column containing hashes
如果cfqueryparam将varchars作为unicode发送,则ColdFusion管理员中有一个设置可能会发生什么。如果该设置与列设置不匹配(在您的情况下,如果启用了该设置),则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>