Oracle - 有什么方法可以查看对特定表的未提交更改吗?

con*_*att 25 oracle oracle-10g transaction

我目前正在通过批处理进行调试,该批处理执行大量 DML 语句,但不会立即执行提交。能够在事务未提交的情况下查看来自另一个会话的“待处理”更改会很好。这可能吗?

例子:

Insert into table myTable (col1, col2) values ("col1", "col2");

--Somehow view the pending transaction maybe by system view?....

...other DML statements....

commit;
Run Code Online (Sandbox Code Playgroud)

Jus*_*ave 18

根据批处理的详细信息以及尝试查看未提交更改的原因,有几种不同的方法。

1) Oracle Workspace Manager是一种工具,最初设计用于允许开发 Spatial 应用程序的人员拥有相当于超长时间运行的事务(即可能需要数天或数周的人来确定在一个事务中运行管道的位置的事务) )。您的批处理过程可以创建一个新的工作区(逻辑上类似于创建一个新事务),在该工作区中进行任何想要的更改,同时随时提交。在单独的会话中,您将不会看到任何已提交的更改,直到您进入批处理的工作区。批处理完成后,它可以将其工作区合并回活动工作区,这相当于提交事务。

2) DBMS_XA 包可用于允许您将事务从一个会话“移交”到另一个会话,并允许一个会话连接到另一个会话启动的事务。这是一个使用起来相当晦涩的包,但最近在PL/SQL Challenge(您可能需要一个免费帐户才能访问它)中有一个使用它的好例子。

3) 如果您只是想查看批处理的状态而不是查看实际数据,批处理可以使用自治事务写入日志信息,然后您可以从另一个会话中查询这些信息。或者您可以使用DBMS_APPLICATION_INFO 包让您的应用程序更新 V$SESSION 和/或 V$SESSION_LONGOPS 中的各种属性,以便您可以监视来自另一个会话的负载状态。


Vin*_*rat 11

编辑:这是在澄清问题之前写的

您可以使用闪回查询来查看没有您自己的未提交数据的表。

考虑:

SQL> CREATE TABLE my_table
  2  AS SELECT ROWNUM ID FROM dual CONNECT BY LEVEL <= 5;

Table created

SQL> INSERT INTO my_table VALUES (6);

1 row inserted
Run Code Online (Sandbox Code Playgroud)

要查看我的交易表和其他人看到的表之间的区别,我可以发出:

SQL> SELECT * FROM my_table
  2  MINUS
  3  SELECT * FROM my_table AS OF TIMESTAMP (systimestamp);

        ID
----------
         6
Run Code Online (Sandbox Code Playgroud)

  • @jack:不清楚 OP 是否希望在其会话之外查看未提交的数据(伪脚本可能在单个会话中)。我的回答只适用于查看自己对表格的未决修改。 (2认同)

Jac*_*las 8

Oracle没有的是读未提交隔离模式。换句话说,您将无法在另一个事务中查询未提交的数据。

有多种方法可以从长时间运行的事务中获取信息——目前没有提到的一种是自主事务(应谨慎使用)


Gai*_*ius 8

是的 - LogMiner可以做到这一点。事实上,如果你只想要提交的事务,你必须专门过滤输出!还有就是TABLE_NAMEV$LOGMINER_CONTENTS,这就是你会怎么看待一个表。


Ker*_*tts 5

没有直接的方法;您要么必须解析日志(如另一个答案中所述),要么使用替代方法来查看长时间运行的过程中发生的情况。

就个人而言,我建议使用自治事务来启用此功能——不是在事务本身上,而是作为一种让您知道发生了什么的日志机制。例如,您可以让 PROCEDURE LONG_ACTION 调用 PROCEDURE WRITE_LOG_ENTRY(定义为自治事务),将 VARCHAR2 写入另一个表。自治事务不会干扰您当前的事务(从逻辑角度;注意对性能的潜在影响),因此无论当前事务中是 COMMIT 还是 ROLLBACK,您都可以通过日志条目查看发生了什么。也就是说,你可以用一个庞大的 DML 语句来做到这一点;你必须使用一个循环。

考虑:

TABLE LOG_ENTRIES defined as
    activity_date  date,
    log_entry varchar2(2000)

TABLE BIG_JOB (definition doesn't really matter)

PROCEDURE WRITE_LOG_ENTRY
                        ( str VARCHAR2 )
IS
    PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
    INSERT INTO LOG_ENTRIES VALUES ( SYSDATE, str );
    COMMIT;
END;

PROCEDURE LONG_ACTION IS
    c NUMBER;
BEGIN
    FOR r IN ( SELECT * FROM BIG_JOB )
    LOOP
       c := c + 1;
       UPDATE BIG_JOB z
          SET fld = hairy_calculation
        WHERE z.rowid = r.rowid;
       IF MOD(c,500) = 0 THEN
           WRITE_LOG_ENTRY ( c || ' rows processed.' );
       END IF;
    END LOOP;
    COMMIT;
END;
Run Code Online (Sandbox Code Playgroud)

鉴于上述情况,无论长期操作是否成功,您都会为每处理 500 行获得一个日志条目。如果您需要完全复制数据以查看其工作状态,我建议制作一个复制表并调用一个将复制数据的过程(该过程是一个自治事务)。然后事后核对数据。(无需重复。)

此外,如果这是出于调试目的,我建议在测试后删除或大幅减少对此类日志记录的需求。而且,一如既往,在您自己的系统上测试、测试、测试以验证事情将如何运作。(有关日志记录如何极大地影响性能的一个很好的例子,请参阅 Niall 的评论。)

(最后,因为我之前忽略了它:当心自治事务。在实施之前充分理解它们,不要“仅仅因为”使用它们。它们可能以一百万种方式错误地使用(例如,尝试尝试避免触发器中的突变错误),所以如果可能的话,总是最好找到替代方案。如果你不能,那么请谨慎行事。在长时间运行的操作期间记录一直是一种相当安全的情况(忽略性能问题),但不要在不知道后果的情况下急于将其应用于其他用途。)