Oracle - 大量插入的策略,但仅在 OLTP 环境中使用最后一次插入
Oracle - strategy for large number of inserts but only using last insert in an OLTP environment
我每 30 秒向 Oracle OLTP table 插入 10000 行。这大约是每半小时 240Mb 的数据。所有 10000 行都具有相同的时间戳,我将其设置为 30 秒边界。我还有 3 个索引,其中一个是空间点几何索引(纬度和经度)。时间戳也被编入索引。
在测试期间,2 个 CPU 显示 50% 的利用率,Input/Output 显示 80%,半小时后插入的持续时间加倍。
我还从 table select 通过使用子查询查找最大时间戳来获取最后插入的时间戳 10000 行,因为这是两个不同的进程(Python 用于插入,google 映射用于 select)。我尝试采用一种策略,即我尝试使用当前时间来检索最后 10000 行,但即使在最后 10000 行之前,我也无法让它工作。它经常不返回任何行。
我的问题是如何有效地检索最后插入的 10000 行以及哪种类型的索引 and/or table 最适合所有 10000 行具有相同时间戳值的情况。然而,保持插入时间低并且持续时间不加倍更为重要,因此不确定是否还需要历史记录 table 而只保留当前 table 中的最后一行;但可以肯定的是,这将使 IO 的数量增加一倍,这似乎是目前最大的问题。任何建议将不胜感激。
数据库可以 "walk" 向下索引 "right hand side" 以非常快速地获得最大值。这是一个例子
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
所以您当前的索引没有问题。只需按照上面的方法获取最高时间戳,就可以了
我每 30 秒向 Oracle OLTP table 插入 10000 行。这大约是每半小时 240Mb 的数据。所有 10000 行都具有相同的时间戳,我将其设置为 30 秒边界。我还有 3 个索引,其中一个是空间点几何索引(纬度和经度)。时间戳也被编入索引。
在测试期间,2 个 CPU 显示 50% 的利用率,Input/Output 显示 80%,半小时后插入的持续时间加倍。
我还从 table select 通过使用子查询查找最大时间戳来获取最后插入的时间戳 10000 行,因为这是两个不同的进程(Python 用于插入,google 映射用于 select)。我尝试采用一种策略,即我尝试使用当前时间来检索最后 10000 行,但即使在最后 10000 行之前,我也无法让它工作。它经常不返回任何行。
我的问题是如何有效地检索最后插入的 10000 行以及哪种类型的索引 and/or table 最适合所有 10000 行具有相同时间戳值的情况。然而,保持插入时间低并且持续时间不加倍更为重要,因此不确定是否还需要历史记录 table 而只保留当前 table 中的最后一行;但可以肯定的是,这将使 IO 的数量增加一倍,这似乎是目前最大的问题。任何建议将不胜感激。
数据库可以 "walk" 向下索引 "right hand side" 以非常快速地获得最大值。这是一个例子
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
所以您当前的索引没有问题。只需按照上面的方法获取最高时间戳,就可以了