Comment créer un index sur la partie date du champ DATETIME dans MySql

comment créer un index sur la partie date du champ DATETIME?

mysql> SHOW COLUMNS FROM transactionlist;
+-------------------+------------------+------+-----+---------+----------------+
| Field             | Type             | Null | Key | Default | Extra          |
+-------------------+------------------+------+-----+---------+----------------+
| TransactionNumber | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| WagerId           | int(11)          | YES  | MUL | 0       |                |
| TranNum           | int(11)          | YES  | MUL | 0       |                |
| TranDateTime      | datetime         | NO   |     | NULL    |                |
| Amount            | double           | YES  |     | 0       |                |
| Action            | smallint(6)      | YES  |     | 0       |                |
| Uid               | int(11)          | YES  |     | 1       |                |
| AuthId            | int(11)          | YES  |     | 1       |                |
+-------------------+------------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)

TranDateTime est utilisé pour enregistrer la date et l'heure de la transaction, comme il arrive

ma Table a plus de 1.000.000 d'enregistrements dans elle et la déclaration

SELECT * FROM transactionlist where date(TranDateTime) = '2008-08-17' 

prend beaucoup de temps.

EDIT:

Regardez ce billet de blog sur " pourquoi le DATETIME de MySQL peut et doit être évitée "

57
demandé sur fancyPants 2008-09-18 22:15:25

13 réponses

si je me souviens bien, cela lancera un scan de table entier parce que vous passez la colonne à travers une fonction. MySQL exécutera obédiemment la fonction pour chaque colonne, en contournant l'index puisque l'optimiseur de requête ne peut pas vraiment connaître les résultats de la fonction.

Ce que je voudrais faire est quelque chose comme:

SELECT * FROM transactionlist 
WHERE TranDateTime BETWEEN '2008-08-17 00:00:00' AND '2008-08-18 23:59:59';

Qui devrait vous donner tout ce qui est arrivé sur 2008-08-17, et tout ce qui s'est passé exactement 2008-08-18 00: 00: 00. Si c'est un problème, vous pouvez modifier le deuxième terme de "2008-08-17 23:59:59' et juste obtenir 2008-08-17.

52
répondu Michael Johnson 2016-02-09 21:59:48

Je ne veux pas paraître mignon, mais une façon simple serait d'ajouter une nouvelle colonne qui ne contenait que la partie date et l'index.

9
répondu Mike Tunnicliffe 2008-09-18 18:22:34

vous ne pouvez pas créer un index uniquement sur la partie date. Est-il une raison pour laquelle vous avez?

même si vous pouviez créer un index uniquement sur la partie date, l'optimiseur ne l'utiliserait probablement pas pour la requête ci-dessus.

je pense que vous trouverez que

SELECT * FROM transactionlist WHERE TranDateTime BETWEEN '2008-08-17' AND '2008-08-18'

Est efficace et fait ce que vous voulez.

8
répondu MarkR 2008-09-18 19:03:18

une autre option (pertinente pour ver 7.5.3 et plus) est de créer une colonne générée/virtuelle basée sur la colonne datetime, puis de l'indexer.

CREATE TABLE `table` (
`my_datetime` datetime NOT NULL,
`my_date` varchar(12) GENERATED ALWAYS AS (DATE(`my_daetime`)) STORED,
KEY `my_idx` (`my_date`)
) ENGINE=InnoDB;
5
répondu Liran Brimer 2017-06-14 15:13:59

Je ne sais pas les spécificités de mySql, mais quel mal y a-t-il à indexer le champ date dans son intégralité?

alors il suffit de rechercher:

 select * from translist 
     where TranDateTime > '2008-08-16 23:59:59'
        and TranDateTime < '2008-08-18 00:00:00'

si les indices sont des arbres b ou quelque chose d'autre qui est raisonnable, ceux-ci devraient être trouvés rapidement.

3
répondu Clinton Pierce 2008-09-18 18:21:23

Valeriy Kravchuk sur une demande de fonctionnalité pour ce même problème sur le site MySQL dit d'utiliser cette méthode.

" dans l'intervalle, vous pouvez utiliser des colonnes de caractères pour stocker des valeurs DATETIME comme chaînes, avec seulement les premiers N caractères étant indexés. Avec une utilisation prudente des déclencheurs dans MySQL 5, vous pouvez créer une solution raisonnablement robuste basée sur cette idée."

vous pourriez écrire une routine assez facile à ajouter cette colonne, et puis avec des déclencheurs garder cette colonne synchronisés. L'index sur cette colonne devrait être assez rapide.

2
répondu Ray Jenkins 2008-09-18 18:25:19

la seule et bonne solution qui fonctionne assez bien est d'utiliser timestamp comme temps, plutôt que datetime. Il est stocké comme INT et être indexé assez bon. Personnellement j'ai rencontré un tel problème sur la table des transactions, qui a environ millions d'enregistrements et ralenti dur, enfin j'ai souligné que cela causé par mauvais champ indexé (datetime). Maintenant, il fonctionne très rapide.

2
répondu Valentin Rusk 2012-02-27 16:16:01

datetime COMME quelque chose d'% ne sera pas attraper l'index.

utilisez ceci: où datetime_field >= cudate();

Qui va attraper l'indice,

et couvrir aujourd'hui:00:00:00 jusqu'à aujourd'hui:23:59:59

Faire.

1
répondu Dr. Tyrell 2014-10-17 04:19:25

que dit "expliquer"? (run EXPLAIN SELECT * FROM transactionlist where date (TranDateTime) = '2008-08-17')

S'il n'utilise pas votre index à cause de la fonction date (), une requête de portée devrait s'exécuter rapidement:

sélectionnez * dans la liste des transactions où TranDateTime > = '2008-08-17' et TranDateTime < '2008-08-18'

0
répondu nathan 2008-09-18 18:20:52

plutôt que de faire un index basé sur une fonction (si cela est même possible dans mysql) faites votre clause où faire une comparaison de gamme. Quelque chose comme:

Où TranDateTime > '2008-08-17 00:00:00', et TranDateTime < '2008-08-17 11:59:59')

cela permet à la DB d'utiliser L'index sur TranDateTime (il y en a un, non?) pour la sélectionner.

0
répondu Justsalt 2008-09-18 18:24:27

créez de nouveaux champs avec juste les dates convert(datetime, left(date_field,10)) et ensuite indexez-les.

0
répondu Mari 2012-11-15 03:19:34

Je ne sais pas les spécificités de mySQL, mais quel mal y a-t-il à indexer le champ date dans son intégralité?

Si vous utilisez fonctionnelle de magie pour les * * * les arbres, des hachages ... est parti, parce que pour obtenir des valeurs vous devez appeler la fonction. Mais, parce que vous ne connaissez pas les résultats à l'avance, vous aurez à effectuer un balayage complet de la table.

Il n'y a rien à ajouter.

peut-être voulez-vous dire quelque chose comme calculé (calculé?) index... mais à ce jour, Je ne l'ai vu qu'au Cachéintersystèmes. Je ne pense pas qu'il y ait un cas dans les bases de données relationnelles (AFAIK).

une bonne solution, à mon avis, est la suivante (exemple clintp mis à jour):

SELECT * FROM translist 
WHERE TranDateTime >= '2008-08-17 00:00:00.0000'
  AND TranDateTime < '2008-08-18 00:00:00.0000'

que vous utilisiez 00:00:00.0000 ou 00:00 à mon avis ne fait aucune différence (je l'ai généralement utilisé dans ce format).

0
répondu antonia007 2012-12-28 01:13:11

pourquoi personne n'a suggéré D'utiliser comme ça? N'est-ce pas faire le travail aussi bien? Il sera aussi rapide qu'ENTRE les deux?

SELECT * FROM transactionlist where TranDateTime LIKE '2008-08-17%'
-2
répondu Nitro Chummy 2014-06-24 00:23:40