当面对在数据库中复制记录并仅修改少量值的任务时,我倾向于使用临时表来避免写出所有未更改的列。有谁知道这会如何影响大型系统的性能?
一个简单的例子(也说明了我更喜欢临时表方法的原因):
假设我有一个包含50列mytbl
... col1
的表格col50
。我想插入一条与col5 = 'Some Value'
行完全相同的新记录,但col45
将设置为'Some other value'
。
方法1
CREATE GLOBAL TEMPORARY TABLE tmptbl AS
SELECT * FROM myschema.mytbl;
INSERT INTO tmptbl
(SELECT *
FROM myschema.mytbl
WHERE mytbl.col5 = 'Some Value');
UPDATE tmptbl
SET col45 = 'Some Other Value';
INSERT INTO myschema.mytbl
(SELECT * FROM tmptbl);
DROP TABLE tmptbl;
方法2
INSERT INTO myschema.mytbl (col1,
col2,
col3,
col4,
col5,
col6,
col7,
col8,
col9,
col10,
col11,
col12,
col13,
col14,
col15,
col16,
col17,
col18,
col19,
col20,
col21,
col22,
col23,
col24,
col25,
col26,
col27,
col28,
col29,
col30,
col31,
col32,
col33,
col34,
col35,
col36,
col37,
col38,
col39,
col40,
col41,
col42,
col43,
col44,
col45,
col46,
col47,
col48,
col49,
col50)
SELECT col1,
col2,
col3,
col4,
col5,
col6,
col7,
col8,
col9,
col10,
col11,
col12,
col13,
col14,
col15,
col16,
col17,
col81,
col19,
col20,
col21,
col22,
col23,
col24,
col25,
col26,
col27,
col28,
col29,
col30,
col31,
col32,
col33,
col34,
col35,
col36,
col37,
col38,
col39,
col40,
col41,
col42,
col43,
col44,
'Some Other Value',
col46,
col47,
col48,
col49,
col50
FROM myschema.mytbl
WHERE col5 = 'Some Value';
创建/删除临时表会产生多少开销?例如,如果这是生产规模系统的日常流程的一部分,那么额外的开销是否会引人注目?我意识到这在很大程度上取决于系统的细节,但总体思路会非常棒。
答案 0 :(得分:10)
首先,这不是临时表在Oracle中的工作方式。全局临时表是永久结构,它只是临时表中的数据。因此,无需为每个操作创建和删除表。这只会增加开销。
其次,临时表合理的情况实际上非常罕见。在大多数情况下,一个简单的变量就足够了。这种语法 - 插入一行 - 从9iR2开始有效:
declare
lrec emp%rowtype;
begin
select *
into lrec
from emp
where empno = 1234;
lrec.empno = 9999;
lrec.sal = 5000;
insert into emp values lrec;
end;
请注意,此配方中不需要括号。
答案 1 :(得分:4)
我无法看到使用临时表如何更快。
即使将临时表创建(和销毁)的开销放在一边(两个操作),您仍然执行三个单独的DB操作而不是一个组合操作。此外,您正在执行两个涉及对非临时表进行单独锁定的操作,从而导致潜在的并发性低于单个组合操作。当然,这在某种程度上与数据库有关,可以获取实际的锁。
最终,我认为方法1比方法2具有多更多的开销,甚至没有考虑临时表创建/销毁的肯定不可忽视的成本。
答案 2 :(得分:3)
我担心这可能是过早优化的情况。似乎这种方法“解决”了可能存在或不存在的问题,但肯定会给系统增加相当程度的复杂性。我的建议是
分享并享受。
答案 3 :(得分:2)
我假设您的方法的主要目标是避免必须两次写出所有50列,我认为如果将另一列添加到表中则必须进行更改。其他人评论了源表结构,临时表开销和过早优化等。这不是你的问题,但根据这个假设,我可以看到第三种可能有效的方法:
declare
type tmptbl_type is table of mytbl%rowtype;
cursor c is
select * from mytbl where col5 = 'Some Value';
tmptbl tmptbl_type;
begin
open c;
loop
fetch c bulk collect into tmptbl limit 1000;
for i in 1..tmptbl.count loop
tmptbl(i).col45 := 'Some Other Value';
end loop;
forall i in 1..tmptbl.count
insert into mytbl values tmptbl(i);
exit when c%notfound;
end loop;
close c;
end;
/
答案 4 :(得分:2)
你可以这样做。
INSERT INTO myschema.mytbl (SELECT * FROM myschema.mytbl WHERE mytbl.col5 ='Some Value');
更新myschema.mytbl SET col45 ='其他一些价值' 在哪里col5 ='某些值'和rownum< = 1;
这比使用临时表更短,并且没有临时表的缺点。当然,如果你的实际问题比你所展示的更复杂,那么这可能无效。
答案 5 :(得分:1)
如果您的过程将使用少于250行,您可能需要考虑使用表变量而不是临时表,因为表变量使用内存而不是物理写出tempdb。