2008-11-13 18 views
4

J'ai besoin d'insérer 20 000 lignes dans une seule table (SQL Server 2005) en utilisant iBatis. Quel est le moyen le plus rapide de le faire? J'utilise déjà le mode de traitement par lots, mais il n'a pas aidé beaucoup:Le moyen le plus rapide de faire des INSERTS en utilisant IBATIS

try { 
    sqlMap.startTransaction(); 
    sqlMap.startBatch(); 
    // ... execute statements in between 
    sqlMap.commitTransaction(); 
} finally { 
    sqlMap.endTransaction(); 
} 

Répondre

1

inserts en vrac sont mieux fait d'utiliser les outils en vrac du chargeur de la base de données. Pour Oracle, c'est SQL * Loader, par exemple. Souvent, ils sont plus rapides que tout ce que vous pourriez écrire.

2

Bien que cela ne soit pas spécifique à votre serveur db, j'ai déjà réussi à écrire les lignes dans un fichier local au format csv, puis à importer la base de données. Cela était considérablement plus rapide que les instructions d'insertion ou même une insertion de lot.

+0

a récemment fait la même expérience avec MySQL: l'insertion de données en utilisant des instructions INSERT INTO simples chargées à partir d'un fichier était significativement plus rapide que l'insertion d'un lot comme décrit ci-dessus. –

2

Dans SQL Server, la méthode d'insertion rapide des enregistrements dans un lot utilise BULK INSERT. Toutefois, cette méthode charge les enregistrements à partir d'un fichier texte plutôt que directement à partir de votre application.

Il ne prend pas non plus en compte le temps passé à créer le fichier. Vous devrez peut-être peser si cela compense les gains de vitesse de l'insertion réelle. Gardez à l'esprit que même si c'est un peu plus lent dans l'ensemble, vous finirez par lier votre serveur de base de données pour moins de temps. La seule autre chose que vous pouvez essayer est d'insérer (staging) le lot dans une table complètement différente (sans index ou quoi que ce soit). Ensuite, déplacez l'enregistrement de cette table de transfert vers votre table cible et supprimez la table de transfert. Cela déplacerait les données vers le serveur en premier, de sorte que l'insertion finale puisse tout se passer avec le serveur sql lui-même. Mais encore une fois: c'est un processus en deux étapes, donc vous devrez compter le temps pour les deux étapes.

+1

+1 Chargement en bloc à partir d'un fichier. Ecrire un fichier à plat est généralement incroyablement rapide. –

4

À l'exception des chargeurs en vrac auxquels d'autres font référence, considérons comment le faire au mieux via SQL. (Et les chargeurs en bloc ne fonctionnent pas bien si vous envoyez des données mélangées à différentes tables.)

D'abord, vous ne devriez pas utiliser la couche d'abstraction que vous utilisez, dans ce cas iBatis, car elle est efficace vous offrira peu de valeur, mais cette couche d'abstraction aura un certain coût CPU (pas nécessairement beaucoup, mais un peu). Vous devriez vraiment simplement utiliser une connexion à une base de données brute.

Ensuite, vous enverrez un paquet d'instructions INSERT. La question est de savoir si vous devez utiliser une chaîne simple pour la déclaration, (c'est-à-dire INSERT INTO TABLE1 VALUES ('x', 'y', 12)) vs une instruction préparée (INSERT INTO TABLE1 VALUES (?,?,?)).

Cela dépend de votre base de données et des pilotes de base de données.

Le problème avec l'utilisation d'une chaîne simple, est essentiellement le coût de conversion d'un format interne (en supposant que vous insérez des données Java) à la chaîne. La conversion d'un nombre ou d'une date en chaîne est en fait une opération CPU assez coûteuse. Certaines bases de données et pilotes fonctionneront directement avec les données binaires, plutôt que simplement avec les données de chaîne. Ainsi, dans ce cas, un PreparedStatement pourrait permettre de réduire certaines économies d'unité centrale en n'ayant potentiellement pas besoin de convertir les données. L'inconvénient est que ce facteur variera en fonction du fournisseur de la base de données et, potentiellement, du fournisseur de la base de données JDBC. Par exemple, Postgres (je crois) ne fonctionne qu'avec des chaînes SQL, plutôt que binaire, donc utiliser PreparedStatement est une perte de temps en construisant simplement la chaîne vous-même.

Ensuite, une fois que vous avez votre type d'instruction, vous souhaitez utiliser la méthode addBatch() de la classe JDBC Statement. Ce que addBatch fait est de regrouper les instructions SQL dans, bien, un lot. L'avantage est qu'au lieu d'envoyer plusieurs requêtes à la base de données, vous envoyez une seule requête LARGE. Cela réduit le trafic réseau, et donnera des gains notables dans le débit.Le détail est que tous les pilotes/bases de données ne supportent pas addBatch (du moins pas bien), mais aussi que la taille de votre lot est limitée. Il est fort probable que vous ne puissiez pas ajouter de Batch pour les 20 000 lignes et que vous vous attendiez à ce que cela fonctionne, même si ce serait le meilleur pari. Cette limite peut également varier selon la base de données.

Pour Oracle, dans le passé, j'ai utilisé un tampon de 64K. Fondamentalement, j'ai écrit une fonction wrapper qui prendrait une instruction INSERT littérale, et les accumulerait en lots de 64K. Donc, si vous voulez insérer des données en vrac via SQL via JDBC, ce sont les moyens de le faire. La grande amélioration est le mode batch, le Statement vs PreparedStatement est plus de conserver potentiellement un peu de CPU, et peut-être le trafic réseau si votre pilote prend en charge un protocole binaire.

Testez, rincez et répétez jusqu'à ce que vous soyez assez heureux.