我们有一个运行时间太长的流程,因此我调查了一些优化,发现它编写得非常糟糕,或者至少我认为。
通常这就是它所做的......首先,获取必要的字段来识别每条记录:
Select key1, key2, key2 from a remote_view@remote_host_dblink;
然后程序循环遍历所有结果,一次查询每个记录的相同远程视图,然后将每个记录插入本地主机。这对我来说似乎很愚蠢,所以我开始重新编写进程以获取第一个查询中的所有数据,而不仅仅是键,如下所示:
insert into localtable(col1, col2, col3 ... col15)
select col1, col2, col3 ... col15 FROM remote_view@remotehost;
这个过程进展不顺利 - 它挂了30分钟,所以DBA杀了它。我不知道这个视图是如何写在远程主机上的,我所知道的是它似乎对该系统非常不利。
所以,问题是:当在查询dblink时,从select中插入是否有一些固有的低效率?如果我先将所有列查询到游标中,然后在我们结束时一次执行一个插入,这会更好吗?
答案 0 :(得分:1)
由于服务器不同,dbLinks之间的大规模操作可能存在风险。 "速度",网络开销,......
一种方法可能是你刚才描述的两种方式之间的中途,即大量操作记录块,而不是所有记录。 您可以尝试使用以下内容(伪代码):
DECLARE
/* define a cursor on your view */
CURSOR curXXX IS
Select key1, key2, key2 from a remote_view@remote_host_dblink;
/* define structures to keep your data */
TYPE tyTabKey1 IS TABLE OF key1%type
INDEX BY
TYPE tyTabKey2 IS TABLE OF key2%type
INDEX BY PLS_INTEGER;;
TYPE tyTabKey3 IS TABLE OF key3%type
INDEX BY PLS_INTEGER;
vTabKey1 tyTabKey1;
vTabKey2 tyTabKey2;
vTabKey3 tyTabKey3;
...
/* define how many rows you want to process at a time */
kLimit number := 5000;
BEGIN
OPEN curXXX;
LOOP
/* fetch the wanted number of rows */
FETCH curXXX
BULK COLLECT INTO SOG_SOGGETTO_ID,
SOG_SOGGETTO_COD,
SOG_DATA_INI,
SOG_VERSIONE
LIMIT kLimit;
/* massively insert the rows */
FORALL i IN 1 .. vTabKey1.COUNT
insert into localtable(col1, col2, col3 ... col15)
VALUES ( vTabKey1(i),
vTabKey2(i),
...
);
num := num + vTabKey1.COUNT;
COMMIT;
/* loop while there are still rows to insert */
EXIT WHEN SOG_SOGGETTO_ID.COUNT < kLimit;
END LOOP;
CLOSE curXXX;
END;
/
在这个例子中我放了一个COMMIT;如果您决定以同样的方式执行此操作,请注意处理错误,因为如果出现错误,您可以进行部分插入。