我试图运行一个包含数百万个INSERT的大型SQL脚本(对于测试,我将其限制为100,000行)。
我尝试了很多不同的方法:CPYFRMSTMF,FTP,JDBC客户端,客户端访问数据传输,IBM Data Studio,来自System i Navigator的SQL脚本......只是想知道哪一个更好。 其中一种方法是使用RUNSQLSTM运行脚本(它位于IFS上)。
但是,开始插入记录需要很长很长时间。 在开始插入记录之前,该命令正在执行一些先前的任务。
我在COMMIT参数上选择了* NONE,以及OPTION中的NOLIST(我不需要假脱机文件)。
但我不知道为什么需要这么长时间。
一个令人难以置信的事情(在我的测试中,我已尝试过100,000条记录)运行脚本只需1分钟:如果我从使用JDBC连接iSeries的软件执行它,则需要40秒。
有什么想法吗?
谢谢!
答案 0 :(得分:2)
试图了解情况。是否有数百万行INSERT INTO ...语句?如果是这样,那么这可能是延迟开始实际插入的原因 - 实际上必须读取巨型脚本文件的所有行。
是否有一个INSERT语句执行类似INSERT INTO ... SELECT FROM ... WHERE ...?如果是这种情况,那么当优化器完成读取源行的工作时可能存在延迟。
还有别的吗?您能否分享一下脚本和所涉及的表格中的确切SQL语句?
答案 1 :(得分:1)
如果从脚本运行,最有可能的主要改进是使用阻塞的INSERT。也就是insert many rows with each INSERT statement。
以下是我运行的低效脚本中的前三个INSERT语句:
INSERT INTO MYLIB/MYDATA VALUES(10, 1, 'N')
;
INSERT INTO MYLIB/MYDATA VALUES(11, 1, 'Y')
;
INSERT INTO MYLIB/MYDATA VALUES(11, 2, 'Y')
;
完整脚本包含100,000个INSERT语句。两次运行给出了20:34和20:32的时间。
我对脚本进行了编辑,以创建一个更高效的示例。我更改了每个语句终结符,以便每个语句插入另外四行。前三行看起来像这样:
INSERT INTO MYLIB/MYDATA VALUES(10, 1, 'N')
,(11, 1, 'Y'),(13, 1, 'N'),(14, 1, 'N'),(14, 2, 'Y');
INSERT INTO MYLIB/MYDATA VALUES(11, 1, 'Y')
,(11, 1, 'Y'),(13, 1, 'N'),(14, 1, 'N'),(14, 2, 'Y');
INSERT INTO MYLIB/MYDATA VALUES(11, 2, 'Y')
,(11, 1, 'Y'),(13, 1, 'N'),(14, 1, 'N'),(14, 2, 'Y');
我修改了脚本,因此只有20,000个INSERT语句(仍然插入100,000行,一次五行)。
两次运行时间分别为1:51和2:09,相同行数的运行时间基本上减少了90%。如果我一次生成了10行或50行的INSERT,那么可能会有更好的改进。
通过一些简单的格式化可以看到表单更好:
INSERT INTO MYLIB/MYDATA VALUES(10, 1, 'N'),
(11, 1, 'Y'),
(13, 1, 'N'),
(14, 1, 'N'),
(14, 2, 'Y');
INSERT INTO MYLIB/MYDATA VALUES(11, 1, 'Y'),
(11, 1, 'Y'),
(13, 1, 'N'),
(14, 1, 'N'),
(14, 2, 'Y');
INSERT INTO MYLIB/MYDATA VALUES(11, 2, 'Y'),
(11, 1, 'Y'),
(13, 1, 'N'),
(14, 1, 'N'),
(14, 2, 'Y');
您可以自动编辑脚本以获得类似的结果。
答案 2 :(得分:0)
对于简单地插入数据,最快的方法是使用AS400命令 并将数据平面复制到文件中。使用sql的最快插入将是一个多插入。当你* DLY索引维护时,这两种方法都会更快。
以下是如何进行平面文件复制的方法。这是数据在文本文件中与表的数据布局完全对齐的位置。表a是txt文件。
CPYF FROMFILE(A)
TOFILE(B)
MBROPT(*ADD)
FMTOPT(*NOCHK)
通过将基于物理文件(表)的每个逻辑文件(索引)的访问路径维护设置为* DLY,可以使批量插入在iseries上更快。忽略任何未更改访问路径的警告消息。这是因为索引是一个唯一键,无法关闭(* DLY)。您需要对表和索引的独占访问才能使用此过程。
CHGLF file(myLib/myFile1) MAINT(*DLY)
CHGLF file(myLib/myFile2) MAINT(*DLY)
CHGLF file(myLib/myFile3) MAINT(*DLY)
CHGLF file(myLib/myFile4) MAINT(*DLY)
在这里插入bluk插件。完成后,根据物理文件(表)将访问路径维护更改回每个逻辑文件(索引)的* IMMED。
CHGLF file(myLib/myLogicalFile1) MAINT(*IMMED)
CHGLF file(myLib/myLogicalFile2) MAINT(*IMMED)
CHGLF file(myLib/myLogicalFile3) MAINT(*IMMED)
CHGLF file(myLib/myLogicalFile4) MAINT(*IMMED)
您可以使用DSPDBR显示数据库关系命令获取基于物理文件(表)的所有逻辑文件(索引)的列表。
DSPDBR FILE(myLib/myTable)
答案 3 :(得分:0)
谢谢,@ danny117 !!! 这样可行!! 但是,使用RUNSQLSTM我将使用shell命令DB2 Utility。它确实很快,虽然它有一些问题(错误控制)。 A bit more info
我使用它的方式非常简单: 我在IFS(QSH)上创建了一个shell批处理文件。在文件中,您只需要一个句子:
db2 -t -v -f $ * LIB
(其中LIB是您正在运行的脚本的目标LIB)。 并且,我使用参数调用它,在这种情况下,只是我想要运行的脚本的路径。
当然,它为您提供了很多选项,因为批处理文件可以完成许多不同的任务。 我使用STRQSH命令从CL运行所有内容。 这是我的CLP来源:
DCL VAR(&CONF1) TYPE(*CHAR) STG(*AUTO) LEN(250) +
VALUE('/BATCH/Batch_pruebas_migracion/bin/rundb2.s+
h +
usr/INIGREDI/PRUEBAS_MIG/PRUMIG_opt-1000000.SQL')
CLRPFM INIGREDI/PRUMIG
OVRPRTF FILE(QPRINT) OUTQ(QEZJOBLOG) MAXRCDS(*NOMAX) +
SPLFNAME(PRUMIG) EXPDATE(*DAYS) DAYS(7)
STRQSH CMD(&CONF1)
我会更多地解释一下CLP。 & CONF1包含我想用STRQSH执行的命令。您需要编写shell批处理文件的完整路径。 并且,在这种情况下,然后,在空格后,参数。在这种情况下,此参数是我要运行的SQL脚本的路径。 我按照你的建议,优化了该脚本(让我说,优化它并不总是一个好主意,它取决于你想要插入的记录的内容和大小)。
'OVRTPRTF'已完成,因为运行DB2实用程序会创建一个假脱机文件。它真的很大,因为它至少包含一行每个句子进入sql脚本(你可以改变详细模式,但最小,1行)。 并且,为了不忘记我的系统上的大卷轴文件,它在7天后编程了其自动删除。
这非常快,特别是与RUNSQLSTM相比。 虽然FTP或CPYFRMSTMF更快,但使用数字字段管理起来有点困难,特别是当它们包含负数或十进制数时。 (但这是另一个历史)。
而且,正如@ danny117所说,优化SQL脚本时的改进真的令人难以置信。在某些情况下,我有2000%的速度差异。 如果您从目标文件中删除日记,这也很重要。或者,当然,逻辑文件,约束或任何意味着在传输过程中对数据库引擎有更多工作的东西。
感谢大家的帮助。如你所见,我从不同的答案中提出了我的问题。 如果您需要有关我如何达到目标的任何进一步解释,请不要犹豫,并要求!