Mysql: créer un index sur 1,4 milliard d'enregistrements

9

J'ai un tableau avec 1,4 milliard d'enregistrements. La structure du tableau est la suivante:

CREATE TABLE text_page (
    text VARCHAR(255),
    page_id INT UNSIGNED
) ENGINE=MYISAM DEFAULT CHARSET=ascii

La condition est de créer un index sur la colonne text.

La taille de la table est d'environ 34G.

J'ai essayé de créer l'index par la déclaration suivante:

ALTER TABLE text_page ADD KEY ix_text (text)

Après 10 heures d'attente, j'ai finalement abandonné cette approche.

Existe-t-il une solution viable à ce problème?

MISE À JOUR : il est peu probable que le tableau soit mis à jour, inséré ou supprimé. La raison pour laquelle créer un index sur la colonne textest que ce type de requête sql serait fréquemment exécuté:

SELECT page_id FROM text_page WHERE text = ?

MISE À JOUR : J'ai résolu le problème en partitionnant la table.

La table est divisée en 40 pièces sur colonne text. La création d'index sur la table prend ensuite environ 1 heure.

Il semble que la création d'index MySQL devienne très lente lorsque la taille de la table devient très grande. Et le partitionnement réduit la table en troncs plus petits.

SiLent SoNG
la source
1
Quel est le problème avec l'utilisation de la CREATE INDEXdéclaration normale ?
Je dirais que cette question pourrait être mieux sur ServerFault - c'est plus un administrateur de base de données qu'une question de programmation.
@Derk: l'approche CREATE INDEX normale est trop lente. Je dois terminer la tâche en 1 jour.
1
Hmm ... Je ne pense pas que vous puissiez contourner cela. Pour construire l'index, le SGBD doit parcourir tous les enregistrements, rassembler leurs champs "texte" et insérer / modifier les nœuds / sous-arbres d'arborescence correspondants. Et cela prend beaucoup de temps pour le 34G ...
chiccodoro
De combien de mémoire dispose votre serveur DB? Avez-vous configuré MySQL pour utiliser toute cette mémoire, ou se limite-t-il?

Réponses:

4

Serait-ce que votre système n'est tout simplement pas à la hauteur? Je n'utilise pas MySQL (ici SQL Server), mais je connais la peine d'indexer une table d'entrées de 800 millions. Fondamentalement ... vous avez besoin du bon matériel pour cela (comme dans: beaucoup de disques rapides). J'utilise maintenant près d'une douzaine de Velociraptors et les performances sont excellentes;)

Les serveurs SQL (pas en tant que MS SQL Server, mais en tant que serveurs de base de données utilisant SQL) vivent et meurent avec un accès au disque, et les disques normaux ne sont tout simplement pas à la hauteur d'opérations plus importantes.

TomTom
la source
Mon doute est que la création d'index est généralement très rapide si le nombre d'enregistrements est petit; disons, des millions. Mais lorsque le nombre atteint des milliards, la création de l'indice devient si lente. On dirait que la croissance temporelle est exponentielle.
Ne devrait pas vraiment l'être. MySQL en général a des limites, mais ce n'est pas une base de données de merde, et ce serait TRÈS mauvais. La génération d'index devient plus lente, mais par log (n), pas (n), donc cela ne devrait pas vraiment être SI mauvais.
TomTom
4

Vous souhaiterez peut-être créer un index sur les premiers (par exemple, 10) caractères du champ de texte.

Depuis les documents:

Des index peuvent être créés qui n'utilisent que la partie principale des valeurs de colonne, en utilisant la syntaxe col_name (longueur) pour spécifier une longueur de préfixe d'index:

CREATE INDEX ix_text ON text_page (text(10))

la source
4

J'ai résolu le problème en partitionnant la table.

La table est divisée en 40 pièces sur colonne text. La création d'index sur la table prend ensuite environ 1 heure.

Il semble que la création d'index MySQL devienne très lente lorsque la taille de la table devient très grande. Et le partitionnement réduit la table en troncs plus petits.

SiLent SoNG
la source
Donc 40 x 1 heure, c'est moins de 10 heures?
symcbean
3

Réglez sort_buffer_size sur 4 Go (ou autant que vous le pouvez en fonction de la quantité de mémoire dont vous disposez).

À l'heure actuelle, l'index de création effectue un tri, mais comme vous disposez d'une taille de sort_buffer_size de 32 Mo, il écrase inutilement le disque dur.

tster
la source
Ces messages sont en désaccord direct avec vous: xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_size et mieux ronaldbradford.com/blog/… Il semble que ce ne soit pas une valeur globale, c'est par requête, c'est donc 4 Go par requête que vous recommandez. En outre, lorsqu'il dépasse 256 Ko, il est mappé sur le disque au lieu d'être une mémoire réelle. Si vous le gardez petit, il nécessite plusieurs passes, mais il évite le disque (il ne change pas).
Ry4an Brase
3

Si vous n'avez pas besoin de faire des requêtes comme:

SELECT page_id FROM text_page WHERE text LIKE '?%';

Je suggère de créer une nouvelle colonne de hachage et d'indexer la table par la colonne. La taille globale de la table + index peut être beaucoup plus petite.

UPD : Au fait, 1,4 milliard d'entiers de clé primaire occupent environ 6 Go, c'est-à-dire que la longueur moyenne de la chaîne est inférieure à 30 caractères, c'est-à-dire que l'indexation sur un préfixe pourrait être plus préférable.

Vous devriez également jeter un œil au moteur de stockage MERGE .

newtover
la source
2

Une façon de procéder consiste à créer une nouvelle table avec l'ensemble d'index et à copier les données dans la nouvelle table.

Assurez-vous également d'avoir suffisamment d'espace temporaire.

décompilé
la source
1
J'ai essayé cette approche. Après 10 heures, moins de 1% des données ont été copiées dans la nouvelle table.
1
Mec ... c'est 1,4 milliards de disques. Pas un million, MILLIARDS. C'est beaucoup. Ça va prendre du temps malgré tout.
Si vous choisissez cette méthode, divisez la copie en morceaux plus petits. Dites environ 100 à 200 millions pour chaque copie.
1
@ décompilé, le diviser en petits morceaux ne fera rien (en fait, cela pourrait le rendre moins efficace). @Bryan, même avec 1,4 milliard d'enregistrements, cela ne devrait pas prendre 1 000 heures.
0

Dans le cas où vous vous demandez toujours comment faire le mieux, je vous suggère d'utiliser un outil de table en ligne alter.

Il y en a beaucoup sur Internet, dont les plus connus sont:

Nous avons les mêmes problèmes avec les grandes tables (plus de 500mil de disques) et la modification est parfaite. Il crée une nouvelle table tmp, ajoute un déclencheur sur la table d'origine (pour les nouveaux enregistrements de mise à jour / suppression / insertion) et en attendant, il copie tous les enregistrements dans la nouvelle table (avec la nouvelle structure)

Bonne chance!

Ali Alwash
la source