4

我有两个具有多对一关系的表。(甲骨文)

**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 调用而不是一次调用时会损失多少效率?

处理受限字符串的所有循环似乎需要做很多工作!

我在想调用应用程序可以对 CHILD 的每个条目进行单独的 SP 调用。但是,我怎样才能确保以某种方式插入 CHILD 不会在插入 PARENT 之前发生......那将是更多的存储过程调用。(很多时候没有要插入的子记录,有的时候一般少于10条,但也有可能多达50条)

我也愿意用另一种方法来获取 Dilimted 字符串 C 中的信息。

有没有比while循环更有效的方法来从有限的字符串中获取信息?

我没有写 SP 我被要求做一个小的修改,如果可能的话让它更有效。

有任何想法吗?

笔记:

我简化了表格,实际上在 dilitied 字符串 C 中有 10 个项目而不是 5,还有两个像 C 一样的 dilited 字符串被插入到表 PARENT 中。这些表还具有比显示更多的字段

记录将在 30 天后删除。

4

2 回答 2

1

这里有几件事......

首先,如果您正在循环使用分隔字符串以将相似的项目放在相似的列中,您可能需要重构您的表以使其更加规范化。例如,如果C是电话号码的分隔列表,并且列C1-C5phone1- phone5,则您可能应该有一个单独的子phone表。这取决于用例,但我认为这是一个潜在的未来问题(即分隔符的知识)。如果分隔字符串中包含不相似的数据(电话号码、城市、姓名等) - 请为每个单独的数据元素制作单独的条目参数。这是一个更大的潜在问题(因为如果条目的顺序很重要,那你就完蛋了,句号)。

你是对的,循环分隔的字符串是很多工作。不一定有更好的方法来做到这一点,除非您的 RDBMS 有某种内置split函数或其他东西(或者您可以调用外部函数)。如果可以的话,我宁愿避免它,并调用一个child存储过程。它必须是每个孩子的,但无论如何这实际上更好 - 不一定是性能方面的,而是用于概念化它,以及未来的维护。

如何防止在child没有 的情况下插入行parent?使用外键约束。如果违反了约束,那是调用者的错,而不是数据库的错。

好的,其中一些需要对 SP 进行一些重大更改,还有一些需要更改底层表结构(如果最初设置正确,则应该对用户基本透明)。但这是我会尝试的......

哦,请告诉我这一切都在承诺控制下运行......

于 2011-08-30T19:41:39.600 回答
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)和使用数据库可以自然读取的数据结构,而不是对数据进行编码和解码(就像您当前对分隔值所做的那样)。

于 2011-08-31T15:47:45.160 回答