web-dev-qa-db-fra.com

"Créer un index unique" sur une grande table en prenant trop de temps

J'essaie de restaurer les décharges de la base de données du Ghtorrent (fichiers CSV contenant GitHub Metadata). La table commits a plus de 891 millions de lignes et le project_commits a plus de 5,4 milliards de lignes. Puisque ces tables sont assez grandes, je devais les charger à l'aide de LOAD DATA INFILE avec une vérification de la clé étrangère. J'utilise le moteur MyISAM. Après avoir terminé les enregistrements d'importation dans les tables, j'essaie de créer des index pour ces tables.

J'exécute la commande mysql suivante pour la table commits et il n'a pas fini de plus de 12 heures.

CREATE UNIQUE INDEX `sha` ON `ghtorrent_restore`.`commits` (`sha` ASC)  COMMENT '';

La table commettre ressemble ci-dessous:

enter image description here

J'ai lu d'autres questions Stackexchange sur l'indexation lente et définir ce qui suit dans my.cnf Fichier dans /etc/mysql répertoire.

[mysqld]
bulk_insert_buffer_size=1G
myisam_sort_buffer_size=8G
key_buffer_size=6G
sort_buffer_size=10M

Étant donné que la commande précédente ne finissait pas à temps, je devais l'arrêter avec Ctrl + Z de la console. J'ai vérifié la table sur MySQL Workbench, il ne figure pas comme corrompu, mais cela montre une longueur d'index de 36 Go.

enter image description here

L'importation de ce tableau a pris environ 25 minutes, alors je m'attends à ce que l'indexation ne devrait pas prendre plus d'une heure, mais je suis maintenant à la commande "Créer un indice unique" pendant environ 2 heures sans aucun signe de progrès.

Quand j'exécute la commande, MySQLD prend beaucoup de processeur et cela continue de prendre la mémoire. Après avoir atteint quelque 6 Go, il devient moins actif et semble presque rien faire.

enter image description here

Voici comment la commande (sélectionnée sur la photo suivante) est à partir du Workbench MySQL.

enter image description here

Je cours mysql 5.7.22-0ubuntu0.16.04.1 sur une machine Linux Mint 17.03 avec 16 Go de RAM.

Comme je ne suis pas un utilisateur avancé, aucune aide sera d'une grande aide.

Mise à jour [comme Wilson H. suggéré]:

My.cnf Fichier [06/05/2018 01:06]

!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/

[mysqld]
secure-file-priv = ""

[mysqld]
bulk_insert_buffer_size=1G
myisam_sort_buffer_size=8G
key_buffer_size=6G
sort_buffer_size=10M

Voici des instantanés de tampon et cache lié variables.

buffer and cache related system variables

Je n'ai rien modifié d'autre dans mon installation MySQL. MySQLD prend une quantité de mémoire différente en fonction de différentes tables hors de la RAM totale de 16 Go disponible dans le système. Je n'exécute aucune application intensive de CPU/mémoire à côté de MySQL.

Observation intéressante: certains tests avec d'autres tables montrant une durée croissante en ce qui concerne le nombre croissant de lignes. La tendance a l'air polynomial.

Polynomial increase of time

Les statistiques suivantes ont été capturées alors que la dernière commande MySQL de la photo ci-dessus était en cours d'exécution (c'est-à-dire l'indexation de "projets" de table).

TOP:top

iostat -x:iostat -x

Ulimit -A:

ulimit -a

DF -H:

df -h

Mettre à jour 2 : Etant donné que la création d'index sur la table "commettre" ne finissait pas, j'essayais d'autres tables et j'ai finalement tenté d'indexer sur la table "Project_Commits" avant de darder la nuit dernière. À ma grande surprise, j'ai trouvé que 18 minutes seulement pour terminer l'indexation.

enter image description here

Je n'ai pas fait de modification supplémentaire et je ne comprends pas pourquoi "commettre" la table n'est jamais terminée. Je connais à nouveau l'indexation sur la table des "commettre" et voyez jusqu'où il se passe.

Mise à jour 3 :

'Montrer Create Table commits;'

CREATE TABLE `commits` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sha` varchar(40) DEFAULT NULL,
  `author_id` int(11) DEFAULT NULL,
  `committer_id` int(11) DEFAULT NULL,
  `project_id` int(11) DEFAULT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `commits_ibfk_1` (`author_id`),
  KEY `commits_ibfk_2` (`committer_id`),
  KEY `commits_ibfk_3` (`project_id`)
) ENGINE=MyISAM AUTO_INCREMENT=922093754 DEFAULT CHARSET=utf8

Afficher la liste des processus :SHOW PROCESSLIST

Bottomline:

L'indexation pour toutes les tables est complétée à l'exception de la table 'commit' (c'est-à-dire la commande suivante n'est pas terminée en cours d'exécution).

CREATE UNIQUE INDEX `sha` ON `ghtorrent_restore`.`commits` (`sha` ASC)  COMMENT '';

Lorsque j'exécute une requête (voir la photo ci-dessous) qui compte environ 19 000 rangées de 891 millions de lignes, il faut environ 76 secondes. Est-ce que cette heure est trop élevée, je dispose d'un ordinateur avec Core i707700HQ CPU @,8 GHz x 4, 16 Go DDR4 RAM et la base de données sont installés sur le disque dur avec 7200RPM? Les 76 secondes indiquent-elles que l'indexation ne fonctionne pas correctement dans la table "commet" ? Veuillez noter que cette requête a été exécutée juste après avoir démarré l'ordinateur pour éviter les impacts des tampons.

enter image description here

4
Narnia_Optimus

Il y a plusieurs problèmes.

Auto_inc de 922m est à mi-chemin de la limite de 2 milliards de INT SIGNED. Suggérez que vous modifiez INT UNSIGNED (4 milliards limites) au cours de la prochaine ALTER.

Myisam enregistre l'espace disque, mais est aussi "pire" que InnoDB. Remarque: Changer à InnoDB nécessitera de modifier plusieurs paramètres.

FOREIGN KEYS Sont ignorés par Myisam.

Si sha est un hachage SHA-1, il est terrible pour l'indexation.

Si sha est un hachage SHA-1, il pourrait être comprimé à BINARY(20) via UNHEX(). Cela diminuerait la table de plus de 20 Go, 30% de la taille actuelle!

Si sha est un hachage SHA-1, n'utilisez pas UTF8; Utilisez ASCII ou LATIN1.

Si sha est un hachage SHA-1, et c'est la colonne que vous créez l'index UNIQUE ON, cochez SHOW PROCESSLIST. S'il est indiqué "Réparer par key_buffer", vous devriez le tuer; Il faudra mois pour terminer. Si cela indique "Réparer par trier", alors il y a de l'espoir qu'il finira.

Envisagez d'utiliser des identifiants plus petits que le 4 octet Int pour l'auteur, le committer et le projet - à moins que vous n'ayez vraiment pas beaucoup de valeurs distinctes. Attendre! Quelle? Chacun de ceux-ci va être UNIQUE? J'en doute.

Quel SELECTs avez-vous? Certains d'entre eux auraient pu nécessiter des indices "composites"?

Mettre plusieurs ALTERs (y compris la création d'index) dans une seule déclaration. Chaque ALTER est une copie complète de la table (dans Myisam).

myisam_sort_buffer_size = 8G Est la moitié de la RAM. C'est mauvais. Suggérez 3G.

polynôme

La tendance a l'air polynomial.

J'espère que vous n'ajoutez pas de UNIQUE INDEX Sur une colonne sur une table déjà a la même colonne que PRIMARY KEY . Ce serait totalement redondant. S'il vous plaît fournir SHOW CREATE TABLE Pour l'un d'entre eux.

Pourquoi "polynôme"? Si c'est (et je pose des questions telles), alors ce serait à cause de la nature de "réparation par clé_buffer":

Pour chaque ligne, recherchez la colonne de tous les index uniques (y compris primaires) pour vous assurer qu'il n'est pas un "duplicata". Cette recherche nécessite de récupérer le bloc de l'index du BTRee et de la mettre dans le "Key_Buffer" pour tester. En fonction de la "commande" de la clé, par rapport à "l'ordre" des données:

  • Pour auto_incrènement ou horodatage, où la rangée ont été insérées chronologiques (et la table n'était pas devenue fragmentée), le bloc suivant nécessaire est très probablement celui qui a été touché. C'est le plus efficace car il a besoin du moins d'E/S.
  • Pour SHA1/MD5/UUID/etc., cette recherche sautera tout autour de l'index. Donc, le bloc suivant nécessaire est de moins en moins susceptible d'être dans la clé Key_buffer in-RAM. À l'extrême, cela conduit à près de 1 disque en lecture par look!
  • Pour d'autres index, le timing est quelque part entre les deux.
3
Rick James
1
Evan Carroll