2013-04-17 1 views
2

J'ai une table avec des millions de lignes, dont une colonne DATE et une colonne TIME.Dans MySQL, puis-je créer un index sur une fonction TIMESTAMP?

La modification de la structure de la table n'est pas une option, bien que l'ajout d'un nouvel index soit possible.

Compte tenu de cette requête:

SELECT * FROM Table WHERE TIMESTAMP(Date, Time) BETWEEN 'X' AND 'Y'; 

Je index sur les colonnes date et heure, également un index sur les colonnes date et heure, mais lorsque j'utilise la fonction TIMESTAMP, la requête utilise aucun index.

La question est, puis-je faire un index qui utilise la fonction TIMESTAMP (pas le type de données). Si non, y a-t-il un moyen de changer la requête ci-dessus pour utiliser les index? J'essaie de garder la requête agréable et courte, et d'essayer d'éviter d'itérer sur chaque date si possible.

EDIT:

Ainsi, depuis MySQL ne supporte pas les indices d'expression, est-il un moyen que je peux changer cette requête pour utiliser la date ou l'index (date, heure)?

+0

Etes-vous autorisé à faire l'inverse (convertir les horodatages constants en combinaisons (date, heure)? WHERE (Date, Heure)> = (Xdate, Xtime) ET (Date, Heure) <= (Ydate, Ytime) ' –

+0

@ypercube, en ce qui concerne la recherche d'index, je ne pense pas que cette expression a un quelconque avantage par rapport à l'exemple' Date BETWEEN' que j'ai donné –

Répondre

4

Ceci est appelé index d'expression, mais toutes les marques de SGBDR ne prennent pas cela en charge.

Vous ne pouvez pas faire cela dans MySQL.

Le plus proche est persistent virtual columns, qui est pris en charge dans un fork de MySQL appelé MariaDB. Mais si vous ne pouvez pas changer votre schéma, je suppose que passer à un autre paquet RDBMS est également hors de question.

PostgreSQL est un exemple de SGBDR qui est does support expression indexes.


Pour contourner ce problème, je vous recommande juste un filtrage sur votre colonne Date, qui devrait restreindre la recherche de manière significative si vous avez un index sur cette colonne.

SELECT * FROM Table WHERE Date BETWEEN 'Xdate' AND 'Ydate' 
    AND CASE WHEN Date = 'Xdate' THEN TIMESTAMP(Date, Time) >= 'X' 
      WHEN Date = 'Ydate' THEN TIMESTAMP(Date, Time) <= 'Y' 
      ELSE 1 END; 

alors l'expression TIMESTAMP() ne doit être évaluée sur un sous-ensemble de vos données, au lieu de chaque ligne de la table. Dans l'exemple ci-dessus, il ne sera possible d'évaluer TIMESTAMP() que si la date correspond au début ou à la fin de la plage de dates. Cela peut être utile si la plage de dates entre Xdate et Ydate est très longue et correspond à beaucoup de lignes. Il n'est pas nécessaire d'exécuter cette fonction pour toutes les dates intermédiaires.

Je n'ai pas testé l'expression ci-dessus, donc mes excuses si je suis parti par un ou quelque chose, je pense que vous devriez avoir l'idée cependant.

+0

Voici les pauses: < –

+0

Aha! Brilliant, cela a beaucoup accéléré la requête Merci :) 2 minutes jusqu'à ce que je puisse accepter la réponse. –

+0

Quelle est l'implication de ELSE 1 dans l'énoncé de cas? –

2

Ma suggestion est de réécrire la requête inverser la fonction est de produire les dates et heures de X et Y horodatages seulement:

SELECT * 
FROM Table 
WHERE (Date, Time) >= ('Xdate', 'Xtime') 
    AND (Date, Time) <= ('Ydate', 'Ytime') ; 

Comme l'a expliqué @BillKarwin dans un commentaire, qui ne bénéficieront pas de Un index.Ainsi donc réécrire si l'indice (Date, Time) peut être utilisé:

SELECT * 
FROM Table 
WHERE 'Xdate' = 'Ydate' 
      AND Date = 'Xdate' AND Time >= 'Xtime' AND Time <= 'Ytime' 
    OR 'Xdate' < 'Ydate' 
      AND (Date = 'Xdate' AND Time >= 'Xtime' 
      OR Date > 'Xdate' AND Date < 'Ydate' 
      OR Date = 'Ydate' AND Time <= 'Ytime' 
      ) ; 

De cette façon, aucun appel du tout sur la fonction TIMESTAMP() sera nécessaire.

+0

Est-ce que la déclaration ci-dessus prend en compte les temps qui dépassent minuit? À première vue, il semblerait que ce n'est pas le cas? –

+0

Oui, c'est le cas. Que voulez-vous dire avec des temps au-dessus de minuit? Les temps vont généralement de 00: 00: 00 à 22: 59.59. Laissez-vous des temps négatifs ou plus de 24: 00: 00 à cette colonne? –

+0

Désolé, me suis confondu avec l'autre déclaration que j'écris, qui ne couvre pas les 24 heures complètes. Cette requête fonctionnerait aussi, merci! +1 –