2012-09-07 6 views
22

Ho un database mysql grande e pesante che funziona a volte piuttosto veloce, ma a volte diventa terribilmente lento. Tutte le tabelle sono InnoDB, server ha 32 GB di RAM edimensione del database è di circa 40GB.MySQL: aggiornamento/inserimento/eliminazione molto lento di query sospese sul passaggio "query end"

Top 20 query nei miei slow_query_log sono update, insert e delete query e non riesco a capire perché sono così lento

Ecco la domanda più frequente (fino a 120 secondi a volte!):

UPDATE comment_fallows set comment_cnt_new = 0 WHERE user_id = 1; 

risultati profilatura:

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) 

sto usando la replicazione master/server, in modo il registro binario è abilitato. Ho a riposo un consiglio che ho trovato su internet e impostare flush_log_at_trx_commit-0 ma non ha fatto alcuna differenza:

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 struttura della tabella:

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 

E tutte le impostazioni InnoDB (server dispone di 32 GB di 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) 

ho lottato con questo problema per settimane e sarebbe molto greatfull per qualsiasi consiglio su come risolvere questo problema.

Perché potrebbe miei update, insert e delete query essere così lento su query end passo?

aggiornamento

Ho disabile di query nella cache, ma update, insert e delete query sono ancora molto molto lento (nulla è cambiato)

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

Quando si esegue quella query con id invece di user_id "UPDATE comment_fallows set comment_cnt_new = 0 WHERE id = 1" avrebbe la stessa latenza? – Pinchy

+0

@Pinchy, si. In realtà, è ancora più lento. –

+0

@SilverLight quale versione di MySql? –

risposta

3

Sembra che ci sia un bug con la modalità di gestione di MySQL la cache della query che causa un comportamento simile (vedere http://bugs.mysql.com/bug.php?id=28382).

In pratica, è necessario aggiornare la cache in seguito a qualsiasi query che modifica i dati (INSERT, UPDATE, DELETE). Con una cache di grandi dimensioni ci vuole molto tempo per farlo, se la cache è più piccola allora è più veloce.

Quindi la soluzione fino a quando il motore è stato risolto è quello di ridurre la dimensione della cache.

+0

joocer, grazie per la risposta. Ho avuto cache di query di 512 Mb. Quando l'ho disabilitato, le cose sono diventate molto più veloci. Ma le query INSERT, UPDATE, DELETE sono ancora molto lente. –

+0

@SilverLight, solo per confermare, le query sono ancora lente sul passaggio "query end" o le prestazioni degli altri passaggi sono cambiate del tutto? – joocer

0

provare ad avviare accordare la innodb_buffer_pool_instances secondo le innodb_buffer_pool_size

Firs di tutto penso è possibile aumentare notevolmente la vostra innodb_buffer_pool_size ...

innodb_buffer_pool_instances sysvar

La dimensione in byte del buffer di memoria InnoDB cacha dati e indici delle proprie tabelle. Il valore predefinito è 128 MB, aumentato da un valore storico predefinito di di 8 MB. Il valore massimo dipende dall'architettura CPU , 32 bit o 64 bit. Per i sistemi a 32 bit, l'architettura e il sistema operativo della CPU a volte impongono una dimensione massima pratica inferiore.

Più grande è il valore impostato, minore è la necessità di I/O su disco per accedere ai dati nelle tabelle. Su un server database dedicato, è possibile impostare questo su su 80% della dimensione della memoria fisica della macchina. Siate pronti a ridimensionare questo valore se si verificano questi altri problemi ...

Quindi è possibile sintonizzare il innodb_buffer_pool_instances, l'utilizzo di più pool di buffer è stato molto importante, yuo può leggere un buon banco di prova qui:

MySQL Workload test

13

impostazione Provate valori:

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) 

Riferimenti:

MySQL docs per la descrizione di diverse variabili.

MySQL Server Setting Tuning

MySQL Performance Optimization basics

Speranza che aiuta ...

+0

Proverò queste impostazioni ... –

+0

non ha funzionato per me. Ancora ottenere la fine della query. Potrebbe non avere alcun disco di scambio sul server? Sto usando Windows Server ... –

+0

Ottimo, funziona. Per installazioni più piccole, probabilmente avrai bisogno di meno innodb_thread_concurrency e innodb_buffer_pool_size, ma in generale questo consiglio funziona. –

1

Può essere un problema di hardware, se si utilizza il server DELL. Ho risolto questo comando.

/opt/Dell/srvadmin/bin/omconfig stoccaggio vdisk action = changepolicy regolatore = 0 vdisk = 0 writepolicy = fwb

0

ho il problema nel nostro ambiente di test (non istituito dalla DBA). Infine trovo che ci sia un conf in my.cnf: sync_binlog = 1. Cambio questo conf a 0 e funziona. Puoi provare.

0

Probabilmente è dovuto alla lentezza delle scritture su disco.

Nel nostro caso è stato a causa di Debian GNU/Linux in esecuzione mysqld è stato virtualizzato in Hyper-V, e anche se è stato dato storage SSD hdparm -t stava dando risultati terribili (10-20MB/s invece di 600MB/s che ottiene su hardware grezzo)