Comment utiliser le délai d'insertion avec le moteur InnoDB et utiliser moins de connexion pour les instructions d'insertion?

10

Je travaille sur une application qui implique beaucoup d'écritures de base de données, environ 70% d'insertions et 30% de lectures. Ce ratio comprendrait également les mises à jour que je considère comme une lecture et une écriture. Grâce aux instructions d'insertion, plusieurs clients insèrent des données dans la base de données via l'instruction d'insertion ci-dessous:

$mysqli->prepare("INSERT INTO `track` (user, uniq_name, ad_name, ad_delay_time ) values (?, ?, ?, ?)");

La question est de savoir si j'utilise insert_delay ou le mécanisme mysqli_multi_query car l'instruction insert utilise ~ 100% de processeur sur le serveur. J'utilise le moteur InnoDB sur ma base de données, donc l'insertion différée n'est pas possible. L'insertion sur le serveur est ~ 36k / h et 99,89% de lecture, j'utilise également l'instruction select pour récupérer les données sept fois en une seule requête , cette requête prend 150 secondes sur le serveur pour s'exécuter. Quel type de technique ou de mécanisme puis-je utiliser pour cette tâche? La mémoire de mon serveur est de 2 Go, dois-je étendre la mémoire?. Jetez un oeil sur ce problème, toute suggestion me sera reconnaissante.

Structure de la table:

+-----------------+--------------+------+-----+-------------------+----------------+
| Field           | Type         | Null | Key | Default           | Extra          |
+-----------------+--------------+------+-----+-------------------+----------------+
| id              | int(11)      | NO   | PRI | NULL              | auto_increment |
| user            | varchar(100) | NO   |     | NULL              |                |
| uniq_name       | varchar(200) | NO   |     | NULL              |                |
| ad_name         | varchar(200) | NO   |     | NULL              |                |
| ad_delay_time   | int(11)      | NO   |     | NULL              |                |
| track_time      | timestamp    | NO   | MUL | CURRENT_TIMESTAMP |                |
+-----------------+--------------+------+-----+-------------------+----------------+

Ma base de données présente l'état, elle affiche 41 000 insertions (écritures), ce qui est très lent pour ma base de données.

état de la base de données

Shashank
la source
Pouvez-vous fournir la définition du tableau? (toutes les colonnes, types de données et index)
ypercubeᵀᴹ
Pouvez-vous donner un bref extrait de votre SHOW FULL PROCESSLISTquand il prend 100% de CPU? Combien de connexions autorisez-vous vs combien sont prises pendant cette période?
Derek Downey
Veuillez exécuter ces deux requêtes: SHOW GLOBAL VARIABLES LIKE 'innodb%';et SELECT VERSION();et afficher leur sortie.
RolandoMySQLDBA
Veuillez indiquer le nombre d'insertions par seconde que vous exécutez.
dabest1
Votre code est très sensible à l'injection SQL. Utilisez des instructions préparées et des valeurs paramétrées.
Aaron Brown

Réponses:

11

Puisque vous avez plus d'écrit puis de lecture, je voudrais recommander ce qui suit

Un réglage décent d'InnoDB serait la clé

Pool de tampons ( dimensionné par innodb_buffer_pool_size )

Comme InnoDB ne prend pas en charge INSERT DELAYED , l'utilisation d'un grand pool de tampons InnoDB est la chose la plus proche que vous pouvez obtenir pour INSERT DELAYED. Tous les DML (INSERT, UPDATE et DELETE) seraient mis en cache dans le pool de tampons InnoDB. Les informations transactionnelles pour les écritures sont écrites immédiatement dans les journaux de rétablissement (ib_logfile0, ib_logfile1). Les écritures qui sont publiées dans le pool de tampons sont périodiquement vidées de la mémoire sur le disque via ibdata1 (InsertBuffer pour les index secondaires, tampon d'écriture double). Plus le pool de tampons est grand, plus la quantité d'inserts peut être mise en cache. Dans un système avec 8 Go ou plus de RAM, utilisez 75 à 80% de la RAM comme taille innodb_buffer_pool_size. Dans un système avec très peu de RAM, 25% (pour accueillir l'OS).

CAVEAT: Vous pouvez définir innodb_doublewrite sur 0 pour accélérer encore plus les écritures, mais au risque d'intégrité des données. Vous pouvez également accélérer les choses en définissant innodb_flush_method sur O_DIRECT pour empêcher la mise en cache d'InnoDB sur le système d'exploitation.

Journaux de rétablissement ( dimensionnés par innodb_log_file_size )

Par défaut, les journaux de rétablissement sont nommés ib_logfile0 et ib_logfile1 et auraient 5 Mo chacun. La taille doit correspondre à 25% de la taille innodb_buffer_pool_size. Si les journaux de rétablissement existent déjà, ajoutez le nouveau paramètre dans my.cnf, arrêtez mysql, supprimez-les et redémarrez mysql .

Tampon de journal ( dimensionné par innodb_log_buffer_size )

Le tampon de journal contient les modifications de la RAM avant de les vider dans les journaux de rétablissement. La valeur par défaut est 8M. Plus la mémoire tampon du journal est grande, moins les E / S de disque sont importantes. Soyez prudent avec les transactions très importantes, car cela peut ralentir les COMMITs de quelques millisecondes.

Accès à plusieurs processeurs

MySQL 5.5 et le plug-in MySQL 5.1 InnoDB ont des paramètres permettant au moteur de stockage InnoDB d'accéder à plusieurs processeurs. Voici les options que vous devez définir:

  • innodb_thread_concurrency définit la limite supérieure du nombre de threads simultanés qu'InnoDB peut maintenir ouverts. Il est généralement recommandé de définir pour cela est (2 X Nombre de CPU) + Nombre de disques. L'année dernière, j'ai appris de première main lors de la conférence Percona NYC que vous devez définir ce paramètre sur 0 afin d'alerter le moteur de stockage InnoDB pour trouver le meilleur nombre de threads pour l'environnement dans lequel il s'exécute.
  • innodb_concurrency_tickets définit le nombre de threads qui peuvent contourner la vérification de la concurrence en toute impunité. Une fois cette limite atteinte, la vérification de la simultanéité des threads redevient la norme.
  • innodb_commit_concurrency définit le nombre de transactions simultanées pouvant être validées. Étant donné que la valeur par défaut est 0, le fait de ne pas le définir permet à un nombre illimité de transactions d'être validées simultanément.
  • innodb_thread_sleep_delay définit le nombre de millisecondes pendant lequel un thread InnoDB peut être inactif avant de rentrer dans la file d'attente InnoDB. La valeur par défaut est 10000 (10 secondes).
  • innodb_read_io_threads (définissez ce paramètre sur 3000) et innodb_write_io_threads (définissez ce paramètre sur 7000) (tous deux depuis MySQL 5.1.38) allouez le nombre spécifié de threads pour les lectures et les écritures. La valeur par défaut est 4 et le maximum est 64. Définissez-les sur 64. Définissez également innodb_io_capacity sur 10000.

Mettre à niveau vers MySQL 5.5

Si vous avez MySQL 5.0, passez à MySQL 5.5. Si vous avez MySQL 5.1.37 ou une version antérieure, passez à MySQL 5.5. Si vous avez MySQL 5.1.38 ou supérieur et que vous souhaitez rester dans MySQL 5.1, installez le plug-in InnoDB. De cette façon, vous pouvez profiter de tous les processeurs pour InnoDB.

RolandoMySQLDBA
la source
la mémoire de mon serveur est de 2 Go, donc en fonction de la mémoire, j'ai défini le pool de mémoire tampon innodb à 500M, et les fichiers journaux à 25% pour le pool, définissez également le tampon de journal à 64M. Mais le serveur est toujours très occupé. Dois-je mettre à niveau la mémoire? De plus, mon serveur est sur Ubuntu 32 bits, donc je peux régler la mémoire à 4 Go au maximum.
Shashank du
Si le serveur est juste pour MySQL (pas d'apache, pas de PHP), alors innodb_buffer_pool_size peut représenter jusqu'à 75% de 2 Go, ce qui représente 1536 Mo. Si vous passez à 4 Go, innodb_buffer_pool_size peut être 3G. Les fichiers journaux doivent représenter 25% du pool de tampons, comme vous l'avez indiqué.
RolandoMySQLDBA
Le serveur exécute apache2, mysql et php, dois-je opter pour une mise à niveau de la mémoire dans cette situation ou existe-t-il une solution optimale, sauf pour le pool de mémoire tampon innodb?
Shashank
Ce type n'est pas d'accord avec vous: percona.com/blog/2008/11/21/… Difficile de discuter avec Percona.
Zenexer
Rolando - vous propose d'ajouter à la réponse des mises à jour pour 5.6 et 5.7. Les valeurs par défaut ont changé; d'autres paramètres sont disponibles; etc. Peut-être inclure des conseils Percona et MariaDB et 8.0.
Rick James
2

INT (2) utilise toujours 4 octets - peut-être que vous vouliez dire TINYINT UNSIGNED?

Combien de valeurs différentes dans setno? S'il est petit, la KEY (setno) ne sera jamais utilisée. INSERTing doit mettre à jour cet index; retirer la CLÉ accélérera EN INSÉRER.

CHAR (10) - La flaglongueur est-elle toujours de 10 caractères? Et en utf8? Peut-être pourriez-vous utiliser le drapeau VARCHAR (10) CHARACTER SET ascii

Batch vos inserts - 100 à la fois fonctionneront 10 fois plus vite. (Au-delà de 100 se met à «des rendements décroissants».)

Quelle est la valeur de l'autocommit? Enveloppez-vous chaque INSERT dans BEGIN ... COMMIT? Quelle est la valeur de innodb_flush_log_at_trx_commit?

Rick James
la source
comment puis-je obtenir l'insertion en lot si les données sont insérées via une source externe comme différents clients avec des valeurs différentes .... est-ce fiable si codej'utilise : insérer dans les valeurs t_name (col1, col2, col3) (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3), (val1, val2, val3); code
Shashank
1

Configurez une file d'attente. L'application écrirait dans une file d'attente 1 ligne à la fois, puis retirerait les lignes et les insérerait dans une base de données par lots en fonction du nombre de lignes ou du temps écoulé depuis la dernière insertion.

J'ai vu où le regroupement des inserts 10 000 à la fois est le plus rapide, vous devez donc tester pour trouver un point idéal.

Vous pouvez créer votre propre système de file d'attente simple ou utiliser un système existant. Voici quelques exemples: HornetQ et File :: Queue . Voici un article sur SE listant quelques autres bonnes options: Files d'attente de messages en perl, php, python .

dabest1
la source
Je suis d'accord avec cette approche - je regroupe ~ 1500 insertions toutes les 5 secondes sur une application et c'est moins d'une seconde. mysql semble avoir un mécanisme implémenté en interne qui rend les insertions par lots très rapides.
Don Wool