web-dev-qa-db-fra.com

Préparé Déclarations et performances

Donc, je continue à entendre que les déclarations préparées sont bonnes pour la performance.

Nous avons une application Java dans laquelle nous utilisons la 'Statement' régulière plus que nous n'utilisons la 'PreparedStatement'. Tout en essayant de progresser vers l'utilisation de plus de PreparedStatements, j'essaie d'obtenir une compréhension plus approfondie du fonctionnement de PreparedStatements - côté client et côté serveur.

Donc, si nous avons des opérations CRUD typiques et mettons à jour un objet à plusieurs reprises dans l'application, cela aide-t-il d'utiliser un PS? Je comprends que nous devrons fermer le PS à chaque fois sinon cela entraînera une fuite de curseur.

Alors, comment cela aide-t-il à la performance? Le pilote met-il en cache l'instruction précompilée et m'en remet-il une copie la prochaine fois que je ferai connection.prepareStatement? Ou le serveur DB aide-t-il?

Je comprends l'argument concernant les avantages de sécurité des PreparedStatements et j'apprécie les réponses ci-dessous qui le soulignent. Cependant, je veux vraiment que cette discussion reste centrée sur les avantages de performances des PreparedStatements.

Mise à jour: Quand je dis mise à jour des données, je veux vraiment dire plus en termes de cette méthode étant appelée au hasard plusieurs fois. Je comprends l'avantage de la réponse ci-dessous qui demande de réutiliser l'instruction dans une boucle.

    // some code blah blah
    update();

    // some more code blah blah 
    update();

.... 

public void update () throws SQLException{
 try{
      PreparedStatement ps = connection.prepareStatement("some sql");
      ps.setString(1, "foobar1");
      ps.setString(2, "foobar2");
      ps.execute();
 }finally {
     ps.close();

 }

}

Il n'y a aucun moyen de réutiliser réellement 'ps' Java object et je comprends que l'appel connection.prepareStatement est assez cher.

C'est ce qui me ramène à la question d'origine. Est-ce que "certains sql" PreparedStatement sont toujours mis en cache et réutilisés sous les couvertures que je ne connais pas?

Je dois également mentionner que nous prenons en charge plusieurs bases de données.

Merci d'avance.

53
Kapsh

L'idée que les déclarations préparées concernent principalement les performances est une idée fausse, bien qu'elle soit assez courante.

Une autre affiche mentionne qu'il a noté une amélioration de la vitesse d'environ 20% dans Oracle et SQL Server. J'ai noté une figure similaire avec MySQL. Il s'avère que l'analyse de la requête n'est tout simplement pas une partie aussi importante du travail impliqué. Sur un système de base de données très occupé, il n'est pas clair non plus que l'analyse des requêtes affectera le débit global: dans l'ensemble, il utilisera probablement juste du temps CPU qui serait sinon inactif pendant que les données reviennent du disque.

Donc, comme raison d'utiliser des instructions préparées, la protection contre les attaques par injection SQL l'emporte de loin l'amélioration des performances. Et si vous n'êtes pas inquiet des attaques par injection SQL, vous devriez probablement l'être ...

30
Neil Coffey

Les instructions préparées peuvent améliorer les performances lors de la réutilisation de la même instruction que vous avez préparée:

PreparedStatement ps = connection.prepare("SOME SQL");

for (Data data : dataList) {
  ps.setInt(1, data.getId());
  ps.setString(2, data.getValue();
  ps.executeUpdate();
}

ps.close();

C'est beaucoup plus rapide que de créer l'instruction dans la boucle.

Certaines plates-formes mettent également en cache les instructions préparées de sorte que même si vous les fermez, elles peuvent être reconstruites plus rapidement.

Cependant, même si les performances sont identiques, vous devez toujours utiliser des instructions préparées pour empêcher l'injection SQL. Dans mon entreprise, c'est une question d'entrevue; vous trompez et nous pourrions ne pas vous embaucher.

28

Les instructions préparées sont en effet mises en cache après leur première utilisation, ce qu'elles offrent en termes de performances par rapport aux instructions standard. Si votre déclaration ne change pas, il est conseillé d'utiliser cette méthode. Ils sont généralement stockés dans un cache d'instructions pour une autre utilisation.

Plus d'informations peuvent être trouvées ici:

http://www.theserverside.com/tt/articles/article.tss?l=Prepared-Statments

et vous souhaiterez peut-être considérer Spring JDBCTemplate comme une alternative à l'utilisation directe de JDBC.

http://static.springframework.org/spring/docs/2.0.x/reference/jdbc.html

14
Jon

L'analyse du SQL n'est pas la seule chose qui se passe. Il y a la validation de l'existence des tables et des colonnes, la création d'un plan de requête, etc. Vous payez cela une fois avec un PreparedStatement.

La liaison pour se prémunir contre l'injection SQL est en effet une très bonne chose. Pas suffisant, OMI. Vous devez toujours valider l'entrée avant d'accéder à la couche de persistance.

8
duffymo

Alors, comment cela aide-t-il à la performance? Le pilote met-il en cache l'instruction précompilée et m'en remet-il une copie la prochaine fois que je ferai connection.prepareStatement? Ou le serveur DB aide-t-il?

Je répondrai en termes de performances. D'autres ici ont déjà stipulé que PreparedStatements sont résistants à l'injection SQL (avantage béni).

L'application (pilote JDBC) crée le PreparedStatement et le transmet au SGBDR avec des espaces réservés (le ?). Le SGBDR précompile, en appliquant l'optimisation de requête (si nécessaire) des PreparedStatement reçus et (dans certains) les met généralement en cache. Lors de l'exécution de PreparedStatement, le PreparedStatement précompilé est utilisé, remplaçant chaque espace réservé par ses valeurs pertinentes et calculé. Ceci contraste avec Statement qui le compile et l'exécute directement, le PreparedStatement compile et optimise la requête ne seule fois. Maintenant, ce scénario expliqué ci-dessus n'est pas un cas absolu par TOUS les fournisseurs JDBC, mais c'est essentiellement la façon dont PreparedStatement est utilisé et utilisé.

4
Buhake Sindi

Pour l'anecdote: j'ai fait quelques expériences avec des instructions préparées vs dynamiques en utilisant ODBC in Java 1.4 il y a quelques années, avec des backends Oracle et SQL Server. I ont constaté que les instructions préparées pouvaient être jusqu'à 20% plus rapides pour certaines requêtes, mais il y avait des différences spécifiques au fournisseur concernant les requêtes qui avaient été améliorées dans quelle mesure (cela ne devrait pas être vraiment surprenant).

L'essentiel est que si vous réutilisez la même requête à plusieurs reprises, les instructions préparées peuvent aider à améliorer les performances; mais si vos performances sont suffisamment mauvaises pour que vous deviez y remédier immédiatement, ne comptez pas sur l'utilisation d'instructions préparées pour vous donner un coup de pouce radical. (20% n'est généralement pas une raison d'écrire.)

Votre kilométrage peut varier, bien sûr.

3
Dan Breslau

C'est ce qui me ramène à la question d'origine. Est-ce que "certains sql" PreparedStatement sont toujours mis en cache et réutilisés sous les couvertures que je ne connais pas?

Oui au moins avec Oracle. Per Oracle® Database JDBC Developer's Guide Implicit Statement Caching (soulignement ajouté),

Lorsque vous activez la mise en cache implicite des instructions, JDBC met automatiquement en cache l'instruction préparée ou appelable lorsque vous appelez la méthode close de cet objet d'instruction. Les instructions préparées et appelables sont mises en cache et récupérées à l'aide des méthodes d'objet de connexion et d'objet d'instruction standard.

Les instructions simples ne sont pas implicitement mises en cache, car la mise en cache implicite des instructions utilise une chaîne SQL comme clé et les instructions simples sont créées sans chaîne SQL. Par conséquent, la mise en cache implicite des instructions s'applique uniquement aux objets OraclePreparedStatement et OracleCallableStatement, qui sont créés avec une chaîne SQL. Vous ne pouvez pas utiliser la mise en cache implicite des instructions avec OracleStatement. Lorsque vous créez un OraclePreparedStatement ou OracleCallableStatement, le pilote JDBC recherche automatiquement dans le cache une instruction correspondante .

3
Elliott Frisch

1. PreparedStatement vous permet d'écrire une requête dynamique et paramétrique

En utilisant PreparedStatement dans Java vous pouvez écrire des requêtes SQL paramétrées et envoyer différents paramètres en utilisant les mêmes requêtes SQL, ce qui est bien mieux que de créer des requêtes différentes.

2. PreparedStatement est plus rapide que Statement en Java

L'un des principaux avantages de l'utilisation de PreparedStatement est de meilleures performances. PreparedStatement est pré-compilé dans la base de données et le plan d'accès est également mis en cache dans la base de données, ce qui permet à la base de données d'exécuter la requête paramétrique écrite à l'aide de l'instruction préparée beaucoup plus rapidement que la requête normale car elle a moins de travail à faire. Vous devez toujours essayer d'utiliser PreparedStatement dans le code JDBC de production pour réduire la charge sur la base de données. Afin d'obtenir des avantages en termes de performances, il convient de noter qu'il ne faut utiliser que la version paramétrée de la requête SQL et non avec la concaténation de chaînes

3. PreparedStatement empêche les attaques par injection SQL en Java

En savoir plus: http://javarevisited.blogspot.com/2012/03/why-use-preparedstatement-in-Java-jdbc.html#ixzz3LejuMnVL

2
Siva Kumar

Les instructions préparées présentent certains avantages en termes de performances par rapport aux instructions normales, selon la façon dont vous les utilisez. Comme quelqu'un l'a déjà dit, si vous devez exécuter la même requête plusieurs fois avec différents paramètres, vous pouvez réutiliser l'instruction préparée et transmettre uniquement le nouveau jeu de paramètres. L'amélioration des performances dépend du pilote et de la base de données spécifiques que vous utilisez.

Par exemple, en termes de performances de base de données, la base de données Oracle met en cache le plan d'exécution de certaines requêtes après chaque calcul (ce n'est pas vrai pour toutes les versions et toutes les configurations d'Oracle). Vous pouvez trouver des améliorations même si vous fermez une instruction et en ouvrez une nouvelle, car cela se fait au niveau du SGBDR. Ce type de mise en cache n'est activé que si les deux requêtes suivantes sont (caractère par caractère) identiques. Cela ne s'applique pas aux instructions normales, car les paramètres font partie de la requête et produisent différentes chaînes SQL.

Certains autres SGBDR peuvent être plus "intelligents", mais je ne m'attends pas à ce qu'ils utilisent des algorithmes de correspondance de modèles complexes pour mettre en cache les plans d'exécution car cela réduirait les performances. Vous pouvez affirmer que le calcul du plan d'exécution n'est qu'une petite partie de l'exécution de la requête. Pour le cas général, je suis d'accord, mais .. ça dépend. Gardez à l'esprit que, généralement, le calcul d'un plan d'exécution peut être une tâche coûteuse, car les rdbms doivent consulter des données hors mémoire comme des statistiques (pas seulement Oracle).

Cependant, l'argument sur la mise en cache va des plans d'exécution à d'autres parties du processus d'extraction. Donner au SGBDR plusieurs fois la même requête (sans aller en profondeur pour une implémentation particulière) aide à identifier les structures déjà calculées au niveau JDBC (pilote) ou RDBMS. Si vous ne trouvez aucun avantage particulier dans les performances maintenant, vous ne pouvez pas exclure que l'amélioration des performances sera implémentée dans les versions futures/alternatives du pilote/rdbms.

Des améliorations de performances pour les mises à jour peuvent être obtenues en utilisant des instructions préparées en mode batch, mais c'est une autre histoire.

1
Nicola Ferraro

Réponse courte:

PreparedStatement améliore les performances, car les clients DB exécutent généralement la même requête de manière répétitive, ce qui permet d'effectuer un prétraitement pour la requête initiale pour accélérer les requêtes répétitives suivantes .

Réponse longue:

Selon Wikipedia , le flux de travail typique de l'utilisation d'une instruction préparée est le suivant:

Préparer : Le modèle d'instruction est créé par l'application et envoyé au système de gestion de base de données (SGBD). Certaines valeurs ne sont pas spécifiées, appelées paramètres, espaces réservés ou variables de liaison (étiquetées "?" Ci-dessous): INSÉRER DANS LE PRODUIT (nom, prix) VALEURS (?,?)

(Pré-compilation) : Le SGBD analyse, compile et effectue l'optimisation des requêtes sur le modèle d'instruction, et stocke le résultat sans l'exécuter.

Execute : Plus tard, l'application fournit (ou lie) des valeurs pour les paramètres, et le SGBD exécute l'instruction (renvoyant éventuellement un résultat). L'application peut exécuter l'instruction autant de fois qu'elle le souhaite avec des valeurs différentes. Dans cet exemple, il peut fournir "Pain" pour le premier paramètre et "1,00" pour le second paramètre.

Préparez:

Dans JDBC, l'étape "Préparer" se fait en appelant l'API Java.sql.Connection . prepareStatement (String sql). Selon son Javadoc:

Cette méthode est optimisée pour gérer les instructions SQL paramétriques qui bénéficient de la précompilation. Si le pilote prend en charge la précompilation, la méthode prepareStatement enverra l'instruction à la base de données pour la précompilation. Certains pilotes peuvent ne pas prendre en charge la précompilation. Dans ce cas, l'instruction ne peut pas être envoyée à la base de données tant que l'objet PreparedStatement n'est pas exécuté. Cela n'a aucun effet direct sur les utilisateurs; cependant, cela affecte les méthodes qui lancent certains objets SQLException.

Étant donné que l'appel de cette API peut envoyer l'instruction SQL à la base de données, il s'agit généralement d'un appel coûteux. Selon l'implémentation du pilote JDBC, si vous avez le même modèle d'instruction sql, pour de meilleures performances, vous devrez peut-être éviter d'appeler cette API plusieurs fois côté client pour le même modèle d'instruction sql.

Précompilation:

Le modèle de relevé envoyé sera précompilé sur la base de données et mis en cache sur le serveur db. La base de données utilisera probablement le modèle de connexion et d'instruction sql comme clé, et la requête précompilée et le plan de requête calculé comme valeur dans le cache. L'analyse de la requête peut nécessiter de valider la table et les colonnes à interroger, ce qui peut donc être une opération coûteuse, et le calcul de plan de requête est également une opération coûteuse.

Exécuter:

Pour les requêtes suivantes à partir du même modèle de connexion et d'instruction SQL, la requête précompilée et le plan de requête seront recherchés directement à partir du cache par le serveur de base de données sans recalculer à nouveau.

Conclusion:

Du point de vue des performances, l'utilisation de l'instruction prepare est un processus en deux phases:

  1. Phase 1, préparation et précompilation, cette phase devrait être effectuée une fois et ajouter des frais généraux pour les performances.
  2. Phase 2, exécutions répétées de la même requête, car la phase 1 a un certain prétraitement pour la requête, si le nombre de requêtes répétitives est suffisamment important, cela peut économiser beaucoup d'efforts de prétraitement pour la même requête.

Et si vous voulez en savoir plus, il y a quelques articles expliquant les avantages de PrepareStatement:

  1. http://javarevisited.blogspot.com/2012/03/why-use-preparedstatement-in-Java-jdbc.html
  2. http://docs.Oracle.com/javase/tutorial/jdbc/basics/prepared.html
1
nybon