2010-10-05 14 views
0

J'ai une requête php qui fonctionne assez souvent comme celui-ci:Avec cette requête typique, ces index sur ma table InnoDB sont-ils corrects ou devrais-je les changer?

$query = 'SELECT * FROM work_orders ' 
    .'WHERE '  
     . "((end_time >= ?" 
    . "AND start_time <= ?) " 
     . "OR (start_time <= ? " 
    . "AND end_time >= ?) " 
     . "OR (start_time >= ? " 
    . "AND end_time <= ?)) "; 

Et une table définie comme:

CREATE TABLE IF NOT EXISTS `work_orders` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `work_order_number` varchar(32) COLLATE latin1_general_ci NOT NULL, 
    `start_time` datetime NOT NULL, 
    `end_time` datetime NOT NULL, 
    `client_name` varchar(128) COLLATE latin1_general_ci NOT NULL, 
    `location` varchar(128) COLLATE latin1_general_ci NOT NULL, 
    `note` varchar(255) COLLATE latin1_general_ci DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `note_idx` (`note`), 
    KEY `client_idx` (`client_name`), 
    KEY `location_idx` (`location`), 
    KEY `start_time_idx` (`start_time`), 
    KEY `end_time_idx` (`end_time`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=1 ; 

Je suis souvent confus par la façon dont je créer des index. Ceci est une table de lecture lourde avec beaucoup de recherche sur les données, ce qui explique pourquoi chaque colonne est indexée, mais de loin la requête utilise le plus souvent les 3 combinaisons de dates de début et de fin pour déterminer si un ordre de travail tombe plage de calendrier. Dois-je avoir un index sur start_time et end_time individuellement, comme je le fais actuellement, ou devrais-je créer une clé composite sur les deux? Y a-t-il une meilleure façon de configurer les index en général? Devrais-je même utiliser InnoDB? Je n'utilise pas de transactions du tout.

Répondre

0

Cette réponse est double. Tout d'abord, je fais l'index comme:

KEY start_time_idx (start_time, end_time)

MAIS (et c'est la deuxième question): Vous requête ne pourrez utiliser l'un des indices. Voici pourquoi:

SELECT * 
FROM work_orders 
WHERE (
    (end_time >= <some-date> AND start_time <= <some-date>) 
    OR 
    (end_time >= <some-date> AND start_time <= <some-date>) 
    OR 
    (end_time >= <some-date> AND start_time <= <some-date>) 
) 

Dès que vous utilisez la déclaration OU, vous désactivez efficacement l'utilisation des index sur les champs impliqués dans la déclaration OU. Puisque votre instruction WHERE n'a aucun autre champ qui n'est pas impliqué dans l'instruction OR, aucun index ne sera utilisé.

Je vérifie que ceci est exécuté dans un script PHP. Avez-vous accès à phpMyAdmin? Ensuite, essayez d'exécuter cette requête préchargée par un EXPLAIN. Cela vous donnera quelques indices.

Si la table contient beaucoup de données, vous pouvez changer cette requête en 3 requêtes, chacune ne demandant qu'une seule plage de dates, puis concaténant le résultat en PHP par la suite.

/Carsten

+0

Intéressant, je ne savais pas que OU supprime effectivement l'utilisation d'index. Le problème est que je dois saisir un ordre de travail qui se termine, commence ou est entièrement contenu dans une plage de dates sélectionnée. Je pense que l'aller-retour, trois recherches distinctes, et le filtrage des doublons après le fait serait plus lent, n'est-ce pas? Cette requête est un exemple, car il y a parfois d'autres filtres, mais cette requête pourrait en théorie être appelée fréquemment. – ashurexm

+0

En ce qui concerne la vitesse: Cela dépend uniquement du nombre d'enregistrements dans votre tableau. Votre requête effectue une "analyse de table", c'est-à-dire une lecture en boucle de tous les enregistrements de la table. Si vous avez seulement quelques milliers d'enregistrements dans la table, vous ne devriez pas voir d'impact sur les performances. Si vous avez, disons 50 000 enregistrements ou plus, vous pourriez commencer à voir des problèmes de performance. –

+0

Si toutefois vous avez d'autres filtres qui sont AND'ed à ce qui précède, vous pouvez obtenir une recherche d'index sur l'un d'entre eux à la place. EXPLAIN est vraiment votre ami ici. http://mysql-tips.blogspot.com/2005/04/mysql-explain-example.html –