J'ai une table de 500 millions de lignes (et en croissance)
J'ai fait ce qui suit pour améliorer les performances des inserts:
Côté base de données:
- abandonné tous les index et contraintes
- journalisation désactivée
Côté application:
- passage d'entités gérées JPA à des requêtes d'insertion natives, ajout d'un indice Oracle APPEND à la requête
- essayé de valider par lots par 1k / 2k / 3k de lignes
- essayé d'écrire en parallèle (plusieurs threads, nombre de threads = nombre de core sur le serveur) sur une table
Cela m'a donné environ 300 lignes par seconde
En outre essayé:
- écrire en parallèle par lots sur plusieurs tables (pour regrouper puis sauvegarder les résultats en utilisant UNION)
Cela m'a donné environ 1 000 lignes par seconde, mais sur des tables vides. Mais lorsque j'ai rempli des tableaux avec des données factices (200 millions chacune), la vitesse des insertions est tombée à 250 - 300 par seconde.
Quelqu'un pourrait-il suggérer quoi d'autre pour accélérer les insertions? Fondamentalement, je veux d'abord comprendre quel est (ce qui pourrait être) le goulot d'étranglement.
UPD: la table est partitionnée par date d'insertion, la table a environ 60 colonnes - la plupart des colonnes sont VARCHAR2 (2000 BYTE)
/*+APPEND*/
indication est ignorée sur les insertions à une seule ligne (si vousINSERT INTO ... SELECT
n'avez pas la peine d'ajouter). (3) Vous devez configurer un exemple SQL * Loader avecdirect=true
pour établir une ligne de base comme suggéré par @parsifal.Réponses:
Je viens de voir la mise à jour, la table 60-col avec principalement des champs VARCHAR (2k) - c'est (potentiellement) une table monstre.
Tout d'abord ...
Vous devez d'abord comprendre votre goulot d'étranglement. Du côté de l'application, retournez à votre solution d'insertion par lots à un seul thread (1/2 / 3k à la fois) et commencez à l'exécuter et connectez-vous à la machine DB et exécutez un `` top '' - voyez combien le temps que prend le processus DB ET combien (le cas échéant) wa% de temps la machine affiche.
Si top vous affiche TOUT temps, cela signifie que votre base de données est liée aux E / S et vous devrez probablement prendre en compte plusieurs machines DB (fragments) ou envisager de lancer des SSD sur la machine hôte.
C'est ça; votre recherche s'arrête là. Peu importe la quantité de CPU prise par la base de données ou la saturation de votre client d'application. si vous rencontrez des problèmes de latence d'E / S sur la base de données hôte, c'est aussi rapide que cela ne vous ira JAMAIS.
CONSEIL Si des modifications matérielles sont hors de question, selon le système de fichiers que vous exécutez (Linux), vous pouvez essayer de désactiver la journalisation ou l'écriture de métadonnées pour la base de données afin d'améliorer légèrement les performances au niveau du système de fichiers. Vous pouvez faire quelque chose de similaire sur NTFS, mais cela ne vous donnera qu'un petit coup de pouce. Ce ne sera pas 2x.
Maintenant, deuxièmement ...
Supposons que vous n'ayez presque pas eu de temps, mais que votre processeur est entièrement lié au processus DB. Votre seule option est maintenant d'introduire plus de machines DB (fragments) et de diviser le travail.
Encore une fois, vous avez terminé vos recherches si tel est le cas. Rien de ce que vous pouvez faire pour modifier le CPU pour aller plus vite.
Enfin, troisième chose ... troisième ...
Disons que la DB ne fait pas grand-chose. Ensuite, accédez à la machine cliente exécutant l'insertion par lots et vérifiez la charge du processeur - est-elle liée? Si c'est le cas, lancez quelques autres machines en faisant exactement les mêmes insertions par lots et voyez si vous pouvez obtenir une rampe linéaire.
Si le CPU n'est pas arrimé, lancez quelques threads supplémentaires sur la même machine jusqu'à ce qu'il soit arrimé et voyez comment la base de données évolue.
Je pense que vous avez peut-être déjà essayé cela, donc je suppose que votre hôte client était déjà ancré (et plus de threads ne feront pas de différence) ou que la base de données atteignait déjà sa limite et ne peut pas évoluer plus loin.
Addenda
Faire des insertions brutes sur une table non indexée qui ne contient pas de déchets est essentiellement une opération APPEND qui devrait aller aussi vite que le disque peut gérer les écritures.
Créer plus de tables sur la même machine hôte ne va pas aider, si cela augmente votre recherche de disque (pour accéder aux autres tables du disque pour y ajouter) et ralentira les choses.
Il est essentiel de comprendre ce goulot d'étranglement d'abord, puis nous pouvons optimiser l'enfer hors de lui.
J'espère que cela pourra aider! Tenez-nous au courant.
la source
L'invocation de l'insertion de chemin direct avec l'indicateur d'ajout entraîne la prise d'un verrou exclusif sur la table entière, donc le fait d'avoir plusieurs threads effectuant l'insertion n'aidera pas. Vous devez explicitement adresser une partition différente à chaque insertion ...
... pour obtenir des verrous exclusifs au niveau de la partition. Vous ne pourrez pas le faire avec une table partitionnée à la date d'insertion, très probablement, mais vous pouvez utiliser le partitionnement composite (pas le sous-partitionnement) pour obtenir plusieurs partitions par plage unique de dates d'insertion.
Ne vous engagez pas au milieu des insertions, juste à la fin.
la source