Comme détaillé ici et confirmé ici , le nombre par défaut de lignes renvoyées par Oracle au moment de la requête de données sur JDBC est 10. Je travaille sur une application à lire et comparer de nombreuses données de notre base de données. Je pensais que si nous augmentions simplement defaultRowPrefetch
pour être quelque chose comme 1000, alors notre application fonctionnerait sûrement plus rapidement. Il s'est avéré plus lent et d'environ 20%.
Nous avons ensuite décidé d'augmenter lentement le nombre de 10 et de voir comment cela fonctionne. Nous avons vu une augmentation d'environ 10% en le plaçant entre 100 et 200. Je n'aurais jamais pensé, cependant, que le régler plus haut rendrait notre application plus lente. Des idées pourquoi cela pourrait arriver?
Merci!
MODIFIER:
Pour plus de précision, j'utilise Oracle 11g R2 et Java 6.
EDIT 2:
D'accord, je veux reformuler ma question pour être claire, car à en juger par les réponses ci-dessous, je ne m'exprime pas correctement:
Comment est-il possible que si je définis une taille de récupération plus élevée, mon application fonctionne plus lentement? Pour moi, cela revient à dire "Nous vous offrons une connexion Internet plus rapide, c'est-à-dire une pipe plus grosse, mais votre navigation sur le Web sera plus lente.
Toutes choses étant égales par ailleurs, comme elles l'ont été dans nos tests, nous sommes très curieux de savoir comment notre application pourrait fonctionner moins bien avec ce seul changement.
Explications possibles:
Java ne fait rien, tandis qu'Oracle calcule le 1000 premières lignes au lieu des 10 premières.
Oracle ne fait rien, tandis que Java calcule les 1000 dernières lignes au lieu des 10 dernières.
Les protocoles de communication (par exemple TCP/IP) attendent beaucoup et doivent alors gérer plus de données à la fois, mais le le transfert de données de pointe sera limité par les limites matérielles. Ceci est contrecarré par la surcharge du protocole, donc il devrait y avoir une taille de récupération optimale et tout ce qui est inférieur ou supérieur serait plus lent;))
Cela pourrait empirer si le processus de récupération est synchrone avec d'autres Java, de sorte que Java ne demande plus de lignes qu'après avoir traité les données précédentes et Oracle ne fait rien dans pendant ce temps.
Imaginez qu'il y ait 3 personnes:
- Le premier plie le papier A4 en deux
- Le 2ème apporte des piles de papier plié d'une pièce à l'autre
- 3e coupe une certaine forme du papier plié.
Quelle doit être la taille des piles, si le 1er doit attendre que le 2e revienne et que le 2e doive attendre que le 3e termine son travail?
Des piles de 1000 ne seront pas meilleures que des piles de 10 je suppose;))
Comme pour tout, il n'y a pas de paramètre FAST=TRUE
. Bien que la taille de récupération par défaut JDBC de 10 ne soit pas idéale pour votre situation, elle convient à une application "typique" OLTP, et n'est vraiment pas que mauvaise pour votre cas non plus, semble-t-il. Apparemment, une grande taille de récupération n'est pas idéale non plus pour votre situation. Mais encore une fois, ce n'est pas ça mauvais d'en faire 1000 à la fois.
L'autre facteur que vous n'avez pas mentionné est la façon dont LARGE les lignes qui sont tirées. Considérez que le bloc de données que vous extrayez du serveur de base de données à travers le réseau vers le serveur d'application est la sum(WIDTH*ROWS)
. Si vos lignes ont une largeur de 5 000 octets et que vous en tirez 1 000 à la fois, chaque extraction va apporter 5 Mo de données. Dans un autre cas, vos lignes sont peut-être "maigres" à seulement 100 octets. Ensuite, en récupérer 1000 revient à faire 100 000 pièces.
Parce que vous seul pouvez savoir à quoi ressembleront les données à revenir, la recommandation est de définir la taille de récupération à l'échelle du système pour le cas "général", puis d'ajuster individuellement les requêtes bizarres selon les besoins.
En général, j'ai également trouvé que 100 était un meilleur cadre pour les processus de données volumineux. Ce n'est pas une recommandation, mais relayer une observation.
BTW, au moins avec Oracle, vous devez être prudent avec la taille de récupération car le pilote Oracle met de côté un tableau pour la taille maximale possible prise par chaque ligne, pas la taille réelle des données. Donc, si vous avez une table grasse, votre empreinte mémoire peut en souffrir.
Jetez un œil ici - http://www.Oracle.com/technetwork/database/enterprise-edition/memory.pdf
Dans Oracle, vous pouvez trouver l'espace maximum possible occupé par une colonne dans la table de métadonnées user_tab_columns (data_length). Il peut être utilisé pour déterminer la taille de l'extraction.
Dans des tests approximatifs, j'ai trouvé que 4 * 1024 * 1024/sum (data_length pour toutes les colonnes de votre table) est une taille d'extraction raisonnable.
La bonne méthode consiste à utiliser setFetchSize.
Par défaut, quand Oracle JDBC exécute une requête, il récupère un jeu de résultats de 10 lignes à la fois à partir du curseur de la base de données. Il s'agit de la valeur de taille d'extraction de ligne Oracle par défaut. Vous pouvez modifier le nombre de lignes récupérées à chaque déplacement vers le curseur de la base de données en modifiant la valeur de la taille d'extraction de ligne.
JDBC standard vous permet également de spécifier le nombre de lignes extraites avec chaque aller-retour de base de données pour une requête, et ce nombre est appelé taille d'extraction. Dans Oracle JDBC, la valeur de lecture anticipée de ligne est utilisée comme taille d'extraction par défaut dans un objet instruction. La définition de la taille d'extraction remplace le paramètre de lecture anticipée des lignes et affecte les requêtes suivantes exécutées via cet objet d'instruction.
La taille de récupération est également utilisée dans un jeu de résultats. Lorsque l'objet instruction exécute une requête, la taille d'extraction de l'objet instruction est transmise à l'objet jeu de résultats produit par la requête. Cependant, vous pouvez également définir la taille d'extraction dans l'objet d'ensemble de résultats pour remplacer la taille d'extraction de l'instruction qui lui a été transmise.
daveslab, plus d'informations ...
Si votre application a besoin de l'ensemble des résultats pour commencer le traitement des données, une taille d'extraction plus grande peut apporter des améliorations. Cependant, il n'y a pas de nombre magique, il est nécessaire de tester la valeur la plus avantageuse.
La définition de la taille de prélecture peut affecter les performances d'une application. L'augmentation de la taille de prélecture réduira le nombre d'aller-retour requis pour obtenir toutes les données, mais augmentera l'utilisation de la mémoire. Cela dépendra du nombre et de la taille des colonnes de la requête et du nombre de lignes devant être renvoyées. Cela dépendra également de la mémoire et du chargement du processeur de la machine cliente JDBC. L'optimum est qu'une application client autonome sera différente du serveur d'applications lourdement chargé. La vitesse et la latence de la connexion réseau doivent également être prises en compte.
Le client Oracle JDBC semble pré-initialiser certaines structures de mémoire pour conserver la taille de prélecture complète. Donc, si vous lui définissez une taille de prélecture de 500, le 50x vous allouez beaucoup de mémoire que si vous aviez une taille de prélecture = 10. C'est une énorme demande supplémentaire sur GC Surtout si vous ne lisez pas réellement ces lignes. Pour penser, vous pourriez exécuter le GC 50x Souvent plus que nécessaire si vous ne récupérez normalement que quelques lignes; cela aura un impact important sur la réactivité de votre application.
Si possible, je recommande d'utiliser le setFetchSize sur une base par requête. Par exemple, si vous savez qu'une requête particulière ne renverra que quelques lignes, définissez la taille d'extraction sur 5. Si vous savez qu'une requête renverra 1 000 lignes, utilisez une taille d'extraction de 100.
À titre d'heuristique, il y a des avantages limités à dépasser 50-100.
J'espère que vous comprenez, j'utilise Google Translator.
À peu près ce qu'a dit Adam H. - il n'y a pas de paramètres universels pour tous les types de scénarios. Il faut du temps pour qu'Oracle récupère les lignes, donc le temps qu'il a passé à attendre les lignes côté serveur, avant de l'envoyer au client, aurait pu être dépensé dans votre application si le seuil de prélecture était plus bas, donc les performances en souffraient.
D'après mes souvenirs, Oracle utilise également la mise en cache côté client pour fournir des curseurs à défilement. Il pourrait être utile de ne positionner le curseur que vers l'avant, du moins du point de vue de la mémoire. Au moins, il était utile dans les anciennes versions du pilote JDBC, peut-être que le comportement a changé depuis.
Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY);