web-dev-qa-db-fra.com

MySQL: filtrer la colonne de date en utilisant LIKE ou MONTH?

J'ai une tâche CRON qui doit extraire les clients avec des anniversaires dans un mois donné, à partir d'une table MySQL InnoDB. Le champ anniversaire est indexé et de type DATE.

Filtrage pour avril, je peux interroger la table des clients soit par:

SELECT * 
FROM customers 
WHERE birthday LIKE "2015/04/%";

ou:

SELECT * 
FROM customers 
WHERE MONTH(birthday) = 4;

Lequel recommanderiez-vous et pourquoi?

4
doc_id

L'intérêt d'utiliser DATE comme type est pour que la base de données puisse interroger efficacement les données. C'est la même raison pour laquelle vous stockez un nombre sous la forme d'un INT et non d'un VARCHAR - afin que le moteur puisse prendre des décisions intelligentes. Si vous utilisez l'opérateur LIKE à une date, vous perdez les avantages d'avoir choisi type de données correct .

L'utilisation de MONTH(birthday) permet à MySQL de récupérer la partie mois de la colonne d'anniversaire dont il sait qu'elle respecte le format de données DATE. Lorsque vous utilisez LIKE, il fait une correspondance de modèle caractère par caractère, ce qui est beaucoup plus coûteux et plus lent à faire.

Si LIKE était suffisant, alors MONTH() n'existerait pas. Toute fonction intégrée va toujours être le choix sur LIKE pour une requête DATE.

10
LowlyDBA

J'irais pour:

SELECT * 
FROM customers 
WHERE MONTH(birthday) = 4;  

... car c'est la façon la plus courante de sélectionner par mois. L'utilisation de MONTH() appellera une fonction intégrée dans MySQL, mais si vous utilisez LIKE, elle le prendra comme caractère puis effectuera la comparaison, donc au lieu de faire une opération, MySQL en exécutera deux.

5
Ahmad Abuhasna

(Plus d'un tas de commentaires, plus une réponse redondante.)

  • Vos deux exemples ne sont pas identiques - l'un est limité à 2015; l'autre ne l'est pas.
  • WHERE birthday BETWEEN '2015-04-01' AND '2015-04-01' + INTERVAL 1 MONTH Pourrait utiliser INDEX(birthday), mais cela ne couvre que ceux qui vont naître le mois prochain.
  • Même si vous aviez une mnth TINYINT UNSIGNED COMMENT 'derived from MONTH(birthday), INDEX(mnth) n'est peut-être pas utilisée. En effet, un pourcentage "important" de la table est souhaité. L'optimiseur peut décider qu'une analyse de table est aussi rapide.
  • Donc, je suis d'accord avec les autres: WHERE MONTH(birthday) = 4 est probablement la "meilleure" réponse.
4
Rick James

J'ai testé pour 100.000 rangs

SELECT * FROM customers WHERE MONTH(birthday) = 4; ==> 18 secondes

SELECT * FROM customers WHERE birthday LIKE "2015/04/%"; ==> 21 secondes

1
agokeren