web-dev-qa-db-fra.com

MySQL - combien de temps pour créer un index?

Quelqu'un peut-il me dire comment ajouter une clé à MySQL? J'ai 500 000 000 lignes dans une base de données, trans, avec les colonnes i (INT UNSIGNED), j (INT UNSIGNED), nu (DOUBLE), A (DOUBLE). J'essaie d'indexer une colonne, par exemple.

ALTER TABLE trans ADD KEY idx_A (A);

et j'attends. Pour une table de 14 000 000 de lignes, l’exécution sur mon MacBook Pro a pris environ 2 minutes, mais pour un demi-milliard, cela prend 15 heures et plus. Est-ce que je fais quelque chose de mal ou est-ce que je suis juste naïf sur la façon dont l'indexation d'une base de données évolue avec le nombre de lignes?

34
xnx

Il y a deux facteurs à prendre en compte:

  • Le tri est une opération N.log (N).
  • Le tri de 14 millions de lignes pourrait bien s’intégrer dans la mémoire principale; le tri avec 500 millions de lignes ne le fait probablement pas, alors le tri déborde sur le disque, ce qui ralentit énormément les choses.

Le facteur ayant une taille d'environ 30, le temps de tri nominal de l'ensemble de données volumineuses serait de l'ordre de 50 fois supérieur - moins de deux heures. Cependant, vous avez besoin de 8 octets par valeur de données et de 8 octets supplémentaires de temps système (c'est une hypothèse: réglez mySQL si vous en savez plus sur ce qu'il stocke dans un index). Ainsi, 14M × 16 × 220 Mo de mémoire principale. Mais 500M × 16 ≈ 8 Go de mémoire principale. À moins que votre machine ne dispose de suffisamment de mémoire (et que MySQL soit configuré pour l'utiliser), le gros problème se répercute sur le disque, ce qui représente une bonne partie du temps restant.

32
Jonathan Leffler

Premièrement, la définition de votre table pourrait faire une grande différence ici. Si vous n'avez pas besoin de valeurs NULL dans vos colonnes, définissez-les NOT NULL. Cela permettra d'économiser de l'espace dans l'index et probablement du temps lors de sa création.

CREATE TABLE x ( 
  i INTEGER UNSIGNED NOT NULL, 
  j INTEGER UNSIGNED NOT NULL, 
  nu DOUBLE NOT NULL, 
  A DOUBLE NOT NULL 
);

En ce qui concerne le temps nécessaire pour créer les index, cela nécessite une analyse de table et s'affichera sous la forme REPAIR BY SORTING. Dans votre cas, il devrait être plus rapide (c’est-à-dire un ensemble de données volumineux) de créer une nouvelle table avec les index requis et d’y insérer les données, car cela évitera l’opération REPAIR BY SORTING car les index sont construits séquentiellement sur l’insertion. Il existe un concept similaire expliqué dans cet article .

CREATE DATABASE trans_clone;
CREATE TABLE trans_clone.trans LIKE originalDB.trans;
ALTER TABLE trans_clone.trans ADD KEY idx_A (A);

Ensuite, écrivez l’insertion dans des morceaux (conformément à l’article) ou exportez les données à l’aide de MYSQLDUMP:

mysqldump originalDB trans  --extended-insert --skip-add-drop-table --no-create-db --no-create-info > originalDB .trans.sql
mysql trans_clone < originalDB .trans.sql

Cela insérera les données, mais ne nécessitera pas de reconstruction d'index (l'index est construit au fur et à mesure que chaque ligne est insérée) et devrait se terminer beaucoup plus rapidement. 

5
Andy

D'après mon expérience: si le matériel le permet, l'indexation de grandes tables avec MySQL est généralement assez linéaire. Je l'ai essayé avec des tables d'environ 100 000 000 lignes jusqu'à présent, mais pas sur un ordinateur portable - principalement sur des serveurs puissants.

Je suppose que cela dépend principalement de facteurs matériels, du type de moteur de table que vous utilisez (MyIsam, INNO ou autre) et d'un peu si la table est utilisée entre les deux. Lorsque je le faisais, l’utilisation du disque montait en flèche, contrairement à l’utilisation du processeur. Pas sûr des disques durs du MacBook, mais je suppose qu'ils ne sont pas les plus rapides du marché.

Si vous utilisez des tables MyISAM, examinez peut-être de plus près les fichiers d'index du répertoire table et voyez comment ils évoluent au fil du temps.

2
Bjoern

Donc, théoriquement, si l'étape de tri est une opération N.log (N), partitionner votre grande table permettrait de gagner du temps sur l'opération 

Environ 30% de gain pour une table de 500 000 000 lignes partitionnées en 100 fichiers égaux: car 500 000 000 * log (500 000 000) = 4 349 485 002 Et 100 * (500 000 000/100 * LOG (500 000 000/100)) = 3 349 485 002

0
Laurent PELE