2010-10-08 5 views
4

Je me suis retrouvé dans une situation difficile. J'ai une table utilisée pour la page hit suivi avec près de 105 millions de lignes Il ressemble à ceci. (!):MySQL: table d'indexation avec 100+ millions de rangées

CREATE TABLE `media_hits` (
    `id` int(10) unsigned NOT NULL auto_increment, 
    `media_code` char(7) NOT NULL, 
    `day` date NOT NULL, 
    `hits` int(10) unsigned NOT NULL default '0', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `media_code` (`media_code`,`day`) 
) ENGINE=InnoDB; 

Comme vous pouvez imaginer courir tout type de requête sur cette table prend beaucoup de temps. Une requête type serait la suivante:

SELECT DISTINCT(`media_code`), COUNT(*) AS c 
FROM `media_hits` 
WHERE `day` >= DATE_SUB(NOW(), INTERVAL 1 DAY) 
GROUP BY(`media_code`) 
ORDER BY c DESC 
LIMIT 200; 

Cette requête prend une éternité. Et EXPLAIN sur la requête me donne ceci:

  id: 1 
    select_type: SIMPLE 
     table: media_hits 
     type: index 
possible_keys: NULL 
      key: media_code 
     key_len: 10 
      ref: NULL 
     rows: 104773158 
     Extra: Using where; Using index; Using temporary; Using filesort 

C'est tout simplement horrible. Donc ma question est: Que puis-je faire à ce sujet? Essayer d'ajouter des index appropriés maintenant est impossible. La requête ALTER TABLE prendrait probablement plus d'une semaine pour s'exécuter. J'ai essayé de supprimer des lignes de plus de 6 mois, mais 24 heures plus tard, cette requête était toujours en cours d'exécution.

J'ai besoin de résoudre ce problème. La seule chose qui me vient à l'esprit est de créer une nouvelle table avec des index appropriés et de commencer à enregistrer les hits dans cette table. En arrière-plan, je pourrais avoir un script insérant lentement des enregistrements de l'ancienne table media_hits. Quelqu'un peut-il offrir des suggestions sur la façon d'indexer cette table, et éventuellement quelques indications sur les colonnes que je devrais indexer?

Répondre

2

Pour ce genre de travail, l'indexation sera très probablement seul ne vous aidera pas beaucoup. Mieux vaut penser à une sorte de stratégie de mise en cache avec des tableaux supplémentaires stockant les agrégats dont vous avez besoin.

Par exemple, pour votre requête ci-dessus, vous pouvez ajouter une deuxième table « media_code_per_day » contenant 3 colonnes « media_code », « contre » et « date ». Chaque fois que vous insérez une ligne dans votre table d'origine, mettez également à jour "media_code_per_day" en conséquence. Ensuite, vous pouvez lancer une nouvelle requête sur "media_code_per_day" au lieu de votre requête d'origine.

Bien sûr, pour initialiser votre nouvelle table dans votre situation, vous devrez faire une course par lots en passant par toutes vos lignes existantes une fois, mais cela est nécessaire qu'une seule fois.

+0

Je suis d'accord qu'un nouveau système est nécessaire, et les tableaux agrégés aideraient énormément. Je suppose que le vrai problème est d'importer les anciennes données d'une manière qui ne prend pas des semaines. haha Si c'est ce qu'il faut, alors c'est ce qu'il faut, mais ce serait bien s'il y avait une approche plus simple. – mellowsoon

2

Pour cette requête spécifique, un index (jour, media_code) aiderait le plus. Il faudra toujours utiliser une table temporaire, à cause du groupe par, et faire des fichiers, parce que vous commandez par nombre (*), mais cet index réduira le nombre de lignes qu'il doit analyser de manière significative.

Si vous avez besoin de meilleures performances que cela, alors vous aurez probablement à faire comme @DocBrown dit et faire des tableaux agrégés. Mais je voudrais d'abord essayer l'index pour voir si cela aide assez, avant d'aller à tout le travail des tables supplémentaires.

Vous pouvez également ajouter une limite à une requête de suppression, si vous voulez nettoyer lentement les anciennes lignes sans avoir à exécuter un grand effacement qui prend des jours. Vous pouvez les supprimer par lots (comme des lignes 10K ou 100K à la fois) pour réduire lentement la taille de cette table jusqu'à ce qu'elle soit suffisamment petite pour ajouter l'index.

0

Vous pouvez également jeter un oeil à l'édition de la communauté vertica. où quelque chose de simple comme

SELECT count(*) FROM event_track; 
    count  
------------ 
1595756573 
(1 row) 

revient en 6 secondes sur un système où la requête n'a pas été soumise récemment. Oui c'est près de 1,6 milliard de lignes, et je fais des requêtes comme celle que vous avez mentionné plus haut tout le temps dans un temps de réponse très raisonnable (souvent des secondes, moins souvent des minutes).La bonne chose est que, après avoir jeté vos données en direct de mysql dans un énorme fichier csv, il est rapide et facile de l'importer dans Vertica avec une seule commande COPY FROM.

https://dba.stackexchange.com/a/35614/20451 a des détails sur où télécharger vertica.

Questions connexes