如何解决为什么在使用 Node.js 将数千行插入 Oracle 表时会发生这种情况?
我是 Oracle 的新手,我正在寻找将数千(可能数百万)条记录插入到表中的最佳方法。
我已经看到有关这种情况的其他问题和答案,但在此 answer 中,PL/SQL 代码使用了两个标量类型 (PSL_INTEGER) 关联数组,并用作表列,我需要相同的但有一个记录/复杂类型的嵌套表,用于在表中作为一行插入。
首先,我使用 oracledb 包 (v 5.1.0) 在 Node.js (TypeScript) 中有此代码:
let data: Array<DataModel>;
// data's variable is populated with data and 'DataModel' is an interface,// data is an array with a the exact table's structure:
// [
// { C_ONE: 'mike',C_TWO: 'hugman',C_THREE: '34',... with other 12 columns },// { C_ONE: 'robert',C_TWO: 'zuck',// { C_ONE: 'john',C_TWO: 'gates',... with other 12 columns }
// ]
let context;
try {
context = await oracledb.getConnection({
user: 'admin',password: 'admin',connectString: 'blabla'
});
const result = await context.execute(
// My SP
'BEGIN PACKAGE_TEST.SP_TEST_STRESS(:p_data,:p_status); END;',{
// My JSON Array
p_data: {
type: 'PACKAGE_TEST.T_STRESS',val: data
},// Variable for check if all success or fails... this doesn't matters :)
p_status: {
type: oracledb.NUMBER,val: 1,dir: oracledb.BIND_OUT
}
},{ autoCommit: true }
);
console.log(result);
if ((result.outBinds as { p_status: number }).p_status === 0) {
// Correct
}
else {
// Failed
}
} catch (error) {
// bla bla for errors
} finally {
if (context) {
try {
await context.close();
} catch (error) {
// bla bla for errors
}
}
}
以及我的 sotore 过程的 PL/SQL 代码:
CREATE OR REPLACE PACKAGE PACKAGE_TEST
IS
TYPE R_STRESS IS RECORD
(
C_ONE VARCHAR(50),C_TWO VARCHAR(500),C_THREE VARCHAR(10),C_FOUR VARCHAR(100),C_FIVE VARCHAR(10),C_SIX VARCHAR(100),C_SEVEN VARCHAR(50),C_EIGHT VARCHAR(50),C_NINE VARCHAR(50),C_TEN VARCHAR(50),C_ELEVEN VARCHAR(50),C_TWELVE VARCHAR(50),C_THIRTEEN VARCHAR(300),C_FOURTEEN VARCHAR(100),C_FIVETEEN VARCHAR(300),C_SIXTEEN VARCHAR(50)
);
TYPE T_STRESS IS VARRAY(213627) OF R_STRESS;
PROCEDURE SP_TEST_STRESS
(
P_DATA_FOR_PROCESS T_STRESS,P_STATUS OUT NUMBER
);
END;
/
CREATE OR REPLACE PACKAGE BODY PACKAGE_TEST
IS
PROCEDURE SP_TEST_STRESS
(
P_DATA_FOR_PROCESS T_STRESS,P_STATUS OUT NUMBER
)
IS
BEGIN
DBMS_OUTPUT.put_line('started');
BEGIN
FORALL i IN 1 .. P_DATA_FOR_PROCESS.COUNT
INSERT INTO TEST_STRESS
(
C_ONE,C_TWO,C_THREE,C_FOUR,C_FIVE,C_SIX,C_SEVEN,C_EIGHT,C_NINE,C_TEN,C_ELEVEN,C_TWELVE,C_THIRTEEN,C_FOURTEEN,C_FIVETEEN,C_SIXTEEN
)
VALUES
(
P_DATA_FOR_PROCESS(i).C_ONE,P_DATA_FOR_PROCESS(i).C_TWO,P_DATA_FOR_PROCESS(i).C_THREE,P_DATA_FOR_PROCESS(i).C_FOUR,P_DATA_FOR_PROCESS(i).C_FIVE,P_DATA_FOR_PROCESS(i).C_SIX,P_DATA_FOR_PROCESS(i).C_SEVEN,P_DATA_FOR_PROCESS(i).C_EIGHT,P_DATA_FOR_PROCESS(i).C_NINE,P_DATA_FOR_PROCESS(i).C_TEN,P_DATA_FOR_PROCESS(i).C_ELEVEN,P_DATA_FOR_PROCESS(i).C_TWELVE,P_DATA_FOR_PROCESS(i).C_THIRTEEN,P_DATA_FOR_PROCESS(i).C_FOURTEEN,P_DATA_FOR_PROCESS(i).C_FIVETEEN,P_DATA_FOR_PROCESS(i).C_SIXTEEN
);
EXCEPTION
WHEN OTHERS THEN
p_status := 1;
END;
P_STATUS := 0;
END;
END;
还有我的目标表:
CREATE TABLE TEST_STRESS
(
C_ONE VARCHAR(50),C_SIXTEEN VARCHAR(50)
);
在这种情况下会发生有趣的行为:
-
如果我发送包含 200 行的 JSON 数组,则效果很好,我不知道成功完成所需的确切时间,但是 我可以说是毫秒。
-
如果我发送包含 200,000 行的 JSON 数组,这需要三到四分钟的等待时间,promise 得到解决并抛出一个类型的异常:ORA-04036:实例超过 PGA_AGGREGATE_LIMIT
这个是在将JSON数组传递给procedure参数的时候出现的,看来处理的时候开销太大了。
- 为什么在第二种情况下会发生这种情况?
- 是否有限制 NESTED TABLE TYPES 中的行数还是Node.js 的任何配置(默认)?
- Oracle 建议 增加 pga_aggregate_limit 但在我的 SQLDeveloper 中看到它 "show parameter pga;" 是3G,是不是表示我的信息 发送是否超过 3 GB?正常吗?
- 是否有更可行的解决方案 不影响数据库的性能?
感谢您的帮助。
解决方法
每个服务器进程都有自己的 PGA,所以我猜这会导致当前运行的所有进程的总聚合 PGA 超过 3 GB。
我认为这是因为您的包裹内部发生了什么,但您只显示了规范,因此无法判断那里发生了什么。
您没有使用嵌套表类型。您正在使用 varray。 varray 的 maximum length 为 2,147,483,647。
听起来您在程序内部执行了一些操作以使用过多内存。也许您需要分块处理 200,000 行?如果没有关于您要执行的操作的更多信息,您是否可以使用其他一些进程来加载数据,例如 sqlldr?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。