为大量更新声明游标的正确方法

发布于 2024-08-22 13:17:52 字数 357 浏览 5 评论 0原文

我需要一些关于我的想法是否可行的建议。我遇到的情况是:

我需要对表的每一行进行更新。更新涉及一些逻辑。 逻辑很简单,但是需要对每一行进行操作。每行都有可能被更新。

目前,我正在考虑编写一个 ESQL/C 程序来执行此操作。我正在考虑将每一行加载到它的 相当于C结构,通过select for update游标,运行逻辑并提交。 HOLD关键字对光标起什么作用?我对这个角色有点困惑。

这些更新将在系统停机期间完成。该表包含大约 1.3 亿行。它有 约45列。大多数列的类型为 SMALLINT 和 INTEGER。

我走在正确的轨道上吗?欢迎提出建议。

数据库将是 Informix(IDS 版本 11.50 FC6)

I need some suggestions as to whether my idea is ok or not. I have a situation where:

I need to do updates to every row of a table. There is some logic involved in the updation.
The logic is very simple, but it needs to be done for every row. There is a possiblity of every row getting updated.

Currently, I'm thinking about writing an ESQL/C program to do this. I'm thinking about loading every row into its
equivalent C structure through a select for update cursor, run the logic and commit.
What role does the HOLD keyword do on the cursor? I'm bit confused about the role of this.

These updates will be done during a system downtime period. The table contains approximately 130 million rows. It has
about 45 columns. Most of the columns are of type SMALLINT and INTEGER.

Am I on the right track? Suggestions welcome.

The database will be Informix (IDS version 11.50 FC6)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

反话 2024-08-29 13:17:52

完成这项工作的关键是在服务器中完成工作,而不是让服务器选择每一行,将其传递给客户端,然后接受从客户端返回的数据。

UPDATE YourTable
   SET y = (CASE WHEN z > x THEN p ELSE y)
 WHERE key_column BETWEEN lo_val AND hi_val;

复杂的部分可能是将工作分解为可管理的子事务;这就是“lo_val .. hi_val”条件的含义。如果您的逻辑日志足够大,可以处理所有正在更新的 1.3 亿行[大约 (2 * (行大小 + X) * 行数),我相信 X 的值约为 20],并且有空闲空间,那么您可以一次性完成所有工作。显然,这会“更新”每一行。

如果您决定必须在客户端中执行此操作(这是一个错误,但是...),那么:

您使用带有 HOLD 的 SELECT 游标,以便它在事务中保持打开状态并正确定位。您启动一项事务,获取几千行,并根据需要更新每一行。确保您使用的是准备好的 UPDATE 语句;也许您使用 WHERE CURRENT OF 条件。


您是否建议将更新作为游标的一部分放入存储过程中?

不,尽管您可以在存储过程中执行此操作。这在一定程度上取决于这是否是您定期做的事情;如果是这样,也许存储过程是一个好主意,但我不会进行一次性练习。

这取决于您如何确定 lo_val 和 hi_val。我可能会使用 I4GL (因为我很熟悉它),然后我希望准备 UPDATE 语句(用问号代替“lo_val”和“hi_val”),然后我希望执行它多次,每次形成一个语句事务。因此,如果您决定使用 000000..099999、100000..199999、... 的 lo_val..hi_val 范围,那么您将进行迭代:

for i = 0 to 10000000 step 100000
    let j = i + 99999
    execute p_update using i, j
end for

在 I4GL 中,您绝对不需要使用准备好的语句。如果您有 IDS 11,则可以在 SPL 中准备语句。在早期版本中,并且不会对性能造成太大影响(我怀疑您是否可以可靠地测量它),您可以简单地使用:

CREATE PROCEDURE update_your_table()
    DEFINE lo_val, hi_val INTEGER;

    FOR lo_val = 0 TO 1000000 STEP 100000
        LET hi_val = lo_val + 99999;
        UPDATE YourTable
           SET y = (CASE WHEN z > x THEN p ELSE y)
         WHERE key_column BETWEEN lo_val AND hi_val;
    END FOR;

END PROCEDURE;

未经测试的代码 - 使用风险自负!

The key to making this work is to do the work in the server, rather than making the server select each row, pass it to the client, and then accept the data back from the client.

UPDATE YourTable
   SET y = (CASE WHEN z > x THEN p ELSE y)
 WHERE key_column BETWEEN lo_val AND hi_val;

The complicated part will likely be splitting the work into manageable sub-transactions; that's what the 'lo_val .. hi_val' condition is about. If your logical logs are big enough to handle all 130 million rows being updated [about (2 * (row size + X) * number of rows), with X being a value around 20, I believe] with space to spare, then you can do it all at once. Clearly, this 'updates' every row.

If you decide you must do it in the client (a mistake, but ...), then:

You use a SELECT cursor with HOLD so that it stays open and correctly positioned across transactions. You start a transaction, fetch a few thousand rows, updating each one as needed. Make sure you are using a prepared UPDATE statement; maybe you use a WHERE CURRENT OF condition.


Do you suggest to put the update as part of the cursor in a stored procedure?

No, though you could do it in a stored procedure. It depends in part on whether this is something you're going to do on a regular basis; if so, maybe the stored procedure is a good idea, but I wouldn't for a one-off exercise.

It depends on how you are going to determine lo_val and hi_val. I'd probably use I4GL (because I'm fluent in it) and then I'd expect to prepare the UPDATE statement (with question marks in place of 'lo_val' and 'hi_val'), and then I'd expect to execute it a number of times, each time forming a single statement transaction. So, if you decided to go with a ranges of lo_val..hi_val from 000000..099999, 100000..199999, ... then you'd iterate:

for i = 0 to 10000000 step 100000
    let j = i + 99999
    execute p_update using i, j
end for

In I4GL you would not absolutely need to use a prepared statement. If you have IDS 11, you can prepare statements in SPL. In earlier versions, and without much of a performance hit (I doubt if you could measure it reliably), you could simply use:

CREATE PROCEDURE update_your_table()
    DEFINE lo_val, hi_val INTEGER;

    FOR lo_val = 0 TO 1000000 STEP 100000
        LET hi_val = lo_val + 99999;
        UPDATE YourTable
           SET y = (CASE WHEN z > x THEN p ELSE y)
         WHERE key_column BETWEEN lo_val AND hi_val;
    END FOR;

END PROCEDURE;

Untested code - use at your own risk!

故事灯 2024-08-29 13:17:52

SPL 是正确的选择!...但我建议您复制该表并首先测试您的批量更新。

SPL is the way to go!.. but I suggest you replicate the table and test your mass update first.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文