In JDBC kann die Methode „executeBatch“ mehrere DML-Anweisungen stapelweise ausführen, und die Effizienz ist viel höher als die einzelne Ausführung von „executeUpdate“. Wie implementiert man die Batch-Ausführung in MySQL und Oracle? Dieser Artikel stellt Ihnen das Prinzip dahinter vor.
Dieses Experiment wird in den folgenden drei Schritten durchgeführt:a Zeichnen Sie den Zeitaufwand für die Stapelausführung und die Einzelausführung von JDBC auf und Einzelausführung von JDBC in Oracle
c Zeichnen Sie die zeitaufwändige Ausführung von Oracle Plsql und Einzelausführung auf
Die relevanten Java- und Datenbankversionen sind wie folgt: Java17, Mysql8, Oracle11G
Erstellen eine Tabelle in MySQL bzw. Oracle
create table t ( -- mysql中创建表的语句 id int, name1 varchar(100), name2 varchar(100), name3 varchar(100), name4 varchar(100) );
create table t ( -- oracle中创建表的语句 id number, name1 varchar2(100), name2 varchar2(100), name3 varchar2(100), name4 varchar2(100) );
Vor dem Experiment müssen Sie die Prüfung der Datenbank aktivieren
Ein paar Punkte sind im Code zu beachten: MySQL-URL muss hinzugefügt werden useServerPrepStmts= true&rewriteBatchedStatements=true Parameter. batchCnt stellt die Anzahl der in jedem Stapel ausgeführten SQL-Anweisungen dar, und 0 steht für eine einzelne Ausführung. Erster MySQL-Testset global general_log = 1;
batchCnt=50 Gesamtzahl der Elemente: 10000, Einfügung pro Stapel: 50, Gesamtzeit: 4369 Millisekunden
batchCnt= 100 Gesamtzahl der Elemente: 10000, jeder Einfügungsstapel: 100, Gesamtzeitverbrauch: 2598 MillisekundenbatchCnt=10000 Gesamtzahl der Elemente: 10000, jeder Stapeleinfügung: 10000, Gesamtzeitaufwand: 2418 Millisekunden
batchCnt=0 Gesamtzahl der Elemente : 10000, einzelne Einfügung, insgesamt aufgewendete Zeit: 59620 MillisekundenbatchCnt=5
batchCnt=0Die Stapelausführung von MySQL schreibt SQL tatsächlich neu und führt mehrere Einfügungen zur Ausführung in Einfügung xx Werte (), () ... zusammen. Beim Ändern von batchCnt von 50 auf 100 verkürzt sich die Zeit grundsätzlich um die Hälfte, aber wenn der Wert erweitert wird, ist die Zeitverkürzung nicht offensichtlich und die Ausführungszeit erhöht sich sogar.
Wir können mehrere Schlussfolgerungen ziehen:
Die Effizienz der Stapelausführung ist im Vergleich erheblich verbessert zur Einzelausführung.
batchCnt=10.000 Gesamtzahl der Elemente: 10.000, jeder Stapeleinfügung: 10.000, Gesamtaufwand: 804 Millisekunden
batchCnt=0 Gesamtzahl der Elemente: 10000, einzelne Einfügung, insgesamt aufgewendete Zeit: 60830 MillisekundenDer Effekt der Ausführung in Oracle ist grundsätzlich der gleiche wie der in MySQL, und die Effizienz von Batch-Vorgängen ist deutlich höher als die der Einzelausführung. Das Problem besteht darin, dass es in Oracle keine solche Syntax zum Einfügen von xx-Werten(),()... gibt. Wie wird also eine Stapelausführung erreicht?
Sehen Sie sich die Audit-Ansicht dba_audit_trail an, wenn „batchCnt=50“ ausgeführt wird 从审计的结果中可以看到,batchCnt=50的时候,审计记录只有200条(扣除登入和登出),也就是sql只执行了200次。sql_text没有发生改写,仍然是"insert into t values (:1 , :2 , :3 , :4 , :5 )",而且sql_bind只记录了批量执行的最后一个参数,即50的倍数。根据awr报告可以看出,实际只执行了200次(由于篇幅限制,省略了awr截图)。那么oracle是怎么做到只执行200次但插入1万条记录的呢?我们来看看oracle中使用存储过程的批量插入。 准备数据: 首先将t表清空 truncate table t; 用java往t表灌10万数据 exec("oracle", 100000, 1000); 创建t1表 create table t1 as select * from t where 1 = 0; 以下两个过程的意图一致,均为将t表中的数据导入t1表。nobatch是单次执行,usebatch是批量执行。 执行上述存储过程 SQL> exec nobatch; 存储过程批量执行效率也远远高于单条执行。查看usebatch(50)执行时的审计日志,sql_bind也只记录了批量执行的最后一个参数,即50的倍数。与使用executeBatch方法在记录内容方面相同。因此可以推断,JDBC的executeBatch和存储过程的批量执行都采用了相同的方法 存储过程的这个关键点就是forall。查阅相关文档。 The FORALL statement runs one DML statement multiple times, with different values in the VALUES and WHERE clauses. 翻译过来就是forall很快,原因就是不需要每次执行的时候等待参数。 Das obige ist der detaillierte Inhalt vonSo implementieren Sie JDBC-Batch-Insert in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!四、存储过程
create or replace procedure nobatch is
begin
for x in (select * from t)
loop
insert into t1 (id, name1, name2, name3, name4)
values (x.id, x.name1, x.name2, x.name3, x.name4);
end loop;
commit;
end nobatch;
/
create or replace procedure usebatch (p_array_size in pls_integer)
is
type array is table of t%rowtype;
l_data array;
cursor c is select * from t;
begin
open c;
loop
fetch c bulk collect into l_data limit p_array_size;
forall i in 1..l_data.count insert into t1 values l_data(i);
exit when c%notfound;
end loop;
commit;
close c;
end usebatch;
/
Elapsed: 00:00:32.92
SQL> exec usebatch(50);
Elapsed: 00:00:00.77
SQL> exec usebatch(100);
Elapsed: 00:00:00.47
SQL> exec usebatch(1000);
Elapsed: 00:00:00.19
SQL> exec usebatch(100000);
Elapsed: 00:00:00.26
The different values come from existing, populated collections or host arrays. The FORALL statement is usually much faster than an equivalent FOR LOOP statement.
The FORALL syntax allows us to bind the contents of a collection to a single DML statement, allowing the DML to be run for each row in the collection without requiring a context switch each time.