首页 > 解决方案 > Oracle - 大量插入的策略,但仅在 OLTP 环境中使用最后一个插入

问题描述

我每 30 秒向 Oracle OLTP 表中插入 10000 行。这大约每半小时有 240Mb 的数据。所有 10000 行都具有相同的时间戳,我将其设置为 30 秒的边界。我还有 3 个索引,其中之一是空间点几何索引(纬度和经度)。时间戳也被索引。

在测试期间,2 个 CPU 的利用率为 50%,输入/输出的利用率为 80%,半小时后插入的持续时间增加了一倍。

我还从表中选择通过使用子查询查找最大时间戳来获取最后插入的时间戳 10000 行,因为这是两个不同的过程(用于插入的 Python 和用于选择的谷歌地图)。我尝试采用一种策略,尝试使用当前时间来检索最后 10000 行,但即使在最后 10000 行之前,我也无法让它工作。它通常不返回任何行。

我的问题是如何有效地检索最后插入的 10000 行,以及在所有 10000 行都具有相同时间戳值的情况下,哪种类型的索引和/或表最合适。然而,保持插入时间较短且持续时间不加倍更为重要,因此不确定是否需要额外的历史表,同时只保留当前表中的最后一行;但这肯定会使 IO 数量增加一倍,这似乎是目前最大的问题。任何建议将被认真考虑。

标签: oracleindexinginserthistory

解决方案


数据库可以“走”下索引的“右手边”以非常快速地获得最大值。这是一个例子

SQL> create table t ( ts date not null, x int, y int, z int );

Table created.

SQL>
SQL> begin
  2   for i in 1 .. 100
  3   loop
  4      insert into t
  5      select sysdate, rownum, rownum, rownum
  6      from dual
  7      connect by level <= 10000;
  8      commit;
  9   end loop;
 10  end;
 11  /

PL/SQL procedure successfully completed.

SQL>
SQL> create index ix on t (ts );

Index created.

SQL>
SQL> set autotrace on
SQL> select max(ts) from t;

MAX(TS)
---------
12-JUN-20

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1223533863

-----------------------------------------------------------------------------------
| Id  | Operation                  | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |      |     1 |     9 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE            |      |     1 |     9 |            |          |
|   2 |   INDEX FULL SCAN (MIN/MAX)| IX   |     1 |     9 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)


Statistics
----------------------------------------------------------
          6  recursive calls
          0  db block gets
         92  consistent gets
          8  physical reads
          0  redo size
        554  bytes sent via SQL*Net to client
        383  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

所以 92 一致的获取非常快......但是,您可以通过使用降序读取的索引跳过最后一个叶块来更好地执行,例如

SQL> select *
  2  from (
  3  select ts from t order by ts desc
  4  )
  5  where rownum = 1;

TS
---------
12-JUN-20

1 row selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3852867534

-------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |     1 |     9 |     3   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY               |      |       |       |            |          |
|   2 |   VIEW                       |      |  1184K|    10M|     3   (0)| 00:00:01 |
|   3 |    INDEX FULL SCAN DESCENDING| IX   |  1184K|    10M|     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM=1)

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)


Statistics
----------------------------------------------------------
          9  recursive calls
          5  db block gets
          9  consistent gets
          0  physical reads
       1024  redo size
        549  bytes sent via SQL*Net to client
        430  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

所以你当前的索引很好。只需按照上述方式获得最高时间戳,您就可以开始了


推荐阅读