如何在 Oracle SQL Developer 中执行超过 100 万条插入查询?

Posted

技术标签:

【中文标题】如何在 Oracle SQL Developer 中执行超过 100 万条插入查询?【英文标题】:How to execute more than 1 million insert queries in Oracle SQL Developer? 【发布时间】:2018-10-16 11:07:21 【问题描述】:

我有超过 100 万个插入查询要在 Oracle SQL Developer 中执行,这需要很多时间。有什么办法可以优化这个。

【问题讨论】:

您有查询还是有 100 万行的数据?您的数据库是在 Oracle SQL Developer 还是 mysql?当前数据在哪里? 将数据放入文件并从文件中加载数据。 @ChetanRanpariya 我有 100 万个查询,数据库是 Oracle SQL Developer Execute scripts by relative path in Oracle SQL Developer的可能重复 我建议你把所有的插入都放在一个 .sql 中,然后复制到数据库服务器上,然后在 Sql+ 命令提示符下运行。 【参考方案1】:

SQL Developer 是运行 1,000,000 行逐行插入的错误工具。

SQL*Plus 也是如此。

如果您无法编写程序来使用循环或游标或某些 pl/sql 批量收集来执行插入操作,那么 do what @marmite-bomber suggests - 将您的数据写入一个平面分隔的文本文件,并设置一个 SQL*加载程序场景。

Now, you CAN use SQL Developer to do this.

指向您的分隔文本文件。

映射所有内容,然后使用此 IMPORT 方法。

完成后,您将拥有一组需要执行的 bash 或 cmd 脚本。但首先,您的机器上需要一个 Oracle 客户端 - 这就是 sqlldr 程序所在的位置。

这比运行 1,000,000 个单独的插入要快几个数量级。而且您的 DBA 不会讨厌您。

使用 SQLDev 向导,您可以在几分钟内启动并运行它。

证明: 我测试了一个简单的场景 - 我的发现是 (details here): SQL*Loader 每秒插入 10,753 条记录 SQL Developer 每秒插入 342 条记录

SQL*Loader 速度提高了 3,144%。

【讨论】:

您是否真的测量过,通过 SQLDeveloper 的脚本运行器实用程序将 1M 插入作为一次性操作运行比这种方法慢 那么多还安装了 Oracle 客户端并可能设置了tnsnames.ora 等?我的意思是,OP 可以使用他们现有的工具来完成这项工作。 @MickMnemonic 是的,我有。 sqlldr 可以在几秒钟内加载 1M 条记录,尤其是如果您查看 sqlldr 带来的直接路径、并行和其他注重性能的特性。 @MickMnemonic 如果您要定期进行任何大小的数据加载,花时间设置适当的工具将是值得的。如果这是一个完成,那么当然,继续并使用 SQLDev 运行您的脚本。 那么使用 SQLDeveloper 花了多长时间?而且我知道 SQLLoader 对于“真正的”数据迁移/转换非常有用。 @MickMnemonic 在我今天刚刚运行的场景中,SQL*loader 比 SQL Developer 快 3,144%。【参考方案2】:

运行单行INSERTs 对于这样的行数是不可行的。

因此一种可能的方法是预处理脚本,仅提取 CSV 数据。

这里是一个简单的例子

Insert into TAB(COL1,COL2,COL3) values ('1','xxx',to_date('16-10-2018 15:13:49','DD-MM-YYYY HH24:MI:SS'));
Insert into TAB(COL1,COL2,COL3) values ('2','zzzzz',to_date('06-10-2018 15:13:49','DD-MM-YYYY HH24:MI:SS'));

删除所有不相关的部分以获得

'1','xxx','16-10-2018 15:13:49'
'2','zzzzz','06-10-2018 15:13:49'

并使用 SQL*Loader 或外部表加载此文件。性能会很好。

【讨论】:

【参考方案3】:

另一个建议是验证您在可能的 PK 列上没有任何重复。在插入之前删除约束,并在完成后将它们放回原处。将更改脚本放在手边。您可以将其作为相同脚本或不同脚本的一部分来执行。同样,如果您不检查 dups 并把 PK 放回预期错误;那么您将使用 dups 追踪行并删除该数据。

【讨论】:

【参考方案4】:

我有超过 100 万个插入查询要在 Oracle SQL Developer 中执行

执行任何 SQL 语句都会产生开销。你支付了 1000000 次税。此外,一些 IDE 为在工作表中执行的每个 SQL 语句的结果实例化一个单独的选项卡(当单击运行时)。我不记得 SQL Developer 是否这样做了,但如果这样做了,那就是你要支付 1000000 倍的另一种税。

两种可能的优化。

通过从dual 中选择值将单行插入插入到集合操作中:

insert into your_table
select blah_seq.nextval, q.txt, q.val from (
   select 'WHATEVER' as txt, 42 as val from dual union all
   select 'AND SO ON'  as txt, 23 as val  from dual union all
    ...
);

这将减少开销。这样做需要大量的编辑工作。

或者,使用批量加载选项(例如 SQL*Loader)或外部表来加载数据。如果您有支持正则表达式的程序员编辑器(如 Notepad++),那么去掉insert 语法并将values 子句转换为CSV 行相对简单。

第三种方法是返回生成数百万条插入语句的源,并要求它们以更易于管理的格式提供数据,例如数据泵导出。

【讨论】:

UNION ALL查询中应注意避免ORA-02287: sequence number not allowed here。 @MarmiteBomber - 感谢您在午餐前发现草率的伪代码;)【参考方案5】:

您可以将数据块放入集合并批量插入

另外,删除除主键之外的所有索引。数据加载后创建索引

可能有点危险,但根据数据的质量,您还可以删除外键,然后在导入数据后重新创建它们。您必须确保您的导入不会破坏 FK 关系

declare
    type my_tab is table of mytable%rowtype index by binary_integer;
    a_imp   my_tab;
begin

    -- do stuff to populate a_imp from presumably a text file? or select statement

    -- you could chunk your population of the array and bulk insert say 10,000 rows at a time

    -- loop through the holding array and import any remaining data
    forall ix in 1 .. a_imp.count
        insert into [tabel_name] values a_imp(ix);
    commit;

end;

【讨论】:

以上是关于如何在 Oracle SQL Developer 中执行超过 100 万条插入查询?的主要内容,如果未能解决你的问题,请参考以下文章

如何安装pl/sql developer

如何安装pl/sql developer

如何在 SQL Developer 中检查语法 Oracle 存储过程?

oracle 客户端 sql developer 如何修改jdk版本

如何在 Oracle SQL Developer 中查询数据库名称?

如何在 oracle sql developer 中运行存储过程?