Oracle优化查询避免游标

发布于 2024-09-17 22:39:05 字数 878 浏览 4 评论 0原文

我正在研究一段我想要优化的sql。 我里面有一堆光标。 我想知道是否可以使用其他东西来代替光标。 我正在考虑使用某种变量,填充它们,并在其余的处理中避免数据库连接(我有一个复杂的处理)。

我有一段代码,例如:

TYPE rec_basket IS RECORD (
 FIELD1 VARCHAR2(40),
 FIELD2 NUMBER(10),
 FIELD3 VARCHAR2(6)
 );

 TYPE tab_basket IS TABLE OF rec_basket
 INDEX BY BINARY_INTEGER;

................................................

CURSOR cur_baskets
   IS
select * from toto

例如, ............

 FOR i IN cur_baskets
   LOOP
  l_tab_basket (l_nbasket).field1 := i.field1;
  l_tab_basket (l_nbasket).field2 := i.field2;
  l_tab_basket (l_nbasket).field3  := i.field3;
  l_nbasket := l_nbasket + 1;    
   END LOOP;

使用游标并填充 l_tab_basket 变量是最好的方法?我在代码中的某处使用 l_tab_basket (索引)。 我放置这段代码的原因是我想将这种机制用于我的其他游标。 实际上我有一个光标在另一个光标内。对于它们中的每一行,我都有一些处理。我想用其他东西替换光标,但我不知道如何。 谢谢。

I'm working on a piece of sql that I want to optimize.
I have inside a bunch of cursors.
I'm wondering if I can use something else instead of cursors.
I'm thinking using some kind of variables, filling them, and for the rest of the treatment avoiding the DB connection (I have a complex treatment).

For instance I have a piece of code like :

TYPE rec_basket IS RECORD (
 FIELD1 VARCHAR2(40),
 FIELD2 NUMBER(10),
 FIELD3 VARCHAR2(6)
 );

 TYPE tab_basket IS TABLE OF rec_basket
 INDEX BY BINARY_INTEGER;

........................

CURSOR cur_baskets
   IS
select * from toto

............................

 FOR i IN cur_baskets
   LOOP
  l_tab_basket (l_nbasket).field1 := i.field1;
  l_tab_basket (l_nbasket).field2 := i.field2;
  l_tab_basket (l_nbasket).field3  := i.field3;
  l_nbasket := l_nbasket + 1;    
   END LOOP;

Using a cursor and filling the l_tab_basket variable is the best way to go? I'm using l_tab_basket (index) somewhere in my code.
The reason I've put this piece of code is that I would like use this mechanism for my other cursors.
Actually I have a cursor inside another one. And for each line of each of them I have some treatment. I would like to replace the cursors with something else, but I don't know how.
Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

海的爱人是光 2024-09-24 22:39:05

您可以使用 BULK COLLECT 将所有记录提取到嵌套表中。这在 10g+ 中有效:

SQL> DECLARE
  2     TYPE rec_basket IS RECORD(
  3        field1 VARCHAR2(40),
  4        field2 NUMBER(10),
  5        field3 VARCHAR2(6));
  6     TYPE tab_basket IS TABLE OF rec_basket INDEX BY BINARY_INTEGER;
  7     l_tab_basket tab_basket;
  8  BEGIN
  9     SELECT 'a', ROWNUM, 'b'
 10       BULK COLLECT INTO l_tab_basket
 11       FROM dual CONNECT BY LEVEL <= 1000;
 12  END;
 13  /

PL/SQL procedure successfully completed

请记住,Oracle 10g 自动从 pl/sql 中的隐式游标中批量 (100) 获取记录,因此收益充其量应该是微乎其微的:您可能会花更多时间查询数据库而不是构建数组除非数组真的很大(在这种情况下使用嵌套表是否明智?)

You can use BULK COLLECT to fetch all records into your nested table. This would work in 10g+:

SQL> DECLARE
  2     TYPE rec_basket IS RECORD(
  3        field1 VARCHAR2(40),
  4        field2 NUMBER(10),
  5        field3 VARCHAR2(6));
  6     TYPE tab_basket IS TABLE OF rec_basket INDEX BY BINARY_INTEGER;
  7     l_tab_basket tab_basket;
  8  BEGIN
  9     SELECT 'a', ROWNUM, 'b'
 10       BULK COLLECT INTO l_tab_basket
 11       FROM dual CONNECT BY LEVEL <= 1000;
 12  END;
 13  /

PL/SQL procedure successfully completed

Keep in mind that Oracle 10g automatically fetch records from implicit cursors in bulk (100) in pl/sql, so the gains should be marginal at best: you will probably spend more time querying the DB than building the array unless the array is really really big (and in that case is it wise to use a nested table?)

家住魔仙堡 2024-09-24 22:39:05

你的代码逻辑不是很清楚。你还没有写出整个程序。让我们检查一下:

CURSOR cur_baskets

select * from toto

这里从表 toto 中读取值并将其放入游标中。

在下面的行中,从光标读取值并将其放入 l_tab_basket 中。

FOR i IN cur_baskets
环形
l_tab_basket (l_nbasket).field1 := i.field1;
l_tab_basket (l_nbasket).field2 := i.field2;
l_tab_basket (l_nbasket).field3 := i.field3;
l_nbasket := l_nbasket + 1;
结束循环;

所以相同的值将被分配给局部变量两次。这是可以避免的。您可以找到直接插入或更新目标表的方法。

您可以尝试批量收集。如果toto很小,您可以不使用游标来插入或更新目标表。

Logic of your code is not very clear. You have not written whole program. Let us examine:

CURSOR cur_baskets
IS
select * from toto

Here the value are read from the table toto and put into a cursor.

In the following lines the values are read from the cursor and put into l_tab_basket.

FOR i IN cur_baskets
LOOP
l_tab_basket (l_nbasket).field1 := i.field1;
l_tab_basket (l_nbasket).field2 := i.field2;
l_tab_basket (l_nbasket).field3 := i.field3;
l_nbasket := l_nbasket + 1;
END LOOP;

So same values are going to local variable twice. This can be avoided. You can find out ways to directly insert into or update target table.

You can try bulk collect. If toto is small, you can insert into or update the target table without using cursor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文