web-dev-qa-db-ja.com

MySQL:非常に遅い更新/挿入/削除クエリが「クエリの終了」ステップでハングする

大きくて負荷の高いmysqlデータベースを使用していますが、これは時々かなり高速に動作しますが、場合によっては非常に遅くなることがあります。すべてのテーブルはInnoDBであり、サーバーには2GBのRAMおよびデータベースサイズは約40GBがあります。

slow_query_logの上位20クエリはupdateinsertdeleteクエリであり、それらがなぜ遅いのか理解できません(最大120秒になることもあります)。

最も頻繁なクエリは次のとおりです。

UPDATE comment_fallows set comment_cnt_new = 0 WHERE user_id = 1;

プロファイリング結果:

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)

マスター/サーバーレプリケーションを使用しているため、バイナリログが有効になっています。インターネットで見つけた1つのアドバイスを無視し、flush_log_at_trx_commit0に設定しましたが、違いはありませんでした。

mysql> show variables like '%trx%';
+-------------------------------------------+-------+
| Variable_name                             | Value |
+-------------------------------------------+-------+
| innodb_flush_log_at_trx_commit            | 0     |
| innodb_use_global_flush_log_at_trx_commit | ON    |
+-------------------------------------------+-------+

テーブル構造:

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

そして、すべてのinnodb設定(サーバーには32 GBの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)

私は何週間もこの問題に取り組んできましたが、この問題を解決する方法についてのアドバイスがあればとても助かります。

updateinsertおよびdeleteクエリがquery endステップで非常に遅くなるのはなぜですか?

更新

クエリキャッシュを無効にしましたが、updateinsert、およびdeleteクエリは非常に低速です(変更なし)。

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                    |
+------------------------------+----------------------+
23
Silver Light

値を設定してみてください:

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)

参照:

MySQL docs さまざまな変数の説明。

MySQLサーバー設定のチューニング

MySQLパフォーマンス最適化の基本

それが役に立てば幸い...

14
jsist

MySQLがクエリキャッシュを処理する方法にバグがあり、同様の動作が発生するようです( http://bugs.mysql.com/bug.php?id=28382 を参照)。

基本的に何が起こっているかというと、データを変更するクエリ(INSERT、UPDATE、DELETE)の後にキャッシュを更新する必要があるということです。キャッシュが大きいと、キャッシュのサイズが小さいほど高速になります。

したがって、エンジンが修正されるまでの回避策は、キャッシュサイズを減らすことです。

3
joocer

Dellサーバーを使用している場合、ハードウェアの問題である可能性があります。このコマンドを解決しました。

/ opt/Dell/srvadmin/bin/omconfig storage vdisk action = changepolicy controller = 0 vdisk = 0 writepolicy = fwb

1
kzmr

innodb_buffer_pool_instancesに従ってinnodb_buffer_pool_sizeの調整を開始してください

すべての最初の私はあなたがあなたのinnodb_buffer_pool_sizeを大幅に増やすことができると思います...

innodb_buffer_pool_instances sysvar

InnoDBがデータとそのテーブルのインデックスをキャッシュするために使用するメモリバッファーのサイズ(バイト単位)。デフォルト値は128MBで、これまでのデフォルトの8MBから増加しています。最大値は、32ビットまたは64ビットのCPUアーキテクチャによって異なります。 32ビットシステムの場合、CPUアーキテクチャとオペレーティングシステムにより、実際的な最大サイズが低くなることがあります。

この値を大きく設定すると、テーブル内のデータにアクセスするために必要なディスクI/Oが少なくなります。専用データベースサーバーでは、これをマシンの物理メモリサイズの最大80%に設定できます。これらの他の問題が発生した場合は、この値を縮小する準備をしてください...

次に、innodb_buffer_pool_instancesを調整できます。複数のバッファープールを使用することが非常に重要でした。yuoは、ここで適切なテストケースを読むことができます。

MySQLワークロードテスト

0
Cristian Porta

おそらくディスクの書き込みが遅いことが原因です。

私たちのケースでは、mysqldを実行するDebian GNU/LinuxがHyper-Vで仮想化されていたため、SSDストレージが与えられた場合でもhdparm -tはひどい結果を出していました(生のハードウェアでは600MB/sではなく10-20MB/s)

0
Matija Nalis

私のテスト環境に問題があります(DBAによって設定されていません)。最後に、my.cnfに1つの設定があることがわかりました:sync_binlog = 1。このconfを0に変更すると、動作します。試してみることができます。

0
user188826