2010-05-04 6 views
3

J'exécute des requêtes sql sur une table mysql db qui a 110Mn + enregistrements uniques pour toute la journée. Problème: Chaque fois que j'exécute une requête avec la clause "where", cela prend au moins 30-40 minutes. Puisque je veux générer la plupart des données le jour suivant, j'ai besoin d'accéder à la table db entière.l'interrogation de l'énorme table de base de données prend trop de temps dans mysql

Pourriez-vous me guider pour optimiser/restructurer le modèle de déploiement?

Description du site:

 
mysql Ver 14.12 Distrib 5.0.24, for pc-linux-gnu (i686) using readline 5.0 
4 GB RAM, 
Dual Core dual CPU 3GHz 
RHEL 3 

contenu my.cnf:

 
[mysqld] 
datadir=/data/mysql/data/ 
socket=/tmp/mysql.sock 

sort_buffer_size = 2000000 
table_cache = 1024 
key_buffer = 128M 
myisam_sort_buffer_size = 64M 

# Default to using old password format for compatibility with mysql 3.x 
# clients (those using the mysqlclient10 compatibility package). 
old_passwords=1 

[mysql.server] 
user=mysql 
basedir=/data/mysql/data/ 

[mysqld_safe] 
err-log=/data/mysql/data/mysqld.log 
pid-file=/data/mysql/data/mysqld.pid 
[[email protected] root]# 

détails de table DB:

CREATE TABLE `RAW_LOG_20100504` (
    `DT` date default NULL, 
    `GATEWAY` varchar(15) default NULL, 
    `USER` bigint(12) default NULL, 
    `CACHE` varchar(12) default NULL, 
    `TIMESTAMP` varchar(30) default NULL, 
    `URL` varchar(60) default NULL, 
    `VERSION` varchar(6) default NULL, 
    `PROTOCOL` varchar(6) default NULL, 
    `WEB_STATUS` int(5) default NULL, 
    `BYTES_RETURNED` int(10) default NULL, 
    `RTT` int(5) default NULL, 
    `UA` varchar(100) default NULL, 
    `REQ_SIZE` int(6) default NULL, 
    `CONTENT_TYPE` varchar(50) default NULL, 
    `CUST_TYPE` int(1) default NULL, 
    `DEL_STATUS_DEVICE` int(1) default NULL, 
    `IP` varchar(16) default NULL, 
    `CP_FLAG` int(1) default NULL, 
    `USER_LOCATE` bigint(15) default NULL 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=200000000; 

Merci à l'avance! Observe,

+4

Pourriez-vous nous fournir quelques exemples d'instructions de sélection que vous exécutez et qui semblent extrêmement lents? – NebuSoft

+3

Avez-vous des index sur la table qui peuvent être utilisés par la clause WHERE? –

+0

@ 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? –

Répondre

2

Ajoutez un index à n'importe quel champ qui est dans votre clause where. Les clés primaires doivent être uniques. Les index uniques doivent être uniques, mais l'unicité n'est pas une condition préalable à un index.

index mal définis ou inexistants sont l'une des principales raisons de la mauvaise performance, et la fixation de ceux-ci peuvent souvent conduire à des améliorations phénoménales

Informations rapides:

+0

@Frank: Merci pour la réponse. Pensez-vous que le changement de moteur db de myisam à innodb aiderait? La raison derrière le moteur myisam était de prendre en charge les enregistrements 100Mn + dans une seule table db. Je préférerais exécuter plus d'une requête simultanée sur la même table sans impact sur les autres requêtes en cours. –

+0

Je ne suis pas entièrement sûr de changer le moteur. J'utilise MyISAM moi-même, mais je n'ai pas de tables dans une base de données MySql, même près de la taille que vous avez. Donc, je ne suis pas la meilleure personne pour répondre à une telle question ... Cela dit, je suis sûr que vous verriez une amélioration en ajoutant simplement quelques index ... –

+0

@Bill: Merci pour la réponse. Pourriez-vous s'il vous plaît élaborer la déclaration suivante "Vous pourriez avoir à recourir à précalculer le COUNT() dont vous avez besoin, et mettre à jour cette statistique périodiquement." Pendant que j'ajoute des index à la table, pourriez-vous jeter un peu de lumière sur la configuration qui sont présents dans my.cnf? Est-ce suffisant ou quoi que ce soit qui manque? @Frank: Merci pour la réponse. Je suis la réponse de Bill et l'ajout d'index pour voir la magie sur la sortie finale. Un commentaire spécifique avec la configuration my.cnf? –

9

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?

+0

@Bill, COUNT (*) utilise-t-il l'indice de couverture? –

+0

@ Bill: Désolé pour ça. Je me suis perdu à cause de nombreuses options "Ajouter un commentaire". J'ai essayé d'utiliser ' CREATE INDEX USER sur RAW_LOG_20100503 (MSISDN, BYTES_RETURNED, REQ_SIZE); ' mais même après 41614 secondes, il n'est pas terminé. J'ai dû abandonner la requête en utilisant "ctrl + c" Me recommanderiez-vous encore l'utilisation de l'index? Il semble que les index sur 100Mn + ne donnent pas les meilleures performances. Encore une chose, c'est-à-dire que j'utiliserais une nouvelle table tous les jours. Comment l'indexation fonctionnera-t-elle dans cette situation? –

+0

@ Bill: Je comprends qu'il n'y aura pas "une solution qui convient à tous" approche. Mais je veux comprendre comment nous pouvons optimiser mysql dans mon cas. Par conséquent, demandez vos points de vue/commentaires précieux qui m'aideront à améliorer les performances de mysql db. –

Questions connexes