【问题标题】:Is it possible for Oracle to insert two rows with the same created date?Oracle 是否可以插入具有相同创建日期的两行?
【发布时间】:2013-09-22 23:37:34
【问题描述】:

我正在运行 Oracle 11g RAC。

我的表上有一个FOR EACH ROW BEFORE INSERT 触发器,它使用sysdate 填充CREATED_DATE (DATE)

DATE 数据类型有什么粒度?当通过这样的触发器填充时,两行是否有可能在 RAC 中具有完全相同的 INSERT 日期/时间?

【问题讨论】:

    标签: date triggers insert oracle11g


    【解决方案1】:

    即使没有 RAC,也很容易实现。

    17:25:47 (455)SYSTEM@dwal> create table t (k int primary key, d date);
    
    Table created.
    
    Elapsed: 00:00:00.35
    17:32:00 (455)SYSTEM@dwal> ed
    Wrote file S:\spool\dwal\BUF_SYSTEM_455.sql
    
      1  create trigger t_bi before insert on t for each row
      2  begin
      3  :new.d := sysdate;
      4* end;
    17:32:04 (455)SYSTEM@dwal> /
    
    Trigger created.
    
    Elapsed: 00:00:00.10
    17:32:04 (455)SYSTEM@dwal> insert into t(k) select rownum from dual connect by rownum <= 1e3;
    
    1000 rows created.
    
    Elapsed: 00:00:00.02
    17:32:30 (455)SYSTEM@dwal> select d, count(*) from t group by d;
    
    D                     COUNT(*)
    ------------------- ----------
    18.09.2013 17:32:37       1000
    
    Elapsed: 00:00:00.01
    

    DATE 类型的粒度以秒为单位,如果您想要更粒度的内容,您可能需要使用 TIMESTAMP:

    17:34:51 (455)SYSTEM@dwal> alter table t add (ts timestamp);
    
    Table altered.
    
    Elapsed: 00:00:00.17
    17:36:01 (455)SYSTEM@dwal> ed
    Wrote file S:\spool\dwal\BUF_SYSTEM_455.sql
    
      1  create or replace trigger t_bi before insert on t for each row
      2  begin
      3  :new.d := sysdate;
      4  :new.ts := systimestamp;
      5* end;
    17:36:05 (455)SYSTEM@dwal> /
    
    Trigger created.
    
    Elapsed: 00:00:00.13
    17:36:05 (455)SYSTEM@dwal> insert into t(k) select rownum from dual connect by rownum <= 1e3;
    
    1000 rows created.
    
    Elapsed: 00:00:00.12
    17:36:47 (455)SYSTEM@dwal> select d, min(ts) mn, max(ts) mx, count(*) from t group by d;
    
    D                   MN                             MX                               COUNT(*)
    ------------------- ------------------------------ ------------------------------ ----------
    18.09.2013 17:36:19 18-SEP-13 05.36.19.481071 PM   18-SEP-13 05.36.19.593846 PM         1000
    
    Elapsed: 00:00:00.02
    

    【讨论】:

      【解决方案2】:

      From the manual

      对于每个 DATE 值,Oracle 存储以下信息:年、月、日、小时、分钟和秒

      因此,如果两个插入发生在同一秒内,那么是的,这些列可以具有相同的值。

      如果您需要更细粒度的时间信息,您应该使用TIMESTAMP 列,该列还可以存储最多 9 位的小数秒。但是在高流量系统上,我认为仍然可能发生两个插入在同一毫秒发生的情况

      【讨论】:

      • 实际上最多 9 位数字。如果您不指定精度,则默认为 6。
      【解决方案3】:

      当您在 SQL 语句中引用 sysdate 时,只使用一个 sysdate 值。

      因此,如果您执行 1,000,000 条记录的插入,包括将 sysdate 分配给 CREATED_AT 列,并且插入需要 15 分钟,那么所有 1,000,000 条记录将具有相同的 CREATED_AT 值。

      但是,当 CREATED_AT 的值由触发器填充时,我相信每次触发器执行都会重新评估其值。 AskTom 对此进行了讨论。其中一个结论是,当您需要在从 SQL 调用的函数中使用 SYSDATE 时,如果时间很关键,可能需要从 SQL 语句中传入 SYSDATE 的值,因为长时间运行的语句或过程可能是引用 SYSDATE 的多个值。

      我相信这同样适用于 TIMESTAMP 值。

      因此,您不能依赖 created_at 列来提供唯一性。这应该是通过序列生成值来实现的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-24
        • 1970-01-01
        • 1970-01-01
        • 2021-11-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多