MySQL InnoDB 与 MyISAM 中的复杂查询性能

Posted

技术标签:

【中文标题】MySQL InnoDB 与 MyISAM 中的复杂查询性能【英文标题】:Complex query performance in MySQL InnoDB versus MyISAM 【发布时间】:2015-05-23 23:18:35 【问题描述】:

我在 4GB RAM 云服务器上运行 MariaDB 10.0.15,并带有用于数据库的本地 SSD 磁盘。

我的模特:

users <n---n> right_holders <n---n> tracks ---n> raw_detections

我有这张表raw_detections 有超过 1 亿条记录。我想在特定时期为特定用户汇总所有raw_detections。这是我遇到问题的查询:

SELECT 
   DATE(raw_detection.created_at),
   SUM(1)
FROM `raw_detection` 
INNER JOIN `audio_sources` ON `audio_sources`.`id` = `raw_detection`.`audio_source_id` 
INNER JOIN `cities` ON `cities`.`id` = `audio_sources`.`city_id` 
INNER JOIN `tracks` ON `raw_detection`.`track_id` = `tracks`.`id` 
INNER JOIN `track_right_holders` ON `tracks`.`id` = `track_right_holders`.`track_id` 
INNER JOIN `right_holders` ON `track_right_holders`.`right_holder_id` = `right_holders`.`id` 
INNER JOIN `user_right_holders` ON `right_holders`.`id` = `user_right_holders`.`right_holder_id` 
WHERE `raw_detection`.`duplicated` = 0 
AND `user_right_holders`.`user_id` = 1 
AND (raw_detection.created_at >= '2015-01-18 00:00:00') 
AND (raw_detection.created_at <= '2015-02-19 23:59:59') 
AND (audio_sources.source_type = 'Radio') 
AND (track_right_holders.role = 'Interpreter') 
GROUP BY DATE(raw_detection.created_at);

有些用户每月的检测次数很多(数万次)。

当 raw_detection 表是 MyISAM 时,此查询需要 2-3 秒才能运行。当表是 InnoDB 时,运行需要 10-20s。我的问题是:

1) 为什么会这样? 2) 如何提高 MyISAM 和 InnoDB 的性能

raw_detection 架构:

CREATE TABLE `raw_detection` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `score` int(11) NOT NULL,
  `track_id` int(11) NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `audio_source_id` int(11) NOT NULL,
  `duplicated` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `index_raw_detection_on_duplicated_and_created_at` (`duplicated`,`created_at`),
  KEY `index_raw_detection_on_created_at` (`created_at`),
  KEY `index_raw_detections_audio_source` (`audio_source_id`,`duplicated`,`created_at`),
  KEY `index_raw_detection_on_track_id_and_duplicated_and_created_at` (`track_id`,`duplicated`,`created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=126224926 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

更新 1: 查询解释的输出

1   SIMPLE  user_right_holders  ref index_user_right_holders_on_user_id,index_user_right_holders_on_right_holder_id index_user_right_holders_on_user_id 5   const   6   Using where; Using temporary; Using filesort
1   SIMPLE  right_holders   eq_ref  PRIMARY PRIMARY 4   playax.user_right_holders.right_holder_id   1   Using index
1   SIMPLE  track_right_holders ref index_track_right_holders_on_track_id,index_track_right_holders_on_right_holder_id2 index_track_right_holders_on_right_holder_id2   773 playax.user_right_holders.right_holder_id,const 4   Using index condition; Using where
1   SIMPLE  tracks  eq_ref  PRIMARY PRIMARY 8   playax.track_right_holders.track_id 1   Using where; Using index
1   SIMPLE  raw_detection   ref index_raw_detection_on_duplicated_and_created_at,index_raw_detection_on_created_at,index_raw_detections_audio_source,index_raw_detection_on_track_id_and_duplicated_and_created_at,raw_detection2_ix    index_raw_detection_on_track_id_and_duplicated_and_created_at   5   playax.tracks.id,const  284 Using index condition
1   SIMPLE  audio_sources   eq_ref  PRIMARY,index_audio_sources_on_city_id,audio_source_city_id,audio_sources_source_type_ix    PRIMARY 4   playax.raw_detection.audio_source_id    1   Using where
1   SIMPLE  cities  eq_ref  PRIMARY PRIMARY 4   playax.audio_sources.city_id    1   Using index

更新 2: 我的 Innodb 和 MyISAM 设置:

ignore_builtin_innodb   OFF
innodb_adaptive_flushing    ON
innodb_adaptive_flushing_lwm    10.000000
innodb_adaptive_hash_index  ON
innodb_adaptive_hash_index_partitions   1
innodb_adaptive_max_sleep_delay 150000
innodb_additional_mem_pool_size 8388608
innodb_api_bk_commit_interval   5
innodb_api_disable_rowlock  OFF
innodb_api_enable_binlog    OFF
innodb_api_enable_mdl   OFF
innodb_api_trx_level    0
innodb_autoextend_increment 64
innodb_autoinc_lock_mode    1
innodb_buffer_pool_dump_at_shutdown OFF
innodb_buffer_pool_dump_now OFF
innodb_buffer_pool_filename ib_buffer_pool
innodb_buffer_pool_instances    8
innodb_buffer_pool_load_abort   OFF
innodb_buffer_pool_load_at_startup  OFF
innodb_buffer_pool_load_now OFF
innodb_buffer_pool_populate OFF
innodb_buffer_pool_size 1073741824
innodb_change_buffer_max_size   25
innodb_change_buffering all
innodb_checksum_algorithm   innodb
innodb_checksums    ON
innodb_cleaner_lsn_age_factor   high_checkpoint
innodb_cmp_per_index_enabled    OFF
innodb_commit_concurrency   0
innodb_compression_failure_threshold_pct    5
innodb_compression_level    6
innodb_compression_pad_pct_max  50
innodb_concurrency_tickets  5000
innodb_corrupt_table_action assert
innodb_data_file_path   ibdata1:12M:autoextend
innodb_data_home_dir    
innodb_disable_sort_file_cache  OFF
innodb_doublewrite  ON
innodb_empty_free_list_algorithm    backoff
innodb_fake_changes 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_timeout 1
innodb_flush_log_at_trx_commit  2
innodb_flush_method O_DIRECT
innodb_flush_neighbors  1
innodb_flushing_avg_loops   30
innodb_force_load_corrupted OFF
innodb_force_recovery   0
innodb_foreground_preflush  exponential_backoff
innodb_ft_aux_table 
innodb_ft_cache_size    8000000
innodb_ft_enable_diag_print OFF
innodb_ft_enable_stopword   ON
innodb_ft_max_token_size    84
innodb_ft_min_token_size    3
innodb_ft_num_word_optimize 2000
innodb_ft_result_cache_limit    2000000000
innodb_ft_server_stopword_table 
innodb_ft_sort_pll_degree   2
innodb_ft_total_cache_size  640000000
innodb_ft_user_stopword_table   
innodb_io_capacity  5000
innodb_io_capacity_max  10000
innodb_kill_idle_transaction    0
innodb_large_prefix OFF
innodb_lock_wait_timeout    50
innodb_locking_fake_changes ON
innodb_locks_unsafe_for_binlog  OFF
innodb_log_arch_dir ./
innodb_log_arch_expire_sec  0
innodb_log_archive  OFF
innodb_log_block_size   512
innodb_log_buffer_size  8388608
innodb_log_checksum_algorithm   innodb
innodb_log_compressed_pages ON
innodb_log_file_size    268435456
innodb_log_files_in_group   2
innodb_log_group_home_dir   ./
innodb_lru_scan_depth   1024
innodb_max_bitmap_file_size 104857600
innodb_max_changed_pages    1000000
innodb_max_dirty_pages_pct  75.000000
innodb_max_dirty_pages_pct_lwm  0.001000
innodb_max_purge_lag    0
innodb_max_purge_lag_delay  0
innodb_mirrored_log_groups  1
innodb_monitor_disable  
innodb_monitor_enable   
innodb_monitor_reset    
innodb_monitor_reset_all    
innodb_old_blocks_pct   37
innodb_old_blocks_time  1000
innodb_online_alter_log_max_size    134217728
innodb_open_files   4096
innodb_optimize_fulltext_only   OFF
innodb_page_size    16384
innodb_print_all_deadlocks  OFF
innodb_purge_batch_size 300
innodb_purge_threads    1
innodb_random_read_ahead    OFF
innodb_read_ahead_threshold 56
innodb_read_io_threads  4
innodb_read_only    OFF
innodb_replication_delay    0
innodb_rollback_on_timeout  OFF
innodb_rollback_segments    128
innodb_sched_priority_cleaner   19
innodb_show_locks_held  10
innodb_show_verbose_locks   0
innodb_simulate_comp_failures   0
innodb_sort_buffer_size 1048576
innodb_spin_wait_delay  6
innodb_stats_auto_recalc    ON
innodb_stats_method nulls_equal
innodb_stats_modified_counter   0
innodb_stats_on_metadata    OFF
innodb_stats_persistent ON
innodb_stats_persistent_sample_pages    20
innodb_stats_sample_pages   8
innodb_stats_traditional    ON
innodb_stats_transient_sample_pages 8
innodb_status_output    OFF
innodb_status_output_locks  OFF
innodb_strict_mode  OFF
innodb_support_xa   ON
innodb_sync_array_size  1
innodb_sync_spin_loops  30
innodb_table_locks  ON
innodb_thread_concurrency   0
innodb_thread_sleep_delay   10000
innodb_track_changed_pages  OFF
innodb_undo_directory   .
innodb_undo_logs    128
innodb_undo_tablespaces 0
innodb_use_atomic_writes    OFF
innodb_use_fallocate    OFF
innodb_use_global_flush_log_at_trx_commit   ON
innodb_use_native_aio   ON
innodb_use_stacktrace   OFF
innodb_use_sys_malloc   ON
innodb_version  5.6.22-71.0
innodb_write_io_threads 4
myisam_block_size   1024
myisam_data_pointer_size    6
myisam_max_sort_file_size   9223372036853727232
myisam_mmap_size    18446744073709551615
myisam_recover_options  BACKUP
myisam_repair_threads   1
myisam_sort_buffer_size 536870912
myisam_stats_method nulls_unequal
myisam_use_mmap OFF

【问题讨论】:

你看过这样的问题吗? ***.com/questions/20148/myisam-versus-innodb?rq=1 你试过用COUNT(*)代替SUM(1)吗?您是否尝试将audio_source_id, track_id 添加到(duplicated, created_at) 上的复合索引的末尾以为此表创建覆盖索引?解释看起来像什么?除了这个查询之外,这个数据库是否还有繁重的写入工作量? COUNT(*) 执行与 SUM(1) 相同的操作 - raw_detection 表一直在写入(大多数是插入,很少更新)。我想添加 audio_source_idtrack_id 不会有帮助,因为这个字段是一个时间戳 InnoDB 和 MyISAM 使用完全不同的参数进行调整。你使用什么设置?值得注意的是,MyISAM 表中的任何数据都必须被认为是易失的,并且可能会在没有通知的情况下消失:该引擎没有日志,并且表损坏可能导致灾难性的数据丢失。相比之下,InnoDB 非常有弹性,通常可以修复。 摆脱“稀有”更新。然后建立汇总表。 【参考方案1】:

MyISAM 在查询简单时速度更快,但在高并发环境中它的表级锁与 InnoDB 的行级锁相比要慢得多。

MyISAM 表可以简单地成为热点并减慢每个连接查询,因此最好避免使用它。

【讨论】:

以上是关于MySQL InnoDB 与 MyISAM 中的复杂查询性能的主要内容,如果未能解决你的问题,请参考以下文章

MySQL存储引擎中的MyISAM和InnoDB区别详解

Mysql存储引擎------InnoDB 与MyISAM

MySQL存储引擎MyISAM与InnoDB区别

MySQL存储引擎--MyISAM与InnoDB区别

MySQL存储引擎--MyISAM与InnoDB区别

MySQL存储引擎--MyISAM与InnoDB区别