Réseau
Tout d'abord, depuis l'utilisation de rowid et rownum est de toute façon verrouillé par le fournisseur, vous devriez envisager d'utiliser des routines stockées dans la base de données. Cela pourrait réduire considérablement les frais généraux de transmission des données de la base de données au serveur d'applications (surtout s'ils se trouvent sur des machines différentes et connectés via le réseau).
Considérant que vous avez 80 millions d'enregistrements à transmettre, cela pourrait être la meilleure amélioration de performances pour vous, bien que cela dépende du type de travail effectué par vos threads.
De toute évidence, l'augmentation de la bande passante aiderait également à résoudre les problèmes de réseau.
Performances du disque
Avant d'apporter des modifications au code, vérifiez la charge du disque dur pendant l'exécution des tâches, peut-être qu'il ne peut tout simplement pas gérer autant d'E/S (10 threads lisant simultanément).
La migration vers un SSD/RAID ou une base de données en cluster peut résoudre le problème. Dans ce cas, la modification de la façon dont vous accédez à la base de données ne le sera pas.
Le multithreading pourrait résoudre les problèmes de CPU, mais les bases de données dépendent principalement du système de disque.
Rownum
Vous pourriez rencontrer quelques problèmes si vous l'implémentez en utilisant rowid et rownum.
1) rownum est généré à la volée pour les résultats de chaque requête. Donc, si la requête n'a pas de tri explicite et qu'il est possible que certains enregistrements aient un numéro de ligne différent à chaque fois que vous exécutez la requête.
Par exemple, vous l'exécutez la première fois et obtenez des résultats comme celui-ci :
some_column | rownum
____________|________
A | 1
B | 2
C | 3
puis vous l'exécutez une deuxième fois, puisque vous n'avez pas de tri explicite, dbms (pour une raison connue de lui-même) décide de renvoyer des résultats comme celui-ci :
some_column | rownum
____________|________
C | 1
A | 2
B | 3
2) le point 1 implique également que si vous filtrez les résultats sur rownum il générera une table temporaire avec ALL résultats, puis filtrez-le
Alors rownum n'est pas un bon choix pour fractionner les résultats. Tandis que rowid semblait mieux, il y a aussi quelques problèmes.
Robind
Si vous regardez la description ROWID vous remarquerez peut-être que "la valeur rowid identifie de manière unique une ligne dans la base de données ".
À cause de cela et du fait que lorsque vous supprimez une ligne, vous avez un "trou" dans la séquence rowid, les rowids peuvent être répartis de manière inégale entre les enregistrements de la table.
Ainsi, par exemple, si vous avez trois threads et que chacun récupère 1 000 000 rowids, il est possible que l'un obtienne 1 000 000 d'enregistrements et les deux autres 1 enregistrement chacun. Ainsi l'un sera submergé, tandis que les deux autres mourront de faim .
Ce n'est peut-être pas un gros problème dans votre cas, même si cela pourrait très bien être le problème que vous rencontrez actuellement avec le modèle de clé primaire.
Ou si vous récupérez d'abord tous les rowids dans le répartiteur, puis les divisez également (comme l'a suggéré peter.petrov), cela pourrait faire l'affaire, bien que récupérer 80 millions d'identifiants semble toujours beaucoup, je pense qu'il serait préférable de faire le fractionnement avec un sql-query qui renvoie les bordures des morceaux.
Ou vous pouvez résoudre ce problème en donnant une faible quantité de rowids par tâche et en utilisant le framework Fork-Join introduit dans Java 7, mais il devrait être utilisé soigneusement .
Point également évident :rownum et rowid ne sont pas portables d'une base de données à l'autre.
Il est donc préférable d'avoir votre propre colonne "sharding", mais vous devrez ensuite vous assurer qu'elle divise les enregistrements en morceaux plus ou moins égaux.
Gardez également à l'esprit que si vous allez le faire dans plusieurs threads, il est important de vérifier quel mode de verrouillage la base de données utilise , peut-être qu'il verrouille simplement la table pour chaque accès, alors le multithreading est inutile.
Comme d'autres l'ont suggéré, vous feriez mieux de trouver d'abord quelle est la principale raison des faibles performances (réseau, disque, verrouillage de la base de données, manque de threads ou peut-être que vous avez simplement des requêtes sous-optimales - vérifiez les plans de requête).