使用cfqueryparam搜索包含哈希的索引列的慢查询

时间:2012-05-11 00:06:21

标签: sql-server performance coldfusion coldfusion-9 cfqueryparam

我有以下查询,运行时间为16ms - 30ms。

<cfquery name="local.test1" datasource="imagecdn">
    SELECT hash FROM jobs WHERE hash in(
        'EBDA95630915EB80709C69089315399B',
        '3617B8E6CF0C62ECBD3C48DDF8585466',
        'D519A38F09FDA868A2FEF1C55C9FEE76',
        '135F94C3774F7719CFF8FF3A275D2D05',
        'D58FAE69C559273D8427673A08193789',
        '2BD7276F209768F2FCA6635659D7922A',
        'B1E3CFBFCCFF6F5B48A849A050E6D424',
        '2288F5B8A797F5302E8CA24323617236',
        '8951883E36B5D38A4643DFAA0396BF13',
        '839210BD564E30BE1355D1A6D4EF7081',
        'ED4A2CB0C28B608C29576819CF7BE19B',
        'CB26925A4874945B810707D5FF0B91F2',
        '33B2FC229F0CC797A02AD163CDBA0875',
        '624986E7547DBAC0F47B3005CFDE0A16',
        '6F692C289BD805CEE41EF59F83F16F4D',
        '8551F0033C617BD9EADAAD6CEC4B3E9E',
        '94C3C0A74C2DE085FF9F1BBF928821A4',
        '28DC1A9D2A69C2EDF5E6C0E6368A0B3C'
    )
</cfquery>

如果我执行相同的查询但使用cfqueryparam,则运行时间为500毫秒 - 2000毫秒。

<cfset local.hashes = "[list of the same ids as above]">
<cfquery name="local.test2" datasource="imagecdn">
    SELECT hash FROM jobs WHERE hash in(
        <cfqueryparam cfsqltype="cf_sql_varchar" value="#local.hashes#" list="yes">
    )
</cfquery>

该表大约有60,000行。 “hash”列是varchar(50)并且具有唯一的非聚集索引,但不是主键。数据库服务器是MSSQL 2008.Web服务器正在运行最新版本的CF9。

知道为什么cfqueryparam导致性能爆炸?无论我刷新页面多少次,它每次都会以这种方式运行。如果我将列表配对只有2或3个哈希值,它仍然表现不佳,如150-200ms。当我取消cfqueryparam时,性能如预期。在这种情况下,有可能进行SQL注入,因此使用cfqueryparam肯定会更好,但是从索引列中找到2条记录不应该花费100毫秒。

编辑:

  1. 我们使用hash()而不是UUIDS或GUIDS生成的哈希值。哈希由hash(SerializeJSON({ struct }))生成,其中包含要对图像执行的一组操作的计划。这样做的目的是它允许我们在插入之前和查询之前知道该结构的确切唯一ID。这些哈希充当已经存储在DB中的结构的“索引”。除了哈希之外,相同的结构将散列到相同的结果,这对于UUIDS和GUIDS来说是不正确的。

  2. 正在5个不同的CF9服务器上执行查询,并且所有这些服务器都表现出相同的行为。对我来说,这排除了CF9缓存某些东西的想法。所有服务器都连接到完全相同的DB,因此如果发生缓存,则必须是数据库级别。

3 个答案:

答案 0 :(得分:8)

您的问题可能与VARCHAR和NVARCHAR有关。这两个链接可能有所帮助 Querying MS SQL Server G/UUIDs from ColdFusionnvarchar vs. varchar in SQL Server, BEWARE

如果cfqueryparam将varchars作为unicode发送,则ColdFusion管理员中可能会出现一个设置。如果该设置与列设置不匹配(在您的情况下,如果启用了该设置),则MS SQL将不使用该索引。

答案 1 :(得分:0)

正如Mark指出的那样,缓存中的执行计划可能很糟糕。 cfqueryparam的一个优点是,当您传入不同的值时,它可以重用它对该语句的缓存计划。这就是为什么当你尝试使用较小的列表时,你会发现没有任何改进。当您不使用cfqueryparam时,SQL Server必须每次都计算出执行计划。这通常是一件坏事,除非它在缓存中有一个次优计划。尝试按照http://www.devx.com/tips/Tip/14401中的说明清除缓存,这有望意味着下次使用cfqueryparam运行语句时,将缓存更好的计划。

有意义吗?

答案 2 :(得分:0)

我认为cfqueryparam不会导致问题。正如您在执行中提到的那样,在尝试使用cfqueryparam时,索引可能不会用于您的查询。我在我的开发计算机上创建了相同的场景,但是在使用和不使用cfqueryparam时我都有相同的执行时间。使用列表可能会有一些开销,因为在第一个查询中,您将其直接作为测试传递,而在第二个coldfusion中需要从提供的列表中的查询参数创建,但这应该不会那么多。我建议启动“SQL Server Profiler”并监视在服务器上执行的查询,这样可以让你更好地花费另外500毫秒。