我们有一个非常高的并发应用程序,其中一些要处理的密钥不断写入Oracle 11g表及其处理优先级.该表上有一个来自序列的主键(ID字段). KEY字段有一个UNIQUE约束.ID KEY PRIORITY-------------------------1 ...
我们有一个非常高的并发应用程序,其中一些要处理的密钥不断写入Oracle 11g表及其处理优先级.该表上有一个来自序列的主键(ID字段). KEY字段有一个UNIQUE约束.
ID KEY PRIORITY
-------------------------
1 ABC 0
2 XYZ 5
3 AZW 0
...
100 CNS 7
上面的表格以非常高的费率插入,比如说每分钟大约有一万条记录.我们还有大约100个并行消费者,这些消费者不断汇集上表寻找工作.一个这样的消费者一次只需要一个密钥来处理,但是关键的不是两个同时具有相同的密钥到一个以上的消费者.处理应在PRIORITY中进行,然后是ID顺序.
为了满足这一点,消费者最终通过调用如下的函数来结束:
FUNCTION select_key RETURN VARCHAR2
IS
v_key VARCHAR2(64) := NULL;
CURSOR keys IS
SELECT key
FROM my_table
ORDER BY priority, id
FOR UPDATE SKIP LOCKED;
BEGIN
OPEN keys
LOOP
FETCH keys INTO v_key;
EXIT WHEN keys%NOTFOUND;
DELETE FROM my_table WHERE key = v_key;
EXIT WHEN SQL%ROWCOUNT > 0;
END LOOP;
CLOSE keys;
RETURN v_key;
END;
因为这个表被插入和删除如此高的速率,该表上的统计数据很快变得陈旧.上述SELECT的执行计划显示全表扫描.这导致密钥选择过程花费的时间越来越长,性能随着时间的推移而显着降低.
除此之外,因为ORACLE锁定在数据块级而不是记录级别,我们经历的处理并不是真正发生在PRIORITY后面的ID顺序.这对我们来说不是一个大问题,但我们仍然希望避免这个问题.
这种方法的另一个更大的问题是,每次针对一个表运行一个完整的SQL,这个表可以很容易地获得几万条记录,只是为了获得一个密钥.
我想到的第一个想法就是为此使用一个真正的队列,让我的并发消费者从中获得服务.然而,我最终遇到了同步我的表和队列提要的所有问题,最终我放弃了这个想法.
关于如何更好地接近这一点的任何建议都将非常感激.
先感谢您.
解决方法:
在(PRIORITY,ID)上创建索引,然后查询可以使用INDEX FULL SCAN按顺序读取数据,而不是扫描整个表.
样本表和数据
drop table my_table;
create table my_table
(
key varchar2(100) not null,
id number not null,
priority number not null,
constraint my_table_pk primary key (key)
);
insert into my_table
select level, level, level
from dual connect by level <= 100000;
begin
dbms_stats.gather_table_stats(user, 'MY_TABLE');
end;
/
使用FULL TABLE SCAN的正常解释计划
explain plan for
select key
from my_table
order by priority, id;
select * from table(dbms_xplan.display);
Plan hash value: 3656711297
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100K| 1562K| | 637 (1)| 00:00:01 |
| 1 | SORT ORDER BY | | 100K| 1562K| 2760K| 637 (1)| 00:00:01 |
| 2 | TABLE ACCESS FULL| MY_TABLE | 100K| 1562K| | 103 (1)| 00:00:01 |
---------------------------------------------------------------------------------------
为更好的索引访问计划创建索引
一开始成本看起来并不好.但真正的版本应该快得多,因为它会很快停止处理.
create index my_table_idx on my_table(priority, id);
explain plan for
select key
from my_table
order by priority, id;
select * from table(dbms_xplan.display);
Plan hash value: 2209255802
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 100K| 1562K| 577 (1)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| MY_TABLE | 100K| 1562K| 577 (1)| 00:00:01 |
| 2 | INDEX FULL SCAN | MY_TABLE_IDX | 100K| | 292 (1)| 00:00:01 |
--------------------------------------------------------------------------------------------
本文标题为:java – Oracle表格就像一个队列
基础教程推荐
- Java异常架构和异常关键字图文详解 2022-11-25
- IDEA 高版本 PlantUML 插件默认主题修改的详细过程 2023-05-14
- Spring @value用法示例详解 2023-04-23
- Springboot启动原理详细讲解 2023-03-07
- Java实战宠物店在线交易平台的实现流程 2023-08-11
- Java Mybatis的初始化之Mapper.xml映射文件的详解 2023-04-17
- Java LinkedList实现班级信息管理系统 2022-11-01
- 详解Thymeleaf的三种循环遍历方式 2023-02-10
- Springboot打印接口的三种方式分享 2023-04-07
- Java中JSR303的基本使用详情 2023-05-25