Je vous encourage à apprendre comment utiliser EXPLAIN
pour analyser le plan de la base de données pour l'optimisation des requêtes. Voir également la présentation EXPLAIN Demystified de Baron Schwartz (lien vers le PDF de ses diapositives sur cette page). Apprenez comment créer des index - ce n'est pas la même chose qu'une clé primaire ou une pseudokey auto-incrémentée. Voir la présentation More Mastering the Art of Indexing par Yoshinori Matsunobu. La table pourrait utiliser un index sur CP_FLAG
et WEB_STATUS
.
CREATE INDEX CW ON RAW_LAW_20100503 (CP_FLAG, WEB_STATUS);
Cela aide à rechercher le sous-ensemble de lignes en fonction de votre condition cp_flag.
Ensuite, vous rencontrez encore l'inefficacité malheureuse de MySQL avec GROUP BY
requêtes. Il copie un ensemble de résultats intermédiaire dans un fichier temporaire sur le disque et le trie ici. L'E/S disque a tendance à tuer les performances.
Vous pouvez augmenter votre paramètre de configuration sort_buffer_size
jusqu'à ce qu'il soit suffisamment grand pour que MySQL puisse trier le jeu de résultats en mémoire plutôt qu'en disque. Mais cela pourrait ne pas fonctionner.
Vous devrez peut-être recourir à un précalcul du COUNT()
dont vous avez besoin et mettre régulièrement à jour cette statistique.
Le commentaire de @Marcus m'a donné une autre idée. Vous regroupez par statut Web, et l'ensemble des valeurs distinctes de l'état Web est une liste assez courte et ils ne changent pas. Vous pouvez donc exécuter une requête distincte pour chaque valeur distincte et générer les résultats dont vous avez besoin beaucoup plus rapidement qu'en utilisant une requête GROUP BY
qui crée une table temporaire pour effectuer le tri. Ou vous pouvez exécuter une sous-requête pour chaque valeur d'état, et les UNION
ensemble:
(SELECT COUNT(*), WEB_STATUS FROM RAW_LOG_20100504 WHERE CP_FLAG > 0 AND WEB_STATUS = 200)
UNION
(SELECT COUNT(*), WEB_STATUS FROM RAW_LOG_20100504 WHERE CP_FLAG > 0 AND WEB_STATUS = 404)
UNION
(SELECT COUNT(*), WEB_STATUS FROM RAW_LOG_20100504 WHERE CP_FLAG > 0 AND WEB_STATUS = 304)
UNION
...etc...
ORDER BY 1 DESC;
Parce que votre indice couvrant comprend CP_FLAG
et WEB_STATUS
, ces requêtes ne doivent lire les lignes réelles dans le tableau. Ils lisent uniquement les entrées dans l'index, auxquelles ils peuvent accéder beaucoup plus rapidement car (a) ils sont dans un arbre trié, et (b) ils peuvent être mis en cache en mémoire si vous allouez suffisamment à votre key_buffer_size
.
Le rapport EXPLAIN
J'ai essayé (avec des lignes 1M de données de test) montre que celui-ci utilise les index bien, et ne crée pas une table temporaire:
+------+--------------+------------------+------+--------------------------+
| id | select_type | table | key | Extra |
+------+--------------+------------------+------+--------------------------+
| 1 | PRIMARY | RAW_LOG_20100504 | CW | Using where; Using index |
| 2 | UNION | RAW_LOG_20100504 | CW | Using where; Using index |
| 3 | UNION | RAW_LOG_20100504 | CW | Using where; Using index |
| NULL | UNION RESULT | <union1,2,3> | NULL | Using filesort |
+------+--------------+------------------+------+--------------------------+
Le Using filesort
pour la dernière ligne signifie simplement qu'il doit trier sans le bénéfice d'un index. Mais trier les trois lignes produites par les sous-requêtes est trivial et MySQL le fait en mémoire.
Lors de la conception de solutions de base de données optimales, il existe rarement des réponses simples. Beaucoup dépend de la façon dont vous utilisez les données et quel type de requêtes sont prioritaires pour accélérer. S'il y avait une seule réponse simple qui fonctionnait dans toutes les circonstances, le logiciel activerait simplement cette conception par défaut et vous n'auriez rien à faire.
Vous avez vraiment besoin de lire beaucoup de manuels, livres et blogs pour comprendre comment tirer le meilleur parti de toutes les fonctionnalités qui s'offrent à vous.
Oui, je recommanderais quand même d'utiliser des index. Clairement, il ne fonctionnait pas avant, lorsque vous interrogez 100 millions de lignes sans le bénéfice d'un index.
Vous devez comprendre que vous devez concevoir des index qui profitent à la requête spécifique que vous souhaitez exécuter. Je n'ai aucun moyen de savoir si l'index que vous venez de décrire dans votre commentaire est approprié, car vous n'avez pas montré l'autre requête que vous essayez d'accélérer.
L'indexation est un sujet complexe. Si vous définissez l'index sur les colonnes incorrectes ou si vous obtenez les colonnes dans le mauvais ordre, il peut ne pas être utilisable par une requête donnée. Je supporte les développeurs SQL depuis 1994, et je n'ai jamais trouvé une seule règle concise pour expliquer comment concevoir des index.
Vous semblez avoir besoin d'un mentor, parce que vous avez besoin de beaucoup de réponses à vos questions. Y a-t-il quelqu'un dans votre lieu de travail que vous pourriez demander pour vous aider?
Pourriez-vous nous fournir quelques exemples d'instructions de sélection que vous exécutez et qui semblent extrêmement lents? – NebuSoft
Avez-vous des index sur la table qui peuvent être utilisés par la clause WHERE? –
@ Nebusoft - Thnx pour la réponse select count (*), WEB_STATUS à partir de $ table_name où CP_FLAG> 0 grouper par 2 commander par 1 desc; @Martin: Thnx pour la réponse.Je ne sais pas comment mettre index sur cette table db car elle ne contient aucune clé unique. Avez-vous l'impression d'utiliser auto_increment pour m'aider? –