J'ai une base de données mysql volumineuse et lourde qui fonctionne assez rapidement, mais parfois très lentement. Toutes les tables sont InnoDB , le serveur a 32 Go de RAM et la taille de la base de données est d’environ 40 Go .
Les 20 requêtes les plus fréquentes dans mon slow_query_log
sont des requêtes update
, insert
et delete
et je ne comprends pas pourquoi elles sont si lentes (jusqu'à 120 secondes parfois!)
Voici la requête la plus fréquente:
UPDATE comment_fallows set comment_cnt_new = 0 WHERE user_id = 1;
Résultats de profilage:
mysql> set profiling = 1;
Query OK, 0 rows affected (0.00 sec)
mysql> update comment_fallows set comment_cnt_new = 0 where user_id = 1;
Query OK, 0 rows affected (2.77 sec)
Rows matched: 18 Changed: 0 Warnings: 0
mysql> show profile for query 1;
+---------------------------+----------+
| Status | Duration |
+---------------------------+----------+
| starting | 0.000021 |
| checking permissions | 0.000004 |
| Opening tables | 0.000010 |
| System lock | 0.000004 |
| init | 0.000041 |
| Searching rows for update | 0.000084 |
| Updating | 0.000055 |
| end | 0.000010 |
| query end | 2.766245 |
| closing tables | 0.000007 |
| freeing items | 0.000013 |
| logging slow query | 0.000003 |
| cleaning up | 0.000002 |
+---------------------------+----------+
13 rows in set (0.00 sec)
J'utilise la réplication maître/serveur, donc le journal binaire est activé. J'ai suivi un conseil que j'avais trouvé sur Internet et défini flush_log_at_trx_commit
sur 0
, mais cela ne faisait aucune différence:
mysql> show variables like '%trx%';
+-------------------------------------------+-------+
| Variable_name | Value |
+-------------------------------------------+-------+
| innodb_flush_log_at_trx_commit | 0 |
| innodb_use_global_flush_log_at_trx_commit | ON |
+-------------------------------------------+-------+
La structure de la table:
CREATE TABLE `comment_fallows` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`part_id` int(11) DEFAULT NULL,
`article_id` int(11) DEFAULT NULL,
`request_id` int(11) DEFAULT NULL,
`comment_cnt` int(10) unsigned NOT NULL,
`comment_cnt_new` int(10) unsigned NOT NULL DEFAULT '0',
`last_comment_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`,`last_comment_date`),
KEY `part_id` (`part_id`),
KEY `last_comment_date` (`last_comment_date`),
KEY `request_id` (`request_id`),
CONSTRAINT `comment_fallows_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
CONSTRAINT `comment_fallows_ibfk_2` FOREIGN KEY (`part_id`) REFERENCES `fanfic_parts` (`id`) ON DELETE CASCADE,
CONSTRAINT `comment_fallows_ibfk_3` FOREIGN KEY (`request_id`) REFERENCES `requests` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=2239419 DEFAULT CHARSET=utf8
Et tous les paramètres innodb (le serveur dispose de 32 Go de RAM):
mysql> show variables like '%innodb%';
+-------------------------------------------+------------------------+
| Variable_name | Value |
+-------------------------------------------+------------------------+
| have_innodb | YES |
| ignore_builtin_innodb | OFF |
| innodb_adaptive_flushing | ON |
| innodb_adaptive_flushing_method | estimate |
| innodb_adaptive_hash_index | ON |
| innodb_adaptive_hash_index_partitions | 1 |
| innodb_additional_mem_pool_size | 16777216 |
| innodb_autoextend_increment | 8 |
| innodb_autoinc_lock_mode | 1 |
| innodb_blocking_buffer_pool_restore | OFF |
| innodb_buffer_pool_instances | 1 |
| innodb_buffer_pool_restore_at_startup | 0 |
| innodb_buffer_pool_shm_checksum | ON |
| innodb_buffer_pool_shm_key | 0 |
| innodb_buffer_pool_size | 21474836480 |
| innodb_change_buffering | all |
| innodb_checkpoint_age_target | 0 |
| innodb_checksums | ON |
| innodb_commit_concurrency | 0 |
| innodb_concurrency_tickets | 500 |
| innodb_corrupt_table_action | assert |
| innodb_data_file_path | ibdata1:10M:autoextend |
| innodb_data_home_dir | |
| innodb_dict_size_limit | 0 |
| innodb_doublewrite | ON |
| innodb_doublewrite_file | |
| innodb_fake_changes | OFF |
| innodb_fast_checksum | OFF |
| innodb_fast_shutdown | 1 |
| innodb_file_format | Antelope |
| innodb_file_format_check | ON |
| innodb_file_format_max | Antelope |
| innodb_file_per_table | ON |
| innodb_flush_log_at_trx_commit | 0 |
| innodb_flush_method | |
| innodb_flush_neighbor_pages | area |
| innodb_force_load_corrupted | OFF |
| innodb_force_recovery | 0 |
| innodb_ibuf_accel_rate | 100 |
| innodb_ibuf_active_contract | 1 |
| innodb_ibuf_max_size | 10737401856 |
| innodb_import_table_from_xtrabackup | 0 |
| innodb_io_capacity | 10000 |
| innodb_kill_idle_transaction | 0 |
| innodb_large_prefix | OFF |
| innodb_lazy_drop_table | 0 |
| innodb_lock_wait_timeout | 120 |
| innodb_locks_unsafe_for_binlog | OFF |
| innodb_log_block_size | 512 |
| innodb_log_buffer_size | 8388608 |
| innodb_log_file_size | 268435456 |
| innodb_log_files_in_group | 3 |
| innodb_log_group_home_dir | ./ |
| innodb_max_dirty_pages_pct | 90 |
| innodb_max_purge_lag | 0 |
| innodb_mirrored_log_groups | 1 |
| innodb_old_blocks_pct | 37 |
| innodb_old_blocks_time | 0 |
| innodb_open_files | 300 |
| innodb_page_size | 16384 |
| innodb_purge_batch_size | 20 |
| innodb_purge_threads | 1 |
| innodb_random_read_ahead | OFF |
| innodb_read_ahead | linear |
| innodb_read_ahead_threshold | 56 |
| innodb_read_io_threads | 8 |
| innodb_recovery_stats | OFF |
| innodb_recovery_update_relay_log | OFF |
| innodb_replication_delay | 0 |
| innodb_rollback_on_timeout | OFF |
| innodb_rollback_segments | 128 |
| innodb_show_locks_held | 10 |
| innodb_show_verbose_locks | 0 |
| innodb_spin_wait_delay | 6 |
| innodb_stats_auto_update | 1 |
| innodb_stats_method | nulls_equal |
| innodb_stats_on_metadata | ON |
| innodb_stats_sample_pages | 8 |
| innodb_stats_update_need_lock | 1 |
| innodb_strict_mode | OFF |
| innodb_support_xa | ON |
| innodb_sync_spin_loops | 30 |
| innodb_table_locks | ON |
| innodb_thread_concurrency | 16 |
| innodb_thread_concurrency_timer_based | OFF |
| innodb_thread_sleep_delay | 10000 |
| innodb_use_global_flush_log_at_trx_commit | ON |
| innodb_use_native_aio | ON |
| innodb_use_sys_malloc | ON |
| innodb_use_sys_stats_table | OFF |
| innodb_version | 1.1.8-rel25.1 |
| innodb_write_io_threads | 8 |
+-------------------------------------------+------------------------+
92 rows in set (0.00 sec)
Cela fait des semaines que je me bats avec ce problème et je serais ravi de vous donner des conseils sur la façon de le résoudre.
Pourquoi mes requêtes update
, insert
et delete
peuvent-elles être si lentes à l'étape query end
?
mettre à jour
J'ai désactivé le cache des requêtes, mais les requêtes update
, insert
et delete
sont toujours très lentes (rien n'a changé)
show variables like '%cache%';
+------------------------------+----------------------+
| Variable_name | Value |
+------------------------------+----------------------+
| binlog_cache_size | 4194304 |
| binlog_stmt_cache_size | 32768 |
| have_query_cache | YES |
| key_cache_age_threshold | 300 |
| key_cache_block_size | 1024 |
| key_cache_division_limit | 100 |
| max_binlog_cache_size | 18446744073709547520 |
| max_binlog_stmt_cache_size | 18446744073709547520 |
| metadata_locks_cache_size | 1024 |
| query_cache_limit | 16777216 |
| query_cache_min_res_unit | 4096 |
| query_cache_size | 0 |
| query_cache_strip_comments | OFF |
| query_cache_type | ON |
| query_cache_wlock_invalidate | OFF |
| stored_program_cache | 256 |
| table_definition_cache | 400 |
| table_open_cache | 2048 |
| thread_cache_size | 8 |
+------------------------------+----------------------+
Essayez de régler les valeurs:
innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT (for non-windows machine)
innodb_buffer_pool_size=25GB (currently it is close to 21GB)
innodb_doublewrite=0
innodb_support_xa=0
innodb_thread_concurrency=0...1000 (try different values, beginning with 200)
Références:
Documentation MySQL pour la description de différentes variables.
Les bases de l'optimisation des performances MySQL
J'espère que ça aide...
Il semble y avoir un bogue dans la façon dont MySQL gère le cache de requêtes, ce qui entraîne un comportement similaire (voir http://bugs.mysql.com/bug.php?id=28382 ).
Ce qui se passe en réalité est que le cache doit être mis à jour à la suite de toute requête modifiant les données (INSERT, UPDATE, DELETE). Avec un cache volumineux, cela prend beaucoup de temps, si le cache est plus petit, il est plus rapide.
Donc, la solution de rechange jusqu'à ce que le moteur soit corrigé consiste à réduire la taille du cache.
Si vous utilisez un serveur Dell, cela peut être un problème de matériel. J'ai résolu cette commande.
/ opt/Dell/srvadmin/bin/omconfig vdisk de stockage action = changepolicy contrôleur = 0 vdisk = 0 writepolicy = fwb
Essayez de régler votre innodb_buffer_pool_instances
en fonction du innodb_buffer_pool_size
De tous les sapins, je pense que vous pouvez augmenter considérablement votre innodb_buffer_pool_size
...
innodb_buffer_pool_instances sysvar
La taille en octets de la mémoire tampon utilisée par InnoDB pour mettre en cache les données et index de ses tables. La valeur par défaut est 128 Mo, augmentée d'un historique par défaut de 8 Mo. La valeur maximale dépend de la CPU architecture, 32 bits ou 64 bits. Pour les systèmes 32 bits, le processeur l'architecture et le système d'exploitation imposent parfois une pratique inférieure taille maximum.
Plus cette valeur est grande, moins il faut d’entrées/sorties sur le disque pour accéder à données dans des tableaux. Sur un serveur de base de données dédié, vous pouvez configurer ceci. Up. à 80% de la taille de la mémoire physique de la machine. Soyez prêt à réduire cette valeur si ces autres problèmes se produisent ...
Ensuite, vous pouvez ajuster le innodb_buffer_pool_instances
, l’utilisation de plusieurs pools de mémoire tampon était très importante, vous pouvez lire un bon scénario de test ici:
Cela est probablement dû à la lenteur des écritures sur le disque.
Dans notre cas, c’était parce que Debian GNU/Linux exécutant mysqld avait été virtualisé dans Hyper-V, et même si le stockage SSD lui était attribué, le hdparm -t
donnait des résultats terribles (10-20 Mo/s au lieu de 600 Mo/s qu’il s’applique au matériel brut).
J'ai le problème dans notre environnement de test (non configuré par DBA). Enfin, je trouve qu'il y a une conf dans my.cnf: sync_binlog = 1. Je change cette conf à 0, et ça marche . Vous pouvez essayer.