Question

Considérez la requête suivante:

SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;

Stamp colonne Transactions table est un TIMESTAMP et il y a un index sur elle. Comment pourrais-je changer cette requête afin qu'il évite des scans de table? (Qui est, en utilisant Stamp en dehors du jour () fonction)

Merci!

Était-ce utile?

La solution

Voici comment je le ferais:

ajouter quelques champs supplémentaires: année, mois, jour ou même heure, la minute en fonction du trafic que vous attendez. Ensuite, construire un déclencheur pour remplir les champs supplémentaires, peut-être en soustrayant l'intervalle de 3 heures à l'avance. Enfin construire un indice sur les champs supplémentaires.

Autres conseils

Si le but est juste d'éviter analyses complètes de table et vous avez une clé primaire (PK-dire le nom) pour les transactions, envisager d'ajouter l'indice couvrant

ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)

Ensuite

SELECT * FROM Transactions WHERE PK IN (SELECT PK FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1
 )

Cette requête ne doit pas utiliser analyses complètes de table (mais optimiseur peut décider d'utiliser l'analyse complète, si le nombre de lignes dans la table est petite ou pour toute autre raison statistique :))

Une meilleure façon peut-être est d'utiliser la table temporaire au lieu de sous-requête.

Vous pouvez souvent réécrire la fonction de sorte que vous avez quelque chose qui ressemble à WHERE Stamp=XXXX et XXXX est une expression. Vous pouvez créer une série de déclarations pour chaque ENTRE mois, WHERE Stamp BETWEEN timestamp('2010-01-01 00:00:00') AND timestamp ('2010-01-01 23:59:59') OR Stamp BETWEEN ..., mais je ne suis pas certain que ce serait utiliser l'index dans ce cas. Je construis une colonne qui était le jour du mois comme @petr suggère.

Calculer votre valeur souhaitée séparément avant Stamp exécuter votre requête principale, i.e..

Étape 1 - calculer la valeur souhaitée Stamp

Étape 2 - exécution d'une requête où Stamp> (valeur calculée)

Parce qu'il n'y a pas de calcul à l'étape 2, vous devriez être en mesure d'utiliser votre index.

Si je comprends bien, vous voulez essentiellement retourner toutes les lignes où le timbre tombe sur le premier de chaque mois (après avoir soustrait les 3 heures)? Si (ce qui est un grand si), vous avez une fenêtre fixe, par exemple les derniers 6 mois, vous pouvez simplement énumérer 6 tests de gamme. Mais encore, je ne suis pas sûr accès indexé sera plus rapide de toute façon.

select *
  from transactions
 where stamp between timestamp '2010-06-01 03:00:00' and timestamp '2010-06-02 02:59:59'
    or stamp between timestamp '2010-07-01 03:00:00' and timestamp '2010-07-02 02:59:59'
    or stamp between timestamp '2010-08-01 03:00:00' and timestamp '2010-08-02 02:59:59'
    or stamp between timestamp '2010-09-01 03:00:00' and timestamp '2010-09-02 02:59:59'
    or stamp between timestamp '2010-10-01 03:00:00' and timestamp '2010-10-02 02:59:59'
    or stamp between timestamp '2010-11-01 03:00:00' and timestamp '2010-11-02 02:59:59'
    or stamp between timestamp '2010-12-01 03:00:00' and timestamp '2010-12-02 02:59:59';

NB! Je ne sais pas comment la partie milliseconde de l'horodatage fonctionne. Vous devrez peut-être pad en conséquence.

Refonte de réponse petr un peu pour éviter la clause IN, et de le faire pour MyISAM ou InnoDB.

Pour MyISAM

ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)

Ou, pour InnoDB, où le PK est implicitement inclus dans chaque index,

ALTER TABLE Transactions ADD INDEX Stamp (Stamp)

Ensuite

SELECT * 
FROM Transactions LEFT JOIN
  (
  SELECT PK 
  FROM Transactions 
  WHERE DAYOFMONTH(Stamp - interval 3 hour) = 1
  ) a ON Transactions.PK=a.PK

La sous-requête aura un indice que l'exécution et la requête externe ne tirez les lignes de la table où a.PK est venu à travers.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top