我有两张表与多对一的关系。 (Oracle)的
**Table: PARENT**
Field: A (PK)
Field: B
Field: C1
Field: C2
Field: C3
Field: C4
Field: C5
**Table CHILD**
Field: A (PK) (FK to PARENT.A)
Field: D (PK)
Field: E
插入到子表中的记录和父表同时插入。
我想知道什么是最有效的方法。
目前,调用应用程序为整个插入步骤调用了一个存储过程。存储过程当前具有以下签名:
Field: A
Field: B
Field: C (dilimited string)
Field: D (dilimited string)
Field: E (dilimited string)
该过程从输入循环C并将每个值存储在数组中。然后使用该数组以及输入中的A和B插入表PARENT。
然后从输入中使用A并从输入循环到D和E,并为稀释字符串中的每个项目插入表CHILD。
每天最多可调用300万次。它需要尽可能高效。
在进行多个SP呼叫而不仅仅是一个SP呼叫时会损失多少效率?
所有用于处理稀释字符串的循环看起来像是很多工作!
我在想,调用应用程序可以为CHILD中的每个条目分别进行SP调用。但是,我怎样才能确保在插入PARENT之前不会以某种方式插入CHILD ......这将是更多的存储过程调用。 (很多时候没有要插入的子记录,当有一般不到10个,但可能多达50个)
我还打开另一种方式来获取稀释字符串C中的信息。
是否有一些比while循环更有效的方法来从稀释的字符串中获取信息?
我没有写SP我被要求做一个小修改,如果可能的话,它会更有效率。
有什么想法吗?
注意:
我简化了表格,实际上有10个项目中的字符串C不是5,还有两个更加稀释的字符串,就像C插入到表PARENT中一样。这些表还有几个字段而不是显示
30天后删除记录。
答案 0 :(得分:1)
这里有几件事......
首先,如果您循环使用分隔字符串将相似的项放在类似的列中,则可能需要重构表以使其更加规范化。例如,如果C
是电话号码的分隔列表,而C1
- C5
列是phone1
- phone5
,则您可能应该有一个单独的孩子phone
表。这取决于用例,但是作为潜在的未来问题(即分隔符的知识)让我感到震惊。
如果分隔的字符串中包含不相似的数据(电话号码,城市,名称等) - 请为每个单独的数据元素单独输入参数。这是一个更大的潜在问题(因为如果条目的顺序很重要,那你就搞砸了,期间)。
你是对的,循环分隔字符串是很多工作。除非可能,如果您的RDBMS具有某种内置split
函数或某些东西(或者您可以调用外部函数),否则不一定有更好的方法。如果可以的话,我宁愿避免它,并调用child
存储过程。它必须是每个孩子,但实际上这更好 - 不一定是表现明智,而是概念化和未来的维护。
如何在没有child
的情况下阻止插入parent
行?使用外键约束。如果违反约束,则是调用者的错,而不是数据库的错误。
好的,其中一些需要对SP进行一些重大更改,有些需要更改基础表结构(如果它最初设置正确,则应该主要对用户透明)。但这就是我想要的......
哦,并告诉我这一切都在承诺控制下运行......
答案 1 :(得分:0)
处理此问题的最有效方法是使用用户定义的数据类型将存储过程的值列表作为数组传递,而不是作为分隔字符串。像这样:
CREATE TYPE r_child IS OBJECT
(a NUMBER, d VARCHAR2(20), e VARCHAR2(20));
CREATE TYPE nt_child AS TABLE OF r_child;
CREATE TYPE nt_c AS TABLE OF VARCHAR2(20);
CREATE PROCEDURE insert_data(
p_a NUMBER, p_b VARCHAR2, p_c nt_c,
p_child nt_child
) AS
v_parent parent%ROWTYPE;
i NUMBER;
BEGIN
v_parent.a := p_a;
v_parent.b := p_a;
FOR i IN p_c.FIRST .. p_c.LAST LOOP
CASE i
WHEN 1 THEN
v_parent.c1 := p_c(i);
WHEN 2 THEN
v_parent.c2 := p_c(i);
WHEN 3 THEN
v_parent.c3 := p_c(i);
WHEN 4 THEN
v_parent.c4 := p_c(i);
WHEN 5 THEN
v_parent.c5 := p_c(i);
END CASE;
END LOOP;
INSERT INTO parent(
a,
b,
c1,
c2,
c3,
c4,
c5
)
VALUES v_parent;
FORALL i IN p_child.FIRST .. p_child.LAST
INSERT INTO child(
a, d, e
)
VALUES (
p_a, p_child(i).d, p_child(i).e
);
END insert_data;
如果包设计得很好,将插入包装在包中将不会增加大量的执行时间。这包括使用批量插入(如我所用的forall
所示)和使用数据库可以自然读取的数据结构,而不是编码和解码数据(正如您目前使用分隔值所做的那样)。 p>