2009-09-01 7 views
7

J'utilise et je travaille sur un logiciel qui utilise MySQL comme moteur backend (il peut utiliser d'autres moteurs tels que PostgreSQL ou Oracle ou SQLite, mais c'est l'application principale que nous utilisons). Le logiciel a été la conception de telle sorte que les données binaires que nous voulons accéder est maintenu comme BLOBs dans les colonnes individuelles (chaque table a un blob colonne, les autres colonnes ont des nombres entiers/flotteurs pour caractériser la blob, et une chaîne colonne avec le hachage MD5 BLOB). Les tables ont généralement 2, 3 ou 4 index, dont l'un est toujours la colonne MD5, qui est faite UNIQUE. Certaines tables ont déjà des millions d'entrées, et elles ont atteint la taille de plusieurs gigaoctets. Nous conservons des bases de données MySQL séparées par an dans le même serveur (jusqu'à présent). Le matériel est assez raisonnable (je pense) pour les applications générales (un serveur Dell PowerEdge 2U-form).Slow MySQL insère

Les requêtes MySQL SELECT sont relativement rapides. Il y a peu de plaintes là-bas, car ce sont (la plupart du temps) en mode batch. Cependant, les requêtes INSERT prennent beaucoup de temps, ce qui augmente avec la taille de la table (nombre de lignes). Certes, c'est parce que la colonne MD5 est de type UNIQUE et que chaque INSERT doit déterminer si chaque nouvelle ligne a une chaîne MD5 déjà insérée. Et ce n'est pas trop étrange (je pense) si la performance s'aggrave s'il y a d'autres index (pas uniques). Mais je ne peux toujours pas me reposer que ce choix d'architecture logicielle (je suspecte garder BLOBs dans la rangée de table au lieu de disque a un impact négatif significatif) n'est pas le meilleur choix. Les insertions ne sont pas critiques, mais c'est un sentiment ennuyeux à avoir.

Est-ce que quelqu'un a de l'expérience dans des situations similaires? Avec MySQL, ou même d'autres RDBMes (de préférence Linux)? Toutes les idées que vous souhaitez fournir, peut-être quelques chiffres de performance? Par ailleurs, la langue de travail est C++ (qui enveloppe les appels C à l'API de MySQL).

Répondre

10

Il peut s'agir d'un délai pour le partitionnement horizontal et le déplacement d'un champ BLOB dans une table distincte. Dans cet article dans 'Une note rapide sur le partitionnement vertical' auteur supprime un plus grand champ varchar d'une table et il augmente la vitesse d'une requête d'ordre de grandeur. La raison est que la traversée physique des données sur un disque devient nettement plus rapide s'il y a moins d'espace à couvrir, donc déplacer des champs plus grands ailleurs augmente les performances. Aussi (et vous le faites probablement déjà) il est avantageux de réduire la taille de votre colonne d'index à son minimum absolu (char (32) en codage ascii pour md5), parce que la taille de la clé est directement proportionnelle à la vitesse de son utilisation.

Si vous multiaxes à la fois avec des tables InnoDB, vous pouvez augmenter considérablement la vitesse d'inserts en les enveloppant dans la transaction et des insertions mupliple dans une requête:

START TRANSACTION 
INSERT INTO x (id, md5, field1, field2) values (1, '123dab...', 'data1','data2'),(2,'ab2...','data3','data4'),.....; 
COMMIT 
+1

Le choix BEGIN TRANSACTION semble la solution la plus simple en ce moment. Cependant j'ai quelques questions, puisque je ne suis pas familier avec lui (je maintiendrai RTFM pendant ce temps). 1) Puisque l'API de MySQL est en C, il peut arriver que nous fassions des erreurs et essayons d'insérer des VALEURS qui pointent vers NULL. Cela entraînera presque certainement la mort de l'application cliente avec SEGFAULT. La transaction sera-t-elle "sale" dans ce cas? Besoin de nettoyer? Comment? 2) Nous utilisons MyISAM. Passer à InnoDB maintenant peut être douloureux et/ou dangereux. Connaissez-vous les performances de TRANSACTION sur MyISAM? Merci d'avance pour vos commentaires. – jbatista

+1

MhISAM n'est pas transactionnel, cela signifie que vous pouvez ignorer tout ce que j'ai écrit sur les transactions, mais l'instruction insert avec plusieurs centaines ou milliers d'insertions dans une requête accélérera également les choses dans MyISAM. – dimus

+1

OK. Savez-vous si la syntaxe INSERT INTO impose une limite à la longueur de la chaîne de requête? I.o.w., MySQL accepte-t-il une chaîne de requête INSERT INTO avec une longueur de (par exemple) des centaines de millions de caractères? Ça sent comme des ennuis pour moi. – jbatista

1

Utilisez-vous MyISAM?
AFAIK MyISAM a de très bonnes performances en lecture, mais de mauvaises performances en écriture.

InnoDB devrait être équilibré en vitesse.

+0

Oui, j'ai oublié ce détail. Le serveur que nous utilisons utilise MyISAM. – jbatista

5

Voir Speed of INSERT Statements. Avez-vous des collisions MD5 fréquentes? Je crois que cela ne devrait pas arriver trop souvent, alors peut-être que vous pouvez utiliser quelque chose comme INSERT ... ON DUPLICATE pour gérer les collisions. Si vous avez des périodes d'insertion spécifiques, vous pouvez disable keys pour l'heure de l'insertion et les restaurer plus tard. Une autre option consiste à utiliser replication, en utilisant une machine maître pour les insertions et un esclave pour les sélections.

+0

Merci pour les suggestions, je vais les examiner. – jbatista

+1

A partir du lien ci-dessus: "Si vous insérez plusieurs lignes du même client en même temps, utilisez des instructions INSERT avec plusieurs listes VALUES pour insérer plusieurs lignes à la fois, ce qui est beaucoup plus rapide (beaucoup plus rapide dans certains cas) en utilisant des instructions INSERT à une seule ligne séparées. " Cela a pris mon processus d'insertion de 6K enregistrements de 2,5 min à 5 secondes –

1

Est-ce que vos données en forme dans la RAM? Sinon, obtenez plus de RAM jusqu'à ce que cela devienne non économique (16G est généralement sur le point pour la plupart des gens). Puis, vos index tiennent-ils dans le tampon de clé MyISAM?

Si vous utilisez un système d'exploitation 32 bits, ne le faites pas. Une fois que vous êtes sur un système d'exploitation 64 bits, définissez le tampon de clé à environ 1/3 du RAM. La RAM est utilisée par le cache du système d'exploitation pour mettre en cache les fichiers de données (ce qui est peu utile pour les insertions mais est bénéfique pour les sélections).

Avoir des tables multi-gigaoctet MyISAM peut être une douleur parce que dans le cas d'un arrêt impur, très longue opération de réparation (s) sont nécessaires, mais

Ne changez pas les moteurs MySQL sans validation importante de votre application, il va changer le comportement de plusieurs façons (pas seulement la performance). Cela affectera l'utilisation de l'espace disque.

1

J'ai également demandé un question quelque peu lié aujourd'hui.

L'une des réponses fournies est de considérer le INSERT DELAYED afin qu'il entre dans la file d'insertion et qu'il soit géré lorsque la base de données n'est pas aussi occupée.

+1

Basé sur une réponse dans ce fil, j'ai regardé dans la documentation INSERT DELAYED de MySQL. Ils prétendent qu'il faut faire attention en optant pour INSERT DELAYED, car cela peut détériorer la performance globale dans les insertions client unique par rapport aux INSERTs "normaux". – jbatista

+0

ok - Je ne l'ai pas vu moi-même, même si je cherchais aussi à accélérer le script qui exécute les insertions plutôt que les performances de l'insertion elle-même – warren

+5

il est à noter que INSERT DELAYED fonctionne avec MyASAM, mais pas InnoDB – dimus

Questions connexes