Comment le mauvais est à l'aide de SELECT MAX(id) dans MYSQL au lieu de mysql_insert_id() en PHP?
Contexte: je suis en train de travailler sur un système où les développeurs semblent être en utilisant une fonction qui exécute une requête MYSQL comme "SELECT MAX(id) AS id FROM TABLE"
quand ils ont besoin pour obtenir l'id de la DERNIÈRE ligne insérée (la table ayant une colonne de type auto_increment).
Je sais que c'est une pratique horrible (parce que les demandes simultanées mess les enregistrements), et je suis en train de le communiquer à la non-tech /équipe de gestion, qui leur réponse est...
"Oh okay, we'll only face this problem when we have (a) a lot of users, or (b) it'll only happen when two people try doing something at _exactly_ the same time"
Je ne suis pas en désaccord avec le point, et je pense que nous allons exécuter ce problème plus tôt que nous le plan. Cependant, je suis en train de calculer (ou la figure d'un mécanisme) pour calculer le nombre d'utilisateurs devraient être en utilisant le système avant de commencer à voir foiré liens.
Toute mathématique aperçu de qui? Encore une fois, je SAIS que c'est une pratique horrible, je veux juste comprendre les variables dans cette situation...
Mise à jour: Merci pour les commentaires des gens - nous allons dans la bonne direction et le code fixe!
OriginalL'auteur DrMHC | 2010-08-18
Vous devez vous connecter pour publier un commentaire.
Le point n'est pas si mauvaises situations sont susceptibles. Le point est que si elles sont possibles. Tant qu'il y aura un non-trivial de probabilité pour que le problème se produisant, s'il est connu, il doit être évité.
C'est pas comme si nous parlons de la modification d'une ligne d'un appel de fonction dans un 5000 ligne monstre à face avec une distance possible de cas de bord. Nous parlons en fait de raccourcissement de l'appel à une plus lisible, et plus d'une utilisation correcte.
J'ai un peu d'accord avec @Mark Baker qu'il est facteur de performance, mais depuis
id
est une clé primaire, laMAX
requête sera très rapide. Bien sûr, laLAST_INSERT_ID()
sera plus rapide (puisque c'est juste de la lecture d'une variable de session), mais seulement par une somme insignifiante.Et vous n'avez pas besoin de beaucoup d'utilisateurs. Tous vous avez besoin est un beaucoup de demandes simultanées (même pas tant que ça). Si le temps entre le commencer de l'insert et le début de la sélection est de 50 millisecondes (en supposant une opération sécuritaire du moteur DB), alors vous avez seulement besoin de 20 requêtes par seconde pour commencer à frapper un problème avec ce systématiquement. Le point est que la fenêtre d'erreur est non-trivial. Si vous dites 20 requêtes par seconde (ce qui dans la réalité n'est pas beaucoup), et en supposant que la personne moyenne des visites pages par minute, vous êtes seulement de parler de 1200 utilisateurs. Et c'est pour que ça arrive régulièrement. Il pourrait se produire une fois avec seulement 2 utilisateurs.
Et à droite de la Documentation de MySQL sur le sujet:
OriginalL'auteur ircmaxell
Au lieu d'utiliser
SELECT MAX(id)
vous devriez faire comme les la documentation dit :Même, ni
SELECT MAX(id)
nimysql_insert_id()
sont "thread-safe" et vous aurait condition de course. La meilleure option que vous avez est de verrouiller les tables avant et après votre demande. Ou encore mieux utiliser les transactions.Oui, c'mysql_insert_id() n'est pas une solution parfaite.
oh. qui a dit que vous?
Salut Colin - merci, je ne suis pas sûr que "mysql_insert_id() vs MySQL LAST_INSERT_ID ()", mais nous pouvons probablement le garder que pour un autre débat...
mysql_insert_id() est thread-safe, et sera de retour le dernier ID inséré pour la connexion en cours. Voir dev.mysql.com/doc/refman/5.0/en/mysql-insert-id.html
OriginalL'auteur Colin Hebert
Je n'ai pas les maths, mais je tiens à souligner que la réponse (a) est un peu idiot. N'est pas la société voulez un grand nombre d'utilisateurs? N'est-ce pas un objectif? Cette réponse implique qu'ils préfèrent résoudre le problème à deux reprises, éventuellement, à grands frais, la deuxième fois, au lieu de le résoudre une fois correctement la première fois.
franchement, un bon code doit être réécrite de toute façon.
Absolument pas en désaccord avec vous - juste essayer de trouver un moyen de calcul lorsqu'un conflit qui allait arriver... juste les bases mathématiques de sorte qu'il est plus clair pour tous...
Est-ce un client en face de produit? Fait de l'argent en dépendent? Si oui, alors le point où il arrive, c'est exactement égal au point à laquelle les clients de se mettre en colère et de l'argent est perdu. Si l'on est à éviter, puis l'autre. Honnêtement, je sympathise avec vous. J'ai travaillé pour des entreprises où, si l'équipe de vente ne demande pas un changement, nous ne pouvions pas le faire. Alors qu'ils avaient de se plaindre que le logiciel ne fonctionne pas bien et les clients sont en colère. Des temps sombres.
OriginalL'auteur David
Ce qui va se produire lorsque quelqu'un ajoute quelque chose à la table entre un insert et que la requête en cours d'exécution. Donc, pour répondre à votre question, deux personnes qui utilisent le système a le potentiel pour que les choses aillent mal.
Au moins à l'aide de la LAST_INSERT_ID() permet de récupérer le dernier ID pour une ressource particulière, de sorte qu'il n'a pas d'importance combien de nouvelles entrées ont été ajoutées entre les deux.
OriginalL'auteur gabe3886
En plus le risque de contracter la mauvaise ID valeur renvoyée, il y a également une requête de base de données surcharge de SELECT MAX(id), et c'est plus le code PHP à l'exécution qu'un simple mysql_insert_id(). Pourquoi délibérément le code quelque chose pour être lent?
OriginalL'auteur Mark Baker