web-dev-qa-db-fra.com

ResultSet: récupération des valeurs de colonne par index par rapport à récupération par étiquette

Lorsque j'utilise JDBC, je rencontre souvent des constructions comme

ResultSet rs = ps.executeQuery();
while (rs.next()) {
    int id = rs.getInt(1);
    // Some other actions
}

Je me suis demandé (et aux auteurs de code aussi) pourquoi ne pas utiliser des étiquettes pour récupérer les valeurs des colonnes:

int id = rs.getInt("CUSTOMER_ID");

La meilleure explication que j'ai entendue concerne la performance. Mais en fait, cela rend-il le traitement extrêmement rapide? Je ne le crois pas, même si je n'ai jamais effectué de mesures. Même si la récupération par étiquette serait un peu plus lente, elle offrirait à mon avis une meilleure lisibilité et flexibilité.
Quelqu'un pourrait-il donc me donner une bonne explication pour éviter de récupérer des valeurs de colonne par index de colonne plutôt que par étiquette de colonne? Quels sont les avantages et les inconvénients des deux approches (peut-être concernant certains SGBD)?

50
Rorick

Vous devez utiliser étiquettes de chaîne par défaut.

Avantages:

  • Indépendance de l'ordre des colonnes
  • Meilleure lisibilité/maintenabilité

Inconvénients:

  • Vous n'avez aucun contrôle sur les noms des colonnes (accès via des procédures stockées)

Lequel préférez-vous?

ints?

int i = 1;
customerId = resultSet.getInt (i ++);
customerName = resultSet.getString (i ++);
customerAddress = resultSet.getString (i ++);

ou cordes?

customerId = resultSet.getInt ("customer_id");
customerName = resultSet.getString ("customer_name");
customerAddress = resultSet.getString ("customer_address");

Et si une nouvelle colonne est insérée à la position 1? Quel code préférez-vous? Ou si l'ordre des colonnes est modifié, quelle version de code devez-vous modifier?

C'est pourquoi vous devez utiliser étiquettes de chaîne par défaut.

46
Martin Klinke

Avertissement: je vais devenir explosif ici, car cela me rend fou.

99% * du temps, c'est une micro-optimisation ridicule que les gens ont une idée vague qui rend les choses "meilleures". Cela ignore complètement le fait que, sauf si vous êtes dans une boucle extrêmement serrée et occupée sur des millions de résultats SQL tout le temps, ce qui, espérons-le, est rare, vous ne le remarquerez jamais. Pour tous ceux qui ne le font pas, le coût en temps de développement de la maintenance, de la mise à jour et de la correction des bogues dans l'indexation des colonnes est bien supérieur au coût incrémentiel du matériel pour votre application aux performances infiniment moins bonnes.

Ne codez pas les optimisations comme celle-ci dans. Code pour la personne qui les gère. Ensuite, observez, mesurez, analysez et optimisez. Observez à nouveau, mesurez à nouveau, analysez à nouveau et optimisez à nouveau.

L'optimisation est à peu près la dernière étape du développement, pas la première.

* Le chiffre est composé.

56
Cowan

La réponse a néanmoins été acceptée, voici quelques informations complémentaires et une expérience personnelle que je n'ai pas encore pu mettre en avant.

Utilisez des noms de colonnes (les constantes et non les littéraux sont préférés) en général et si possible. C'est à la fois plus clair, plus facile à maintenir et les modifications futures sont moins susceptibles de casser le code.

Il existe cependant une utilisation pour les index de colonnes. Dans certains cas, ceux-ci sont plus rapides, mais pas suffisamment pour que cela remplace les raisons ci-dessus pour les noms *. Celles-ci sont très précieuses lors du développement d'outils et de méthodes générales traitant de ResultSets. Enfin, un index peut être requis car la colonne n'a pas de nom (comme un agrégat sans nom) ou il existe des noms en double, il n'y a donc pas de moyen facile de référencer les deux.

* Notez que j'ai écrit quelques pilotes JDBC et regardé à l'intérieur de sources ouvertes et celles-ci utilisent en interne des index de colonnes pour référencer les colonnes de résultats. Dans tous les cas avec lesquels j'ai travaillé, le pilote interne mappe d'abord un nom de colonne à un index. Ainsi, vous pouvez facilement voir que le nom de la colonne, dans tous ces cas, prendrait toujours plus de temps. Cela peut ne pas être vrai pour tous les pilotes.

6
Kevin Brock

Depuis la documentation Java:

L'interface ResultSet fournit des méthodes getter (getBoolean, getLong, etc.) pour récupérer les valeurs de colonne de la ligne actuelle. Les valeurs peuvent être récupérées à l'aide du numéro d'index de la colonne ou du nom de la colonne. En général, l'utilisation de l'index de colonne sera plus efficace. Les colonnes sont numérotées de 1. Pour une portabilité maximale, les colonnes de l'ensemble de résultats dans chaque ligne doivent être lues de gauche à droite et chaque colonne ne doit être lue qu'une seule fois.

Bien sûr, chaque méthode (nommée ou indexée) a sa place. Je suis d'accord que les colonnes nommées devraient être la valeur par défaut. Cependant, dans les cas où un grand nombre de boucles sont nécessaires et où l'instruction SELECT est définie et maintenue dans la même section de code (ou classe), les index doivent être corrects - il est conseillé de répertorier les colonnes sélectionnées, pas seulement "SELECT * FROM ...", car tout changement de table cassera le code.

6
Jason

Bien sûr, l'utilisation des noms de colonnes augmente la lisibilité et facilite la maintenance. Mais l'utilisation de noms de colonnes a un revers. Comme vous le savez, SQL autorise plusieurs noms de colonne avec le même nom, il n'y a aucune garantie que le nom de colonne que vous avez tapé dans la méthode getter de resultSet pointe réellement vers le nom de colonne auquel vous avez l'intention d'accéder. En théorie, l'utilisation de numéros d'index au lieu de noms de colonne est préférable, mais elle réduit la lisibilité ...

Merci

4
user228462

Vous pouvez avoir le meilleur des deux! La vitesse d'utilisation des index avec la maintenabilité et la sécurité de l'utilisation des noms de colonne.

Tout d'abord - à moins que vous ne boucliez à travers un jeu de résultats, utilisez simplement les noms de colonne.

  1. Définissez un ensemble de variables entières, une pour chaque colonne à laquelle vous accéderez. Les noms des variables peuvent inclure le nom de la colonne: par ex. iLast_Name.

  2. Avant la boucle d'ensemble de résultats, parcourez les métadonnées de colonne et définissez la valeur de chaque variable entière sur l'index de colonne du nom de colonne correspondant. Si l'index de la colonne 'Last_Name' est 3, définissez la valeur de 'iLast_Name' sur 3.

  3. Dans la boucle du jeu de résultats, utilisez les noms de variables entières dans les méthodes GET/SET. Le nom de la variable est un indice visuel pour le développeur/mainteneur quant au nom réel de la colonne en cours d'accès, mais la valeur est l'index de la colonne et donnera les meilleures performances.

REMARQUE: le mappage initial (c'est-à-dire le nom de la colonne pour le mappage d'index) n'est effectué qu'une seule fois avant la boucle plutôt que pour chaque enregistrement et colonne de la boucle.

2
Rick Post

J'ai fait un profilage des performances sur ce sujet exact sur une base de données Oracle. Dans notre code, nous avons un ResultSet avec de nombreuses colonnes et un grand nombre de lignes. Sur les 20 secondes (!) La demande prend pour exécuter la méthode Oracle.jdbc.driver.ScrollableResultSet.findColumn (String name) prend environ 4 secondes.

Évidemment, il y a quelque chose qui ne va pas dans la conception globale, mais l'utilisation d'index au lieu des noms de colonne prendrait probablement 4 secondes.

2
Marko Ullgren

Je ne pense pas que l'utilisation des étiquettes affecte beaucoup les performances. Mais il y a une autre raison de ne pas utiliser Strings. Ou ints, d'ailleurs.

Pensez à utiliser des constantes. L'utilisation d'une constante int rend le code plus lisible, mais aussi moins susceptible d'avoir des erreurs.

En plus d'être plus lisible, la constante vous empêche également de faire des fautes de frappe dans les noms d'étiquette - le compilateur générera une erreur si vous le faites. Et tout IDE vaut quelque chose le ramassera. Ce n'est pas le cas si vous utilisez Strings ou ints.

2
Sietse

Le pilote JDBC prend soin de la colonne pour indexer la recherche. Ainsi, si vous extrayez des valeurs par nom de colonne à chaque fois que le pilote effectue une recherche (généralement dans une carte de hachage) pour vérifier l'index correspondant pour le nom de colonne.

1
zloster

Outre la recherche dans Map pour les étiquettes, cela conduit également à une création de chaîne supplémentaire. Bien que cela se produise sur la pile, mais cela a un coût.

Tout dépend du choix individuel et jusqu'à la date, je n'ai utilisé que des index :-)

0
Vinod Singh

Je suis d'accord avec les réponses précédentes que la performance n'est pas quelque chose qui peut nous forcer à choisir l'une ou l'autre des approches. Il serait bon de considérer les choses suivantes à la place:

  • Lisibilité du code: pour chaque développeur qui lit vos étiquettes de code, elles ont beaucoup plus de sens que les index.
  • Maintenance: pensez à la requête SQL et à la façon dont elle est maintenue. Qu'est-ce qui est le plus susceptible de se produire dans votre cas après avoir corrigé/amélioré/refactorisé la requête SQL: changer l'ordre des colonnes extraites ou changer les noms des colonnes de résultat. Il me semble que le changement de l'ordre des colonnes extraites (comme les résultats de l'ajout/suppression de nouvelles colonnes dans le jeu de résultats) a une plus grande probabilité de se produire.
  • Encapsulation: malgré la façon dont vous choisissez, essayez d'isoler le code dans lequel vous exécutez la requête SQL et analysez le jeu de résultats dans le même composant et faites uniquement connaître à ce composant les noms des colonnes et leur mappage aux index (si vous avez décidé de les utiliser) ).
0
Cha2lenger

L'utilisation de l'index est une tentative d'optimisation.

Le temps ainsi gagné est perdu par l'effort supplémentaire qu'il faut au développeur pour rechercher les données nécessaires pour vérifier si leur code fonctionnera correctement après les modifications.

Je pense que c'est notre instinct intégré d'utiliser des chiffres plutôt que du texte.

0
databyss

Comme cela est souligné par d'autres affiches, je m'en tiendrai aux noms de colonnes, sauf si vous avez une raison vraiment puissante de ne pas le faire. L'impact sur les performances est négligeable par rapport, par exemple, à l'optimisation des requêtes. Dans ce cas, la maintenance est beaucoup plus importante qu'une petite optimisation.

0
Rober2D2