1 Description
Dans JDBC, la méthodeexecuteBatch peut exécuter plusieurs instructions DML par lots, ce qui est plus efficace que une seule instruction L'exécution de executeUpdate est beaucoup plus élevée. Quel est le principe ? Comment implémenter l'exécution par lots dans MySQL et Oracle ? Cet article vous présentera le principe derrière cela.
2. Introduction à l'expérience
Cette expérience se déroulera à travers les trois étapes suivantes
a. exécution unique de jdbc dans mysql Time
b. Enregistrez le temps nécessaire à l'exécution par lots et à l'exécution unique de jdbc dans Oracle
c. exécution d'Oracle plsql
# ????#Les versions pertinentes de Java et de la base de données sont les suivantes?: Java17, Mysql8, Oracle11G3. dans mysql et oracle respectivementcreate table t ( -- mysql中創(chuàng)建表的語句
id int,
name1 varchar(100),
name2 varchar(100),
name3 varchar(100),
name4 varchar(100)
);
create table t ( -- oracle中創(chuàng)建表的語句
id number,
name1 varchar2(100),
name2 varchar2(100),
name3 varchar2(100),
name4 varchar2(100)
);
Vous devez activer l'audit de la base de données avant l'expérience mysql active l'audit?: set global general_log = 1;oracle active l'audit?:
alter system set audit_trail=db, extended; audit insert table by scott; -- 實(shí)驗(yàn)采用scott用戶批量執(zhí)行insert的方式le code java est le suivant?:
import java.sql.*; public class JdbcBatchTest { /** * @param dbType 數(shù)據(jù)庫類型,oracle或mysql * @param totalCnt 插入的總行數(shù) * @param batchCnt 每批次插入的行數(shù),0表示單條插入 */ public static void exec(String dbType, int totalCnt, int batchCnt) throws SQLException, ClassNotFoundException { String user = "scott"; String password = "xxxx"; String driver; String url; if (dbType.equals("mysql")) { driver = "com.mysql.cj.jdbc.Driver"; url = "jdbc:mysql://ip/hello?useServerPrepStmts=true&rewriteBatchedStatements=true"; } else { driver = "oracle.jdbc.OracleDriver"; url = "jdbc:oracle:thin:@ip:orcl"; } long l1 = System.currentTimeMillis(); Class.forName(driver); Connection connection = DriverManager.getConnection(url, user, password); connection.setAutoCommit(false); String sql = "insert into t values (?, ?, ?, ?, ?)"; PreparedStatement preparedStatement = connection.prepareStatement(sql); for (int i = 1; i <= totalCnt; i++) { preparedStatement.setInt(1, i); preparedStatement.setString(2, "red" + i); preparedStatement.setString(3, "yel" + i); preparedStatement.setString(4, "bal" + i); preparedStatement.setString(5, "pin" + i); if (batchCnt > 0) { // 批量執(zhí)行 preparedStatement.addBatch(); if (i % batchCnt == 0) { preparedStatement.executeBatch(); } else if (i == totalCnt) { preparedStatement.executeBatch(); } } else { // 單條執(zhí)行 preparedStatement.executeUpdate(); } } connection.commit(); connection.close(); long l2 = System.currentTimeMillis(); System.out.println("總條數(shù):" + totalCnt + (batchCnt>0? (",每批插入:"+batchCnt) : ",單條插入") + ",一共耗時:"+ (l2-l1) + " 毫秒"); } public static void main(String[] args) throws SQLException, ClassNotFoundException { exec("mysql", 10000, 50); } }Quelques points à noter dans le code,
# ???? L'URL #mysql doit ajouter des paramètres useServerPrepStmts=true&rewriteBatchedStatements=true.
batchCnt représente le nombre d'instructions SQL exécutées dans chaque lot et 0 représente une exécution unique.
Premier test de mysql
exec("mysql", 10000, batchCnt);
Mettez différentes valeurs batchCnt pour voir le temps d'exécution
#?? ??#batchCnt= 50 Nombre total d'éléments : 10000, insertion par lot : 50, consommation de temps totale : 4369 millisecondes
batchCnt=100 Nombre total d'éléments : 10000, insertion par lot : 100, consommation de temps totale : 2598 millisecondesbatchCnt= 200 Nombre total d'éléments : 10000, chaque lot d'insertions : 200, temps total passé : 2211 millisecondes
batchCnt=1000 Nombre total d'éléments : 10000, chaque lot d'insertions : 1000, temps total dépensé : 2099 millisecondesbatchCnt= 10000 Nombre total d'éléments : 10000, chaque insertion par lot : 10000, consommation de temps totale : 2418 millisecondesbatchCnt=0 Nombre total d'éléments : 10000, insertion unique, consommation de temps totale : 59620 millisecondes
batchCnt=0
# ????#Voir le journal général
batchCnt=5
Plusieurs conclusions peut être dessiné?:
#???? #L'efficacité de l'exécution par lots est grandement améliorée par rapport à l'exécution unique. L'exécution par lots de MySQL réécrit en fait SQL et fusionne plusieurs insertions dans les valeurs d'insertion xx(),()... pour l'exécution.- Lors du changement de batchCnt de 50 à 100, le temps est fondamentalement réduit de moitié, mais lorsque la valeur est augmentée, la réduction du temps n'est pas évidente. Le temps d'exécution. peut même augmenter.
- Raison de l'analyse?:
Après que le client ait envoyé l'instruction SQL à exécuter au serveur de base de données, la base de données exécute le Instruction SQL et renvoyer les résultats au client. Temps total pris = temps d'exécution de la base de données + temps de transmission réseau. La réduction du nombre d’allers-retours grace à l’exécution par lots réduit le temps de transfert réseau et donc le temps global. Cependant, lorsque batchCnt devient plus important, même si le temps de transmission sur le réseau n'est plus le principal goulot d'étranglement, la réduction du temps total ne sera pas aussi évidente. Surtout lorsque batchCnt=10 000, c'est-à-dire que les 10 000 instructions sont exécutées en même temps, le temps devient plus long. Cela peut être d? au fait que le programme et la base de données doivent demander plus de mémoire lors de la préparation de ces paramètres d'entrée, ce qui prend donc plus de temps (. Je suppose).
exec("oracle", 10000, batchCnt);Mettez différentes valeurs batchCnt pour voir le temps d'exécution
batchCnt=50 Nombre total d'entrées : 10000, Insérez chaque lot : 50, temps total passé : 2055 millisecondes
batchCnt=100 Nombre total d'éléments : 10000, insérez chaque lot : 100, temps total passé : 1324 millisecondesbatchCnt=200 Nombre total d'articles : 10000, Insertion par lot : 200, consommation de temps totale : 856 millisecondes
batchCnt=1000 Nombre total d'entrées : 10000, insertion par lot : 1000, consommation de temps totale : 785 millisecondesbatchCnt =10000 Nombre total d'entrées : 10000, Chaque lot d'insertions : 10000, temps total passé : 804 millisecondes
batchCnt=0 Nombre total d'éléments : 10000, insertion unique, temps total passé : 60830 millisecondes# ????#Exécuté dans Oracle L'effet est fondamentalement le même que celui de MySQL, et l'efficacité des opérations de traitement par lots est nettement supérieure à celle d'une exécution unique. Le problème est qu'il n'existe pas de syntaxe d'insertion de valeurs xx(),()... dans Oracle, alors comment réalise-t-il l'exécution par lots ?
Afficher la vue d'audit dba_audit_trail
lorsque batchCnt=50 est exécuté從審計(jì)的結(jié)果中可以看到,batchCnt=50的時候,審計(jì)記錄只有200條(扣除登入和登出),也就是sql只執(zhí)行了200次。sql_text沒有發(fā)生改寫,仍然是"insert into t values (:1 , :2 , :3 , :4 , :5 )",而且sql_bind只記錄了批量執(zhí)行的最后一個參數(shù),即50的倍數(shù)。根據(jù)awr報(bào)告可以看出,實(shí)際只執(zhí)行了200次(由于篇幅限制,省略了awr截圖)。那么oracle是怎么做到只執(zhí)行200次但插入1萬條記錄的呢?我們來看看oracle中使用存儲過程的批量插入。
四、存儲過程
準(zhǔn)備數(shù)據(jù):
首先將t表清空 truncate table t;
用java往t表灌10萬數(shù)據(jù) exec("oracle", 100000, 1000);
創(chuàng)建t1表 create table t1 as select * from t where 1 = 0;
以下兩個過程的意圖一致,均為將t表中的數(shù)據(jù)導(dǎo)入t1表。nobatch是單次執(zhí)行,usebatch是批量執(zhí)行。
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; /執(zhí)行上述存儲過程
SQL> exec nobatch; ?
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存儲過程批量執(zhí)行效率也遠(yuǎn)遠(yuǎn)高于單條執(zhí)行。查看usebatch(50)執(zhí)行時的審計(jì)日志,sql_bind也只記錄了批量執(zhí)行的最后一個參數(shù),即50的倍數(shù)。與使用executeBatch方法在記錄內(nèi)容方面相同。因此可以推斷,JDBC的executeBatch和存儲過程的批量執(zhí)行都采用了相同的方法
存儲過程的這個關(guān)鍵點(diǎn)就是forall。查閱相關(guān)文檔。
The FORALL statement runs one DML statement multiple times, with different values in the VALUES and WHERE clauses.
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.翻譯過來就是forall很快,原因就是不需要每次執(zhí)行的時候等待參數(shù)。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undress AI Tool
Images de déshabillage gratuites

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Article chaud

Outils chauds

Bloc-notes++7.3.1
éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Pour gérer correctement les transactions JDBC, vous devez d'abord désactiver le mode de validation automatique, puis effectuer plusieurs opérations, et enfin vous engager ou randonner en fonction des résultats; 1. Appelez Conn.SetAutoCommit (false) pour démarrer la transaction; 2. Exécuter plusieurs opérations SQL, telles que l'insertion et la mise à jour; 3. Appelez Conn.Commit () Si toutes les opérations sont réussies, et appelez Conn.Rollback () Si une exception se produit pour garantir la cohérence des données; Dans le même temps, les ressources TRY-With doivent être utilisées pour gérer les ressources, gérer correctement les exceptions et cl?turer les connexions pour éviter la fuite de connexion; De plus, il est recommandé d'utiliser des pools de connexion et de définir des points de sauvegarde pour réaliser un retour en arrière partiel, et de maintenir les transactions aussi courtes que possible pour améliorer les performances.

Utilisez des classes dans le package Java.Time pour remplacer les anciennes classes de date et de calendrier; 2. Obtenez la date et l'heure actuelles via LocalDate, LocalDateTime et Localtime; 3. Créez une date et une heure spécifiques en utilisant la méthode OF (); 4. Utilisez la méthode plus / moins pour augmenter et diminuer le temps; 5. Utilisez ZonedDateTime et ZoneID pour traiter le fuseau horaire; 6. Format et cha?nes de date d'analyse via DateTimeFormatter; 7. Utilisez instantanément pour être compatible avec les anciens types de dates si nécessaire; Le traitement des dattes dans le Java moderne devrait donner la priorité à l'utilisation de Java.timeapi, qui fournit clairement, immuable et linéaire

Pré-formancetartuptimemoryusage, quarkusandmicronautleadduetocompile-timeprocessingandgraalvsupport, withquarkusofperforming lightbetterine scénarios.

NetworkportsandfirewallsworkTogeTherToenable Communication whileSenSurringSecurity.1.networkportsAreVirtualEndpointsNumberred0–65535, Withwell-connuportslike80 (HTTP), 443 (HTTPS), 22 (SSH), et 25 (SMTP)

La collecte des ordures de Java (GC) est un mécanisme qui gère automatiquement la mémoire, ce qui réduit le risque de fuite de mémoire en récupérant des objets inaccessibles. 1. GC juge l'accessibilité de l'objet de l'objet racine (tel que les variables de pile, les threads actifs, les champs statiques, etc.), et les objets inaccessibles sont marqués comme des ordures. 2. Sur la base de l'algorithme de compensation de marque, marquez tous les objets accessibles et effacez des objets non marqués. 3. Adopter une stratégie de collecte générationnelle: la nouvelle génération (Eden, S0, S1) exécute fréquemment MinorGC; Les personnes agées fonctionnent moins, mais prend plus de temps pour effectuer MajorGC; Metaspace Stores Metadata de classe. 4. JVM fournit une variété de périphériques GC: SerialGC convient aux petites applications; Le parallelGC améliore le débit; CMS réduit

Le choix du bon type HTMLinput peut améliorer la précision des données, améliorer l'expérience utilisateur et améliorer la convivialité. 1. Sélectionnez les types d'entrée correspondants en fonction du type de données, tels que le texte, le courrier électronique, le tel, le numéro et la date, qui peuvent vérifier automatiquement la somme de la somme et l'adaptation au clavier; 2. Utilisez HTML5 pour ajouter de nouveaux types tels que l'URL, la couleur, la plage et la recherche, qui peuvent fournir une méthode d'interaction plus intuitive; 3. Utilisez l'espace réservé et les attributs requis pour améliorer l'efficacité et la précision du remplissage des formulaires, mais il convient de noter que l'espace réservé ne peut pas remplacer l'étiquette.

HTTP Log Middleware dans GO peut enregistrer les méthodes de demande, les chemins de requête, la propriété intellectuelle du client et le temps qui prend du temps. 1. Utilisez http.handlerfunc pour envelopper le processeur, 2. Enregistrez l'heure de début et l'heure de fin avant et après l'appel Suivant.Servehttp, 3. Obtenez le vrai client IP via R.RemoteAddr et X-Forwared-For Headers, 4. Utilisez le log.printf aux journaux de demande de sortie, 5. L'exemple de code complet a été vérifié pour s'exécuter et convient au démarrage d'un projet petit et moyen. Les suggestions d'extension incluent la capture des codes d'état, la prise en charge des journaux JSON et le suivi des ID de demande.

GradleisthebetterChoiceFormostNewProjectsDuetOtsSuperiorflexibility, Performance et ModerNtoolingSupport.1.gradle’sgroovy / kotlindslismoreConcis
