【问题标题】:Why is Oracle losing data during commit?为什么 Oracle 在提交期间会丢失数据?
【发布时间】:2014-11-10 21:12:38
【问题描述】:

我有一个相当标准的 SQL 查询如下:

TRUNCATE TABLE TABLE_NAME;
INSERT INTO TABLE_NAME 
(
UPRN,
SAO_START_NUMBER,
SAO_START_SUFFIX,
SAO_END_NUMBER,
SAO_END_SUFFIX,
SAO_TEXT,
PAO_START_NUMBER,
PAO_START_SUFFIX,
PAO_END_NUMBER,
PAO_END_SUFFIX,
PAO_TEXT,
STREET_DESCRIPTOR,
TOWN_NAME,
POSTCODE,
XY_COORD,
EASTING,
NORTHING,
ADDRESS
)
SELECT  
BASIC_LAND_AND_PROPERTY_UNIT.UPRN, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_START_NUMBER AS SAO_START_NUMBER, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_START_SUFFIX AS SAO_START_SUFFIX, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_END_NUMBER AS SAO_END_NUMBER, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_END_SUFFIX AS SAO_END_SUFFIX, 
LAND_AND_PROPERTY_IDENTIFIER.SAO_TEXT AS SAO_TEXT, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_START_NUMBER AS PAO_START_NUMBER, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_START_SUFFIX AS PAO_START_SUFFIX, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_END_NUMBER AS PAO_END_NUMBER, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_END_SUFFIX AS PAO_END_SUFFIX, 
LAND_AND_PROPERTY_IDENTIFIER.PAO_TEXT AS PAO_TEXT, 
STREET_DESCRIPTOR.STREET_DESCRIPTOR AS STREET_DESCRIPTOR, 
STREET_DESCRIPTOR.TOWN_NAME AS TOWN_NAME, 
LAND_AND_PROPERTY_IDENTIFIER.POSTCODE AS POSTCODE, 
BASIC_LAND_AND_PROPERTY_UNIT.GEOMETRY AS XY_COORD, 
BASIC_LAND_AND_PROPERTY_UNIT.X_COORDINATE AS EASTING, 
BASIC_LAND_AND_PROPERTY_UNIT.Y_COORDINATE AS NORTHING,
decode(SAO_START_NUMBER,null,null,SAO_START_NUMBER||SAO_START_SUFFIX||' ')
||decode(SAO_END_NUMBER,null,null,SAO_END_NUMBER||SAO_END_SUFFIX||' ')
||decode(SAO_TEXT,null,null,SAO_TEXT||' ')
||decode(PAO_START_NUMBER,null,null,PAO_START_NUMBER||PAO_START_SUFFIX||' ')
||decode(PAO_END_NUMBER,null,null,PAO_END_NUMBER||PAO_END_SUFFIX||' ')
||decode(PAO_TEXT,null,null,'STREET RECORD',null,PAO_TEXT||' ')
||decode(STREET_DESCRIPTOR,null,null,STREET_DESCRIPTOR||' ')
||decode(POST_TOWN,null,null,POST_TOWN||' ')
||Decode(Postcode,Null,Null,Postcode)  As Address 
From (Land_And_Property_Identifier
      Inner Join Basic_Land_And_Property_Unit
        On Land_And_Property_Identifier.Uprn = Basic_Land_And_Property_Unit.Uprn)  
Inner Join Street_Descriptor
  On Land_And_Property_Identifier.Usrn = Street_Descriptor.Usrn
Where Land_And_Property_Identifier.Postally_Addressable='Y';

如果我在 SQL Developer 中运行此查询,它会在插入 180 万个功能时运行良好(会话中的select count(*) from TABLE_NAME 证实了这一点)。

但是当我运行提交时,数据消失了! select count(*) from TABLE_NAME 现在返回 0 个结果。

我们已经做了很多事情来尝试看看发生了什么:

  • Truncate 期间,表空间被释放,并在插入期间再次填充。提交期间没有任何变化。这意味着数据在数据库中。

  • 如果我执行完全相同的查询,但在末尾附加了and rownum < 100,则提交有效。与1000 相同。

  • 我发现了这个问题:oracle commit kills 并让我们的 DBA 尝试“SQL Trace”。这产生了一个 >4GB 的文件,当用 TKPROF 解析时产生了一个 120 页的报告,但我们不知道如何阅读它,而且那里没有明显的错误。

  • 我们的错误日志中没有任何内容。而且在提交过程中显然没有错误。

  • 有一个触发器/序列在此过程中确实增加了 180 万。

我现在已经重复了大约 4 次,但结果总是一样。

所以我的问题很简单——提交期间数据发生了什么?我们怎样才能知道?谢谢。

注意:这在过去运行良好,所以我认为 SQL 本身没有任何问题。


编辑:问题已解决通过从头开始重新创建表。现在,当我插入时,与之前的 2000 年相比,它只需要 500 秒。而且提交是即时的;当它被破坏时,提交花了 4000 秒! 我仍然不知道为什么会这样。


对于那些询问,创建表语法:

CREATE TABLE TABLE_NAME
(
ADDRESS                                            VARCHAR2(4000),
UPRN                                               NUMBER(12),
SAO_START_NUMBER                                   NUMBER(4),
SAO_START_SUFFIX                                   VARCHAR2(1),
SAO_END_NUMBER                                     NUMBER(4),
SAO_END_SUFFIX                                     VARCHAR2(1),
SAO_TEXT                                           VARCHAR2(90),
PAO_START_NUMBER                                   NUMBER(4),
PAO_START_SUFFIX                                   VARCHAR2(1),
PAO_END_NUMBER                                     NUMBER(4),
PAO_END_SUFFIX                                     VARCHAR2(1),
PAO_TEXT                                           VARCHAR2(90),
STREET_DESCRIPTOR                                  VARCHAR2(100),
TOWN_NAME                                          VARCHAR2(30),
POSTCODE                                           VARCHAR2(8),
XY_COORD                                           MDSYS.SDO_GEOMETRY,
EASTING                                            NUMBER(7),
NORTHING                                           NUMBER(7)
)

CREATE INDEX TABLE_NAME_ADD_IDX ON TABLE_NAME (ADDRESS);

【问题讨论】:

  • :检查表的脚本,可能是全局临时表,在提交时截断数据。http://www.oracle-base.com/articles/8i/temporary-tables.php
  • 你对表有约束吗(尤其是延迟约束)?您是否定义了提交物化视图?这些是我能想到的唯一可能导致提交失败的事情(尽管在任何情况下您都应该收到错误消息)。
  • @GauravSoni - 感谢您的建议。它是在 SQL Developer 中使用普通“创建”创建的常规表。语法:CREATE TABLE TABLE_NAME ( ... some columns ... )
  • @VincentMalgrat - 我不是 Oracle 类型,所以不知道它们是什么。正如我在另一条消息中所指出的,据我所知,它应该只是一张普通的桌子。我还没有尝试删除表并重新创建它。我认为这是下一个。
  • @Rachcha: count() 不会溢出

标签: oracle oracle10g


【解决方案1】:

如果将交易包装在匿名块中,是否还会丢失数据?

我的猜测是您在 SQL Developer 中打开了两个 SQL 窗口,这意味着两个单独的会话。即在窗口 1 中运行 SQL 代码并提交;在窗口 2 中不会提交在窗口 1 中所做的更改。

截断表执行隐式提交。因此,在插入 + 提交完成之前,该表将是空的。

begin
  execute immediate 'truncate table table_name reuse storage'; --use "reuse" if you know the data will be of similar size
  -- implicit commit has occured and the table is empty for all sessions
  insert into table_name (lots)
     select lots from table2;
  commit;
end;

您应该将 truncate 与重用存储一起使用,这样数据库就不会为了在插入中获取相同数量的块而释放所有块。

如果您希望/需要随时提供数据,则更好(但更长)的方法是

begin
   savepoint letsgo;
   delete from table_name;
   insert into table_name (lots)
   select lots from table2;
   commit;
exception
   when others then
      rollback to letsgo;
end;

【讨论】:

    【解决方案2】:

    可能你有一个你没有注意到的触发器。你能检查一下 oracle 的 recyclebin 表,它可能存储了你删除的表和触发器的历史记录吗?

    Select * from recyclebin;
    

    参考:http://www.oraclebin.com/2012/12/recyclebinflashback.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-10
      • 2015-06-10
      • 2021-01-11
      相关资源
      最近更新 更多