【发布时间】:2020-07-02 12:05:46
【问题描述】:
我们的 Oracle DB 中有一个包含 200 列的表,我们必须将其插入其中,并且我们有一个 C 程序在该表中插入请求,它使用 Pro*C 调用 oracle DB 中的存储程序来执行工作。
目前我们用 TLV 格式{Tag-Length-Value} 序列化所有字段,并有一个带有 Varchar2 参数的函数(字段的序列化列表)。例如:
008603701212345678901201100611111104800622222220000633333320100644444401201420200321164712
更易于阅读:
0086 037 012 123456789012 011 006 111111 048 006 222222 200 006 333333 201 006 444444 012 014 20200321164712
意思是:
String Len:86
Field037 with len 12:123456789012
Field011 with len 6:111111
Field048 with len 6:222222
Field200 with len 6:333333
Field201 with len 6:444444
Field012 with len 14:20200321164712
这些字段中的每一个都映射到表中的一个字段,存储的程序解析巨大的字符串并将它们填充到一个行类型中,最后将行插入到表中。
多年来它运行良好,但是当我们准备好接受更多请求(因此更多插入)时,我们的 DBA 说我们正在使用大量 CPU 来反序列化 TLV。所以我们必须改变我们的插入方法。
我目前在 C 中创建了一个结构并映射其中的所有字段并调用:
typedef struct
{
char field37[12+1];
char field11[6+1];
char field48[6+1];
char field200[6+1];
char field201[6+1];
char field12[14+1];
} NewRecord;
NewRecord newRecord;
TlvToStruct(sTlv, &newRecord);//Mapper Function
EXEC SQL INSERT INTO MY_TABLE(FIELD37, FIELD11, FIELD200, FIELD201, FIELD12) VALUES(:newRecord);
EXEC SQL COMMIT WORK RELEASE;
这种方法目前效果很好,但我的问题是:我是否应该继续开发并将所有 200 个字段添加到此结构并使用这种方法,或者最好使用 PLSQL 调用(可能开发并使用另一个插入函数)而不是这个SQL 插入?
我目前知道 PLSQL 的好处,但这里有一些问题:
1- Pro*C does not support PLSQL Records
2- It is not so reasonable to have a function with 200 parameters!
3- We use Types in plsql but never used them in Pro*C(actually I tried once and I failed long ago)
我在这里尝试描述问题,如果不清楚请询问
谢谢
================================================ ===
编辑:
这是我们旧的 Get_Tag 和 Put_Tag 函数:
FUNCTION GET_TAG(P_TAG_NAME IN VARCHAR2, P_TLV_STRG IN VARCHAR2, P_TAG_LEN OUT NOCOPY PLS_INTEGER, P_TAG_VALUE OUT NOCOPY VARCHAR2)
RETURN PLS_INTEGER IS
V_COUNTER_LOOP PLS_INTEGER := 1;
V_TLV_STRG VARCHAR2(4096) := SUBSTR(P_TLV_STRG, 5);
BEGIN
P_TAG_VALUE := NULL;
P_TAG_LEN := 0;
WHILE V_COUNTER_LOOP < LENGTH(V_TLV_STRG) LOOP
IF SUBSTR(V_TLV_STRG, V_COUNTER_LOOP, 3) = P_TAG_NAME THEN
P_TAG_LEN := TO_NUMBER(SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 3, 3));
P_TAG_VALUE := SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 6, P_TAG_LEN);
RETURN (DECLARATION_CST.OK);
END IF;
V_COUNTER_LOOP := V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(V_TLV_STRG, V_COUNTER_LOOP + 3, 3));
END LOOP;
RETURN 0;
EXCEPTION
WHEN OTHERS THEN
RETURN -1;
END GET_TAG;
================================================ =============
FUNCTION PUT_TAG(P_TAG_NAME IN VARCHAR2, P_TAG_VALUE IN VARCHAR2, P_TLV_STRG IN OUT NOCOPY VARCHAR2)
RETURN PLS_INTEGER IS
V_COUNTER_LOOP PLS_INTEGER := 0;
TMP_VARCHAR VARCHAR2(4096);
BEGIN
P_TLV_STRG := SUBSTR(P_TLV_STRG, 5);
V_COUNTER_LOOP := 1;
WHILE V_COUNTER_LOOP < LENGTH(P_TLV_STRG) LOOP
IF SUBSTR(P_TLV_STRG, V_COUNTER_LOOP, 3) = SUBSTR(P_TAG_NAME, 1, 3) THEN
TMP_VARCHAR :=
SUBSTR(P_TLV_STRG, 1, V_COUNTER_LOOP - 1)
|| SUBSTR(P_TAG_NAME, 1, 3)
|| TO_CHAR(NVL(LENGTH(P_TAG_VALUE), 0), 'FM000')
|| P_TAG_VALUE
|| SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 3, 3)));
P_TLV_STRG := TO_CHAR(LENGTH(TMP_VARCHAR), 'FM0000') || TMP_VARCHAR;
RETURN (DECLARATION_CST.OK);
END IF;
V_COUNTER_LOOP := V_COUNTER_LOOP + 6 + TO_NUMBER(SUBSTR(P_TLV_STRG, V_COUNTER_LOOP + 3, 3));
END LOOP;
P_TLV_STRG :=
P_TLV_STRG
|| SUBSTR(P_TAG_NAME, 1, 3)
|| TO_CHAR(NVL(LENGTH(P_TAG_VALUE), 0), 'FM000')
|| P_TAG_VALUE;
P_TLV_STRG := TO_CHAR(LENGTH(P_TLV_STRG), 'FM0000') || P_TLV_STRG;
RETURN 0;
EXCEPTION
WHEN OTHERS THEN
RETURN -1;
END PUT_TAG;
【问题讨论】:
-
每条记录的长度都不一样?可以发布PL/SQL 存储程序吗?也许是一种优化。 Oracle 数据库版本是多少?
-
是的,有些字段是可变长度的,你想看看解析器功能吗?
-
是的,如果你能分享的话
标签: oracle serialization plsql insert oracle-pro-c