带有大型数据集的SQL插入

时间:2008-12-31 02:21:17

标签: sql database oracle

当运行像“插入表”这样的查询时,我们如何处理提交大小?即来自anotherTable的所有记录都插入到单个事务中,或者有没有办法设置提交大小?

非常感谢~Sri PS:我是这里的第一个计时器,这个网站看起来非常好!

12 个答案:

答案 0 :(得分:3)

在一个原子语句的好数据库中,所以不,没有办法限制插入的记录数 - 这是一件好事!

答案 1 :(得分:3)

在原始海报希望避免回滚空间问题的背景下,答案非常简单。回滚段的大小应该适合于交易的大小,而不是相反。您在交易完成时提交。

答案 2 :(得分:2)

我已经用各种语言(主要是Java)编写代码来执行像你描述的那样的批量插入。每次我这样做,主要是从解析一些输入文件或类似的东西,我基本上只准备从总量(通常批量4000左右)插入数据的子集,并将数据提供给我们的DAO层。所以它是以编程方式完成的。我们从来没有注意到这样做的任何真正的性能打击,我们处理了几百万条记录。如果您要插入大型数据集,则无论您如何操作,操作都会“花费一段时间”。

答案 3 :(得分:1)

除非您明确编码,否则无法处理提交大小。例如,您可以使用where循环,并编写一种方法来限制您选择的数据量。

答案 4 :(得分:1)

David Aldridge是对的,当您希望INSERT成功或失败时,根据最大事务调整回滚段的大小。

一些替代方案:

如果您不关心能够将其回滚(这就是该段的用途),您可以使用ALTER TABLE并添加 NOLOGGING 子句。但这不是一个明智之举,除非您正在加载一个报告表,在该表中删除所有旧行并加载新行或其他特殊情况。

如果您可以插入某些行而其他行由于某种原因而失败,那么使用 INSERT INTO LOG ERRORS INTO 语法添加对处理失败的支持

答案 5 :(得分:0)

如果您需要限制数据集,请在查询中构建该限制。

例如,在Microsoft SQL Server的说法中,您可以使用“TOP N ”来确保查询仅返回有限数量的行。

INSERT INTO thisTable
  SELECT TOP 100 * FROM anotherTable;

答案 6 :(得分:0)

我想这样做的原因是为了避免回滚段空间不足。另外,我希望定期在目标表中填充结果。

我不想使用where循环,因为它可能会增加性能开销。不是吗?

〜斯里兰卡

答案 7 :(得分:0)

您是对的,您可能希望批量运行大型插入。附加的链接显示了在SQL Server中执行此操作的方法,如果您使用的是不同的后端,则可以执行类似的操作,但确切的语法可能不同。这是循环可以接受的情况。

http://www.tek-tips.com/faqs.cfm?fid=3141

答案 8 :(得分:0)

“我之所以这样做,是为了避免回滚段空间不足。另外,我希望定期在目标表中填充结果。”

第一个问题只是正确调整撤消表空间的大小。由于撤消是对现有行的删除,因此不需要大量空间。相反,删除通常需要更多空间,因为它必须有一个整个已删除行的副本才能重新插入它以撤消它。

对于第二个,请查看v $ session_longops和/或v $ sql中的rows_processed

答案 9 :(得分:0)

INSERT INTO TableInserted
SELECT *
FROM (
   SELECT  *,
          ROW_NUMBER() OVER (ORDER BY ID) AS RowNumber
   FROM TableSelected
) X
WHERE RowNumber BETWEEN 101 AND 200

你可以很容易地将上面的内容包装成while循环,用变量替换101和200。这比一次做1条记录要好。

我不知道哪些版本的Oracle支持窗口函数。

答案 10 :(得分:0)

这是一个扩展注释,用于证明设置NOLOGGING的索引有助于减少INSERT的UNDO或REDO。

手册暗示NOLOGGING索引可以通过减少UNDO和REDO来帮助改进DML。由于NOLOGGING帮助表DML,它似乎也有助于INDEX更改。但是这个测试用例表明将索引更改为NOLOGGING对INSERT语句没有影响。

drop table table_no_index;
drop table table_w_log_index;
drop table table_w_nolog_index;

--#0: Before
select name, value from v$mystat natural join v$statname where display_name in ('undo change vector size', 'redo size') order by 1;

--#1: NOLOGGING table with no index.  This is the best case scenario.
create table table_no_index(a number) nologging;
insert /*+ append */ into table_no_index select level from dual connect by level <= 100000;
commit;
select name, value from v$mystat natural join v$statname where display_name in ('undo change vector size', 'redo size') order by 1;

--#2: NOLOGGING table with LOGGING index.  This should generate REDO and UNDO.
create table table_w_log_index(a number) nologging;
create index table_w_log_index_idx on table_w_log_index(a);
insert /*+ append */ into table_w_log_index select level from dual connect by level <= 100000;
commit;
select name, value from v$mystat natural join v$statname where display_name in ('undo change vector size', 'redo size') order by 1;

--#3: NOLOGGING table with NOLOGGING index.  Does this generate as much REDO and UNDO as previous step?
create table table_w_nolog_index(a number) nologging;
create index table_w_nolog_index_idx on table_w_nolog_index(a) nologging;
insert /*+ append */ into table_w_nolog_index select level from dual connect by level <= 100000;
commit;
select name, value from v$mystat natural join v$statname where display_name in ('undo change vector size', 'redo size') order by 1;

以下是统计信息查询的结果。这些数字是会议的累积数字。测试用例#2和#3在UNDO和REDO中具有相同的增加。

--#0: BEFORE: Very little redo or undo since session just started.
redo size      35,436
undo change vector size    10,120

--#1: NOLOGGING table, no index: Very little redo or undo.
redo size      88,460
undo change vector size    21,772

--#2: NOLOGGING table, LOGGING index: Large amount of redo and undo.
redo size   6,895,100
undo change vector size 3,180,920

--#3: NOLOGGING table, NOLOGGING index: Large amount of redo and undo.
redo size   13,736,036
undo change vector size 6,354,032

答案 11 :(得分:-1)

您可能只想制作索引NOLOGGING。这样表数据是可恢复的,但如果恢复表,则需要重建索引。索引维护可以创建大量撤消。