【问题标题】:Updating record when table is empty - CF hangs表为空时更新记录 - CF 挂起
【发布时间】:2012-10-19 21:31:11
【问题描述】:

我昨天遇到了一些事情,我花了一段时间才弄清楚。在此代码中,当正在更新的表中不存在任何记录时,服务器会挂起,并且不会给出超时错误或任何错误。使用第二个表中的记录,代码可以正常工作。

<cfquery name="getSomething">
    SELECT one, two
    FROM some_table
    WHERE conditions = 'my conditions'
</cfquery>
<cfloop query="getSomething">
    <cfquery name="updateSomethingElse">
        UPDATE other_table
        SET three = 'my value'
        WHERE four = #getSomething.one#
        AND five = #getSomething.two#
    </cfquery>
    <!--- always run an insert --->
    <cfquery name="insertSomething">
        INSERT INTO other_table
        (columns)
        VALUES
        (values)
    </cfquery>
</cfloop>

我认为这是一个 CF 问题,因为在 Toad 中运行更新查询会在没有记录时完成人们所期望的 - 什么都没有。

我通过首先运行查询来获取第二个表中的记录计数来修复它,并且仅在记录计数大于 0 时才运行更新查询。

这是使用带有修补程序的 Oracle 10、CF 9.02。

注意:select查询返回2K/20K记录之间; 当第二个表中有现有记录时,更新和插入查询都可以正确运行; 删除更新查询允许插入查询运行,而不管第二个表中是否有记录。

编辑:我将探索将更新和插入查询移出循环,如下所示。我仍然认为最初的问题(为什么服务器在第二个表中没有记录的情况下挂起)尚未得到回答。

【问题讨论】:

  • “表格中有记录,代码工作正常。” - 不,它没有;您缺少 cfloop 查询属性的结束引号。如果没有记录,查询循环将不会执行其主体,因此这里肯定有比您在此处显示的更多内容。
  • 这只是我为演示问题而输入的内容。实际代码是正确的——正如我所提到的,当表中有记录时它运行良好。此外,选择查询返回 2K 到 20K 记录,具体取决于传递的参数 int。
  • 提供实际代码(过滤/删除敏感/重复信息)总是让事情变得更容易和更清晰......
  • 您目前似乎正在对每一次 2-20K 循环迭代运行更新。如果是这样,请将其移出循环,使其运行一次,(理想情况下,也可以执行插入/选择组合 Matt 建议)。

标签: oracle coldfusion oracle10g sql-update coldfusion-9


【解决方案1】:

如果没有返回记录,服务器将不会挂在 UPDATE 上,因为它永远不会到达 UPDATE 语句。我建议在没有返回记录时删除您的 UPDATE 查询并在循环中仅输出“记录”。服务器应该仍然挂起,所以你可以排除你的 UPDATE 是问题

但是,为什么不添加记录检查呢?

<cfquery name="getSomething">
SELECT one, two
FROM some_table
WHERE conditions = 'my conditions'
</cfquery>

<cfloop query="getSomething">
 <cfif getSomething.RecordCount>
  <cfquery name="updateSomethingElse">
  UPDATE other_table
  SET three = 'my value'
  WHERE conditions = 'other conditions'
  </cfquery>
 </cfif>
 <cfquery>
 INSERT
 </cfquery>
</cfloop>

我还建议使用将两个表连接在一起的 UPDATE 语句。如果您使用 12,000 次更新来访问数据库,则可能至少需要十分钟,而运行下面的代码将花费更少的时间。

<cfquery name="updateSomethingElse">
UPDATE other_table
SET three = 'my value'
FROM some_table, other_table
WHERE some_table.id = other_table.id
AND some_table.conditions = 'my conditions'
AND other_table.conditions = 'other conditions'
</cfquery>
<cfquery name="getSomething">
INSERT INTO other_table (one, two)
SELECT one, two
FROM some_table
WHERE conditions = 'my conditions'
</cfquery>

【讨论】:

  • 好吧,我运行循环的原因是我还在更新后执行插入查询,每次循环都必须执行此操作。即使有 20K 记录,20K 更新和 20K 插入也会在不到一分钟的时间内发生。这是一项管理功能,其中较早的记录得到更新(基本上变为非活动状态)并同时插入新记录,并且通常每年只由管理员运行一次左右。不过,我会考虑您对更新声明的建议 - 这听起来很有可能。
  • 我更新了我的答案以更好地满足您的问题。您也可以执行 INSERT/SELECT 语句,因此无论返回多少条记录,您都只运行 2 个查询
  • 您还可以运行合并,以便它插入或更新,因为目标表是相同的。
  • iivel,MERGE 是要走的路,事实证明...花了一点时间来弄清楚这个查询的语法,但是伙计,与我之前的方式相比,速度有那么快吗这样做!
  • 我应该把它放在我的答案而不是评论中,我明天会更新详细信息,以便将来的搜索者可以使用。但是,是的,合并是一个很棒的功能。
【解决方案2】:

至于为什么挂起,是对数据库的调用还是在评估第二个查询时挂起[我猜你的意思是第二个表是空的]。我似乎记得这样的问题,我只能使用您注意到的相同方法来解决,但是 - 第二个 cfquery 并不是绝对必要的,因为您可以使用子选择并在选择时更新。如果更新中的条件是从第一个查询生成的,则可能会创建笛卡尔积,从而导致查询运行时间过长(取决于您的超时设置,实际上不会超时)。

我会对完整的查询感兴趣,因为另一种方法是消除循环的必要性,让数据库做数据库的工作。 Oracle 允许基于 select 进行更新,因此您将拥有:

UPDATE other_table OT
SET OT.three = ( SELECT one 
                 FROM some_table ST
                 INNER JOIN OT
                      ON OT.whatever = ST.stuff
                 WHERE conditions = 'conditions')
WHERE other_conditions = 'other conditions'

鉴于您已明确声明您需要能够从初始表中进行选择,然后进行更新或删除,您可以使用合并命令,合并操作实际上是插入或更新(有时称为插入)。 Wikipedia 链接实际上非常清楚如何构建语法。

http://en.wikipedia.org/wiki/Merge_(SQL)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-07
    • 1970-01-01
    • 1970-01-01
    • 2012-03-05
    • 2012-08-26
    • 1970-01-01
    相关资源
    最近更新 更多