Mysql
 sql >> Base de données >  >> RDS >> Mysql

Dois-je utiliser une fonction JOIN ou exécuter plusieurs requêtes dans une structure en boucle ?

Aucune des deux solutions proposées n'est probablement optimale, MAIS la solution 1 est IMPRÉVISIBLE et donc INCONTOURNABLE !

L'une des premières choses que vous apprenez lorsque vous traitez avec de grandes bases de données est que "la meilleure façon" d'effectuer une requête dépend souvent de facteurs (appelés métadonnées) au sein de la base de données :

  • Combien de lignes il y a.
  • Combien de tables vous interrogez.
  • La taille de chaque ligne.

Pour cette raison, il est peu probable qu'il y ait une solution miracle à votre problème. Votre base de données n'est pas la même que ma base de données, vous devrez comparer différentes optimisations si vous avez besoin des meilleures performances disponibles.

Vous constaterez probablement que appliquer et construire des index corrects (et comprendre l'implémentation native des index dans MySQL) dans votre base de données en fait beaucoup plus pour vous.

Il existe certaines règles d'or avec les requêtes qui doivent rarement être enfreintes :

  • Ne les faites pas dans des structures en boucle . Aussi tentant que cela soit souvent, la surcharge liée à la création d'une connexion, à l'exécution d'une requête et à l'obtention d'une réponse est élevée.
  • Évitez SELECT * sauf si nécessaire . La sélection de plus de colonnes augmentera considérablement la surcharge de vos opérations SQL.
  • Connaissez vos index . Utilisez le EXPLAIN afin que vous puissiez voir quels index sont utilisés, optimiser vos requêtes pour utiliser ce qui est disponible et en créer de nouveaux.

Pour cette raison, des deux, j'irais pour la deuxième requête (en remplaçant SELECT * avec seulement les colonnes que vous voulez), mais il existe probablement de meilleures façons de structurer la requête si vous avez le temps de l'optimiser.

Cependant, la vitesse ne devrait PAS soyez votre seule considération à cet égard, il y a une EXCELLENTE raison de ne pas utiliser la première suggestion :

PRÉVISIBILITÉ :pourquoi les verrous en lecture sont une bonne chose

L'une des autres réponses suggère que le verrouillage de la table pendant une longue période est une mauvaise chose et que, par conséquent, la solution à requêtes multiples est bonne.

Je dirais que cela ne pourrait pas être plus éloigné de la vérité . En fait, je dirais que dans de nombreux cas, la prévisibilité de l'exécution d'un seul verrouillage SELECT requête est un argument plus important POUR l'exécution de cette requête que les avantages d'optimisation et de rapidité.

Tout d'abord, lorsque nous exécutons un SELECT (lecture seule) sur une base de données MyISAM ou InnoDB (systèmes par défaut pour MySQL), ce qui se passe, c'est que la table est verrouillée en lecture. Cela empêche toute opération WRITE de se produire sur la table jusqu'à ce que le verrou de lecture soit abandonné (soit notre SELECT la requête se termine ou échoue). Autre SELECT les requêtes ne sont pas affectées, donc si vous exécutez une application multithread, elles continueront à fonctionner.

Ce retard est une BONNE chose. Pourquoi, me demanderez-vous ? Intégrité des données relationnelles.

Prenons un exemple :nous exécutons une opération pour obtenir une liste des éléments actuellement dans l'inventaire d'un groupe d'utilisateurs sur un jeu, nous faisons donc cette jointure :

SELECT * FROM `users` JOIN `items` ON `users`.`id`=`items`.`inventory_id` WHERE `users`.`logged_in` = 1;

Que se passe-t-il si, lors de cette opération de requête, un utilisateur échange un article avec un autre utilisateur ? En utilisant cette requête, nous voyons l'état du jeu tel qu'il était lorsque nous avons lancé la requête :l'élément existe une fois, dans l'inventaire de l'utilisateur qui l'avait avant que nous exécutions la requête.

Mais que se passe-t-il si nous l'exécutons en boucle ?

Selon que l'utilisateur l'a échangé avant ou après qu'on ait lu ses coordonnées, et dans quel ordre on lit l'inventaire des deux joueurs, il y a quatre possibilités :

  1. L'objet peut être affiché dans l'inventaire du premier utilisateur (scanner l'utilisateur B -> scanner l'utilisateur A -> article échangé OU scanner l'utilisateur B -> scanner l'utilisateur A -> article échangé).
  2. L'objet peut être affiché dans l'inventaire du second utilisateur (objet échangé > scanner l'utilisateur A -> scanner l'utilisateur B OU objet échangé -> scanner l'utilisateur B -> scanner l'utilisateur A).
  3. L'article pourrait être affiché dans les deux inventaires (scanner l'utilisateur A -> article échangé -> scanner l'utilisateur B).
  4. L'élément ne peut être affiché dans aucun des inventaires de l'utilisateur (scanner l'utilisateur B -> article échangé -> scanner l'utilisateur A).

Cela signifie que nous serions incapables de prédire les résultats de la requête ou d'assurer l'intégrité relationnelle .

Si vous prévoyez de donner 5 000 $ au gars avec l'ID d'article 1000000 à minuit mardi, j'espère que vous avez 10 000 $ en main. Si votre programme repose sur des éléments uniques qui sont uniques lors de la prise d'instantanés, vous déclencherez peut-être une exception avec ce type de requête.

Le verrouillage est bon car il augmente la prévisibilité et protège l'intégrité des résultats.

Remarque :Vous pouvez forcer une boucle à se verrouiller avec une transaction , mais ça va toujours être plus lent.

Oh, et enfin, UTILISEZ DES DÉCLARATIONS PRÉPARÉES !

Vous ne devriez jamais avoir une déclaration qui ressemble à ceci :

mysqli_query("SELECT * FROM Table2 WHERE ColumnAId=" . $row['ColumnAId'], $con);

mysqli a prise en charge des instructions préparées . Lisez à leur sujet et utilisez-les, ils vous aideront à éviter quelque chose de terrible n'arrive à votre base de données .