web-dev-qa-db-fra.com

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

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 je dois utiliser insert_delay ou utiliser mysqli_multi_query mécanisme car insert utilise ~ 100% cpu 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 là 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 du tableau:

+-----------------+--------------+------+-----+-------------------+----------------+
| 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.

database status

10
Shashank

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 )

Puisque 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 innodb_buffer_pool_size. Dans un système avec très peu de RAM, 25% (pour accueillir le système d'exploitation).

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 RAM avant de les vider dans les journaux de rétablissement. La valeur par défaut est 8 Mo. Plus le tampon de journal est grand, moins les E/S de disque. Soyez prudent avec les transactions très volumineuses, 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 qui peuvent ê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-le sur 3000) et innodb_write_io_threads (définissez-le 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.

11
RolandoMySQLDBA

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) - flag est-il toujours composé 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, les "rendements décroissants" augmentent.)

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?

2
Rick James

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 endroit 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 d'autres bonnes options: Files d'attente de messages en Perl, php, python .

1
dabest1