獨家揭秘丨GreatSQL 沒開Binlog時多線程插入數據性能劣化之謎

来源:https://www.cnblogs.com/greatsql/p/18310838
-Advertisement-
Play Games

一、問題發現 在一次數據遷移中,用到了INSERT INTO t1 SELECT * FROM t2這樣的 SQL 用來搬遷大表,為了提高插入效率關閉了Binlog,考慮用多線程來插入提高速度。表的類型信息和插入效率如下所示。 測試環境: Linux node-76-11 4.19.90-17.ky ...


一、問題發現

在一次數據遷移中,用到了INSERT INTO t1 SELECT * FROM t2這樣的 SQL 用來搬遷大表,為了提高插入效率關閉了Binlog,考慮用多線程來插入提高速度。表的類型信息和插入效率如下所示。

測試環境:

  • Linux node-76-11 4.19.90-17.ky10.aarch64,128核CPU,512G記憶體。

GreatSQL參數配置如下(為降低 I/O 因素影響,關閉 Binlog):

#**********************Performance*********************
#******connect
max_connections=10000
max_connect_errors=1000000
open_files_limit=65535
back_log=1500
table_definition_cache=10000
thread_stack=256K
thread_cache_size=3000

#******session
sort_buffer_size=4M
join_buffer_size=4M
read_buffer_size=4M
read_rnd_buffer_size=4M
bulk_insert_buffer_size=64M
tmp_table_size=64M
max_heap_table_size=64M
net_buffer_length=16K
max_allowed_packet=1G

#******timeout
lock_wait_timeout=600
connect_timeout=10
interactive_timeout=31536000
wait_timeout=31536000
net_read_timeout=86400
net_write_timeout=86400
net_retry_count=10
#**********************InnoDB**************************
transaction_isolation=READ-COMMITTED
innodb_buffer_pool_size=200G
innodb_buffer_pool_instances=16
innodb_max_dirty_pages_pct=90
innodb_flush_log_at_trx_commit=0
innodb_log_buffer_size=1G
innodb_page_cleaners=8
innodb_buffer_pool_dump_at_shutdown=ON
innodb_buffer_pool_load_at_startup=ON
innodb_buffer_pool_dump_pct=100
innodb_checksum_algorithm=NONE
innodb_log_checksums=NO
innodb_undo_log_truncate=OFF
innodb_change_buffering = none
innodb_spin_wait_delay=6
innodb_spin_wait_pause_multiplier=50
innodb_sync_spin_loops=30
#******feature
innodb_open_files=65535
innodb_flush_method=O_DIRECT
innodb_flush_neighbors=0
innodb_flush_sync=ON
innodb_io_capacity=20000
innodb_io_capacity_max=40000
innodb_lru_scan_depth=9000
innodb_lock_wait_timeout=30
innodb_print_all_deadlocks=ON
innodb_online_alter_log_max_size=4G
innodb_thread_concurrency=0
innodb_read_io_threads=32
innodb_write_io_threads=32
innodb_doublewrite=ON
innodb_doublewrite_pages=64
innodb_adaptive_hash_index=OFF
innodb_status_file=OFF

1、窄表 + 有自增主鍵

greatsql> CREATE TABLE t1 (
  c1 int invisible auto_increment primary key,
  c2 int,
  str1 int DEFAULT(100) NOT NULL,
  str2 int DEFAULT(100) NOT NULL,
  str3 int DEFAULT(100) NOT NULL,
  str4 int DEFAULT(100) NOT NULL
) engine=InnoDB;

greatsql> CREATE TABLE t2 LIKE t1;

行平均長度約 30 位元組

行數 插入sql 線程數 總用時 解釋
1000萬行 insert into t2 select * from t1; 單線程 1 min 46.47 sec
1000萬行 insert into t2 select * from t1; 2 1 min 15.45 sec
1000萬行 insert into t2 select * from t1; 6 55.74 sec
1000萬行 insert into t2 select * from t1; 10 45.34 sec
1000萬行 insert into t2 select * from t1; 16 43.78 sec 最佳
1000萬行 insert into t2 select * from t1; 2 1 min 11.62 sec
1000萬行 insert into t2 select * from t1; 6 1 min 2.53 sec
1000萬行 insert into t2 select * from t1; 10 1 min 0.55 sec
1000萬行 insert into t2 select * from t1; 16 55.46 sec
1000萬行 insert into t2 select * from t1; 2 1 min 24.13 sec
1000萬行 insert into t2 select * from t1; 6 1 min 14.43 sec
1000萬行 insert into t2 select * from t1; 10 1 min 10.64 sec

2、中等寬度表 + 有自增主鍵

greatsql> CREATE TABLE t1 (
  c1 int invisible auto_increment primary key,
  c2 int,
  str1 varchar(512) CHARACTER SET latin1 DEFAULT(repeat('a',512)) NOT NULL
) engine=InnoDB;

greatsql> CREATE TABLE t2 LIKE t1;

行平均長度約 500多位元組

行數 插入sql 線程數 總用時 解釋
1000萬行 insert into t2 select * from t1; 單線程 4 min 30.41 sec
1000萬行 insert into t2 select * from t1; 2 4 min 36.58 sec 效率無提升
1000萬行 insert into t2 select * from t1; 6 4 min 46.58 sec 效率無提升
1000萬行 insert into t2 select * from t1; 10 4 min 50.43 sec 效率無提升
1000萬行 insert into t2 select * from t1; 2 4 min 26.28 sec 效率無提升
1000萬行 insert into t2 select * from t1; 6 4 min 38.84 sec 效率無提升
1000萬行 insert into t2 select * from t1; 10 4 min 49.42 sec 效率無提升
1000萬行 insert into t2 select * from t1; 2 4 min 25.67 sec 效率無提升
1000萬行 insert into t2 select * from t1; 6 4 min 40.42 sec 效率無提升
1000萬行 insert into t2 select * from t1; 10 4 min 46.70 sec 效率無提升

3、寬表 + 有自增主鍵

greatsql> CREATE TABLE t1 (
  c1 int invisible auto_increment primary key,
  c2 int,
  str1 varchar(1024) CHARACTER SET latin1 DEFAULT(repeat('a1',512)) NOT NULL,
  str2 varchar(1024) CHARACTER SET latin1 DEFAULT(repeat('b2',512)) NOT NULL,
  str3 varchar(1024) CHARACTER SET latin1 DEFAULT(repeat('c3',512)) NOT NULL,
  str4 varchar(1024) CHARACTER SET latin1 DEFAULT(repeat('c3',512)) NOT NULL
) engine=InnoDB;

greatsql> CREATE TABLE t2 LIKE t1;

行平均長度約 5000多位元組

行數 插入sql 線程數 總用時/s 解釋
100萬行 insert into t2 select * from t1; 單線程 4 min 32.90 sec
100萬行 insert into t2 select * from t1; 2 4 min 52.36 sec 性能劣化
100萬行 insert into t2 select * from t1; 2 4 min 52.31 sec 性能劣化
100萬行 insert into t2 select * from t1; 6 5 min 36.07 sec 性能劣化
100萬行 insert into t2 select * from t1; 2 4 min 48.34 sec 性能劣化

4、窄表 + 無主鍵(GIPK關)

greatsql> CREATE TABLE t1 (
  c1 int invisible auto_increment primary key,
  c2 int,
  str1 int DEFAULT(100) NOT NULL,
  str2 int DEFAULT(100) NOT NULL,
  str3 int DEFAULT(100) NOT NULL,
  str4 int DEFAULT(100) NOT NULL
) engine=InnoDB;

greatsql> CREATE TABLE t2 (
  c2 int,
  str1 int DEFAULT(100) NOT NULL,
  str2 int DEFAULT(100) NOT NULL,
  str3 int DEFAULT(100) NOT NULL,
  str4 int DEFAULT(100) NOT NULL
) engine=InnoDB;

行平均寬度約 30 位元組,沒用 GIPKs 特性

行數 插入sql 線程數 總用時 解釋
1000萬行 insert into t2 select * from t1; 單線程 1 min 29.08 sec
1000萬行 insert into t2 select * from t1; 2 1 min 38.84 sec 性能劣化
1000萬行 insert into t2 select * from t1; 6 2 min 18.88 sec 性能劣化
1000萬行 insert into t2 select * from t1; 10 2 min 14.51 sec 性能劣化
1000萬行 insert into t2 select * from t1; 2 1 min 35.96 sec 性能劣化
1000萬行 insert into t2 select * from t1; 6 2 min 3.55 sec 性能劣化
1000萬行 insert into t2 select * from t1; 10 2 min 1.52 sec 性能劣化

5、結論

從上面的測試結果可以看出,無主鍵表併發插入劣化嚴重,有主鍵的情況下,窄表的併發性能提升效果好,但是對於寬表反而會造成劣化。

二、問題調查過程

1、首先調查無主鍵的情況下長數據造成性能劣化的情況。用perf查看造成性能劣化的瓶頸在哪裡。

+   12.55%     0.01%  mysqld   mysqld               [.] lock_clust_rec_read_check_and_lock
+   12.34%     0.13%  mysqld   [kernel.kallsyms]    [k] x64_sys_call
+   12.03%     0.01%  mysqld   mysqld               [.] Buf_fetch<Buf_fetch_normal>::mtr_add_page
+   11.92%     0.01%  mysqld   mysqld               [.] btr_cur_ins_lock_and_undo
+   11.27%     0.19%  mysqld   [kernel.kallsyms]    [k] __x64_sys_futex
-   11.18%    11.11%  mysqld   mysqld               [.] ut_delay
     10.89% start_thread
        pfs_spawn_thread
        handle_connection
        do_command
        dispatch_command
        dispatch_sql_command                                                                           
        mysql_execute_command
        Sql_cmd_dml::execute
        Sql_cmd_dml::execute_inner 
        Query_expression::execute  
      - Query_expression::ExecuteIteratorQuery 
         - 10.75% Query_result_insert::send_data 
              write_record         
              handler::ha_write_row            
              ha_innobase::write_row           
              row_insert_for_mysql 
              row_insert_for_mysql_using_ins_graph 
              row_ins_step         
              row_ins              
              row_ins_index_entry_step         
              row_ins_index_entry  
              row_ins_clust_index_entry        
            - row_ins_clust_index_entry_low    
               - 10.16% btr_pcur_t::open       
                  - btr_cur_search_to_nth_level  
                     - 10.10% buf_page_get_gen 
                        - 10.08% Buf_fetch<Buf_fetch_normal>::single_page 
                           - 10.07% Buf_fetch<Buf_fetch_normal>::mtr_add_page 
                                rw_lock_x_lock_gen 
                              - pfs_rw_lock_x_lock_func                   
                                 - 10.07% rw_lock_x_lock_func             
                                      ut_delay 
+   11.08%     0.21%  mysqld   [kernel.kallsyms]    [k] do_futex          
+   10.90%     0.02%  mysqld   mysqld               [.] rw_lock_x_lock_func   
+   10.90%     0.00%  mysqld   mysqld               [.] pfs_rw_lock_x_lock_func 
+   10.90%     0.01%  mysqld   mysqld               [.] rw_lock_x_lock_gen   
+    9.44%     0.01%  mysqld   mysqld               [.] locksys::owns_page_shard 
+    9.39%     0.05%  mysqld   mysqld               [.] locksys::Latches::owns_page_shard 
+    9.29%     0.64%  mysqld   mysqld               [.] PolicyMutex<TTASEventMutex<GenericPolicy> >::trylock 
+    7.66%     0.02%  mysqld   mysqld               [.] locksys::rec_queue_latch_and_validate 
+    7.65%     0.17%  mysqld   mysqld               [.] rw_lock_debug_mutex_exit 
+    7.39%     0.07%  mysqld   mysqld               [.] trx_undo_report_row_operation     
+    7.17%     0.01%  mysqld   mysqld               [.] buf_pool_validate_instance        
+    7.17%     0.00%  mysqld   mysqld               [.] buf_validate      
-    6.63%     5.87%  mysqld   mysqld               [.] unlikely          
   - 5.84% start_thread            
        pfs_spawn_thread           
        handle_connection          
        do_command                 
        dispatch_command           
        dispatch_sql_command       
        mysql_execute_command      
        Sql_cmd_dml::execute       
        Sql_cmd_dml::execute_inner 
        Query_expression::execute  
      - Query_expression::ExecuteIteratorQuery 
         - 4.44% Query_result_insert::send_data  
              write_record         
              handler::ha_write_row            
              ha_innobase::write_row           
            - row_insert_for_mysql 
               - 4.43% row_insert_for_mysql_using_ins_graph               
                  - 4.42% row_ins_step         
                     - 4.41% row_ins           
                        - 4.41% row_ins_index_entry_step                  
                           - 4.35% row_ins_index_entry                    
                                row_ins_clust_index_entry                 
                              - row_ins_clust_index_entry_low             
                                 - 1.89% btr_pcur_t::open                 
                                    - btr_cur_search_to_nth_level         
                                       - 1.08% page_cur_search_with_match 
                                            0.52% dtuple_t::compare       
                                 - 1.87% btr_cur_optimistic_insert        
                                      1.13% page_cur_tuple_insert         
                                      0.56% btr_cur_ins_lock_and_undo     
         + 1.40% TableScanIterator::Read       
     0.76% unlikely                
+    6.38%     0.45%  mysqld   [kernel.kallsyms]    [k] futex_wait        
+    5.88%     0.02%  mysqld   mysqld               [.] Buf_fetch_normal::get 
+    5.76%     0.01%  mysqld   mysqld               [.] lock_rec_lock       

可以看到多線程數據插入時候,在無主鍵的情況下頻繁的索引分裂影響性能,所以導致性能劣化嚴重

那麼有自增主鍵的情況下性能是什麼情況呢?

看一下有自增主鍵的情況下性能情況,在有自增主鍵的時候與上面無主鍵的性能瓶頸處差不多,但是沒有那麼嚴重的頻繁的索引分裂的性能問題。

+   10.16%     0.67%  mysqld   mysqld               [.] PolicyMutex<TTASEventMutex<GenericPolicy> >::trylock         
+    9.25%     0.03%  mysqld   mysqld               [.] trx_undo_report_row_operation     
+    8.49%     0.31%  mysqld   [kernel.kallsyms]    [k] futex_wait        
+    7.77%     0.00%  mysqld   libstdc++.so.6.0.32  [.] 0x00007ffff7958793    
+    7.59%     0.17%  mysqld   mysqld               [.] rw_lock_debug_mutex_exit 
-    7.30%     6.87%  mysqld   mysqld               [.] unlikely          
     6.58% start_thread            
        pfs_spawn_thread           
        handle_connection          
        do_command                 
        dispatch_command           
        dispatch_sql_command       
        mysql_execute_command      
        Sql_cmd_dml::execute       
        Sql_cmd_dml::execute_inner 
        Query_expression::execute  
      - Query_expression::ExecuteIteratorQuery 
         - 5.01% Query_result_insert::send_data  
            - 5.00% write_record   
                 handler::ha_write_row         
               - ha_innobase::write_row        
                  - 4.99% row_insert_for_mysql 
                     - row_insert_for_mysql_using_ins_graph               
                        - 4.96% row_ins_step   
                           - row_ins           
                              - 4.95% row_ins_index_entry_step            
                                 - 4.91% row_ins_index_entry              
                                      row_ins_clust_index_entry           
                                    - row_ins_clust_index_entry_low       
                                       - 2.63% btr_cur_optimistic_insert  
                                          - 1.35% page_cur_tuple_insert   
                                               0.67% page_cur_insert_rec_low  
                                          - 0.87% btr_cur_ins_lock_and_undo   
                                               0.59% trx_undo_report_row_operation        
                                       - 1.22% btr_pcur_t::open           
                                            1.20% btr_cur_search_to_nth_level 
                                       - 0.55% btr_cur_pessimistic_insert 
                                          - 0.55% btr_page_split_and_insert   
                                               0.51% page_validate        
         + 1.57% TableScanIterator::Read       
+    7.06%     0.03%  mysqld   mysqld               [.] mtr_t::commit     
+    7.02%     0.00%  mysqld   mysqld               [.] buf_validate      
+    7.01%     0.02%  mysqld   mysqld               [.] buf_pool_validate_instance    

我們知道對自增主鍵插入新數據時,是先獲取一個區段鎖,這樣可以避免頻繁持鎖造成的性能劣化。而無顯式定義主鍵表(其他可用於聚集索引的非空唯一索引也沒有)時,會採用實例級的 DB_ROW_ID 作為該表的聚集索引,這個 DB_ROW_ID 每插入一行都需要請求加鎖,因此會比自增主鍵表更加耗時。所以上面可以看到無主鍵表的多線程插入性能反而比單線程劣化。

2、接著調查有主鍵的情況下寬表造成性能劣化的情況。用perf查看造成性能劣化的瓶頸在哪裡。

+   12.66%     0.05%  mysqld   [kernel.kallsyms]    [k] do_syscall_64     
-   12.65%    12.30%  mysqld   mysqld               [.] ut_delay                                       
   - 7.46% start_thread            
        pfs_spawn_thread           
        handle_connection          
        do_command                 
        dispatch_command           
        dispatch_sql_command       
        mysql_execute_command      
        Sql_cmd_dml::execute       
        Sql_cmd_dml::execute_inner 
        Query_expression::execute  
      - Query_expression::ExecuteIteratorQuery 
         - 7.27% Query_result_insert::send_data  
              write_record         
              handler::ha_write_row            
              ha_innobase::write_row           
              row_insert_for_mysql 
              row_insert_for_mysql_using_ins_graph 
              row_ins_step         
              row_ins              
              row_ins_index_entry_step         
              row_ins_index_entry  
              row_ins_clust_index_entry        
            - row_ins_clust_index_entry_low    
               - 4.53% btr_pcur_t::open        
                  - btr_cur_search_to_nth_level  
                     - 2.52% mtr_t::sx_lock    
                          rw_lock_sx_lock_gen  
                        - pfs_rw_lock_sx_lock_func 
                           + 2.52% rw_lock_sx_lock_func                   
                     - 1.85% buf_page_get_gen  
                        - 1.84% Buf_fetch<Buf_fetch_normal>::single_page  
                           - 1.81% Buf_fetch<Buf_fetch_normal>::mtr_add_page  
                                rw_lock_s_lock_gen 
                                rw_lock_s_lock_func                       
                                rw_lock_s_lock_spin                       
                                ut_delay       
               - 2.07% btr_height_get          
                    btr_root_block_get         
                    btr_block_get  
                    btr_block_get_func         
                  - buf_page_get_gen           
                     - 2.06% Buf_fetch<Buf_fetch_normal>::single_page     
                        - 2.05% Buf_fetch<Buf_fetch_normal>::mtr_add_page 
                             rw_lock_s_lock_gen  
                             rw_lock_s_lock_func 
                             rw_lock_s_lock_spin 
                             ut_delay          
                 0.50% btr_cur_optimistic_insert 
- 4.85% 0x7ffff7958793          
      - 4.70% std::thread::_State_impl<std::thread::_Invoker<std::tuple<Detached_thread, void (*)(unsigned long), unsigned long> > >::_M_run
           std::thread::_Invoker<std::tuple<Detached_thread, void (*)(unsigned long), unsigned long> >::operator()
           std::thread::_Invoker<std::tuple<Detached_thread, void (*)(unsigned long), unsigned long> >::_M_invoke<0ul, 1ul, 2ul>
           std::__invoke<Detached_thread, void (*)(unsigned long), unsigned long>         
           std::__invoke_impl<void, Detached_thread, void (*)(unsigned long), unsigned long>  
           Detached_thread::operator()<void (*)(unsigned long), unsigned long>  
           std::_Bind<void (*(unsigned long))(unsigned long)>::operator()<, void>         
           std::_Bind<void (*(unsigned long))(unsigned long)>::__call<void, , 0ul>        
           std::__invoke<void (*&)(unsigned long), unsigned long&>        
         - std::__invoke_impl<void, void (*&)(unsigned long), unsigned long&> 
            - 4.53% io_handler_thread          
               - fil_aio_wait      
                  - 4.14% buf_page_io_complete 
                     - 1.48% buf_flush_write_complete                     
                        - 1.48% mutex_enter_inline<PolicyMutex<TTASEventMutex<GenericPolicy> > >
                             PolicyMutex<TTASEventMutex<GenericPolicy> >::enter 
                             TTASEventMutex<GenericPolicy>::enter         
                             TTASEventMutex<GenericPolicy>::spin_and_try_lock 
                             TTASEventMutex<GenericPolicy>::is_free       
                             ut_delay          
                     - 1.38% ibuf_merge_or_delete_for_page                
                        - 1.19% ibuf_bitmap_get_map_page                  
                             buf_page_get_gen  
                             Buf_fetch<Buf_fetch_normal>::single_page     
                             Buf_fetch<Buf_fetch_normal>::mtr_add_page    
                             rw_lock_x_lock_gen  
                             pfs_rw_lock_x_lock_func                      
                             rw_lock_x_lock_func 
                             ut_delay          
                     - 1.04% mutex_enter_inline<PolicyMutex<TTASEventMutex<GenericPolicy> > > 
                          PolicyMutex<TTASEventMutex<GenericPolicy> >::enter  
                          TTASEventMutex<GenericPolicy>::enter            
                          TTASEventMutex<GenericPolicy>::spin_and_try_lock    
                          TTASEventMutex<GenericPolicy>::is_free          
                          ut_delay                                                 
+   12.57%     0.41%  mysqld   [kernel.kallsyms]    [k] x64_sys_call      
+    9.93%     0.00%  mysqld   mysqld               [.] buf_validate      
+    9.91%     0.06%  mysqld   mysqld               [.] buf_pool_validate_instance        
+    9.73%     0.11%  mysqld   [kernel.kallsyms]    [k] __x64_sys_futex   
+    9.72%     0.30%  mysqld   mysqld               [.] rw_lock_debug_mutex_enter         
+    9.61%     0.13%  mysqld   [kernel.kallsyms]    [k] do_futex          
+    8.23%     0.03%  mysqld   mysqld               [.] TableScanIterator::Read 
+    8.20%     0.02%  mysqld   mysqld               [.] handler::ha_rnd_next  
+    8.17%     0.00%  mysqld   mysqld               [.] ha_innobase::rnd_next 
+    8.17%     0.00%  mysqld   mysqld               [.] ha_innobase::general_fetch        
+    8.08%     0.05%  mysqld   mysqld               [.] row_search_mvcc   
+    7.75%     0.02%  mysqld   mysqld               [.] buf_page_t::Latching_rules_helpers::assert_latches_let_distinguish 
+    7.71%     0.03%  mysqld   mysqld               [.] buf_page_t::is_io_fix_write       
+    7.41%     0.04%  mysqld   mysqld               [.] ut::Stateful_latching_rules<buf_io_fix, 3ul>::assert_latches_let_distinguish 
+    7.10%     0.01%  mysqld   mysqld               [.] btr_cur_optimistic_insert         
+    6.98%     0.02%  mysqld   mysqld               [.] Buf_fetch_normal::get 
+    6.76%     0.29%  mysqld   mysqld               [.] PolicyMutex<TTASEventMutex<GenericPolicy> >::trylock
+    6.50%     0.02%  mysqld   mysqld               [.] Buf_fetch<Buf_fetch_normal>::mtr_add_page
+    6.15%     0.04%  mysqld   mysqld               [.] ut::Stateful_latching_rules<buf_io_fix, 3ul>::assert_latches_let_distinguish
+    6.11%     0.02%  mysqld   mysqld               [.] ut::Stateful_latching_rules<buf_io_fix, 3ul>::can_leave
+    5.92%     0.27%  mysqld   [kernel.kallsyms]    [k] futex_wait        
+    5.89%     0.11%  mysqld   mysqld               [.] rw_lock_debug_mutex_exit 
+    5.89%     0.01%  mysqld   mysqld               [.] btr_block_get     
+    5.88%     0.00%  mysqld   mysqld               [.] btr_block_get_func    
+    5.74%     0.02%  mysqld   mysqld               [.] rw_lock_s_lock_func   
+    5.50%     0.01%  mysqld   mysqld               [.] PolicyMutex<TTASEventMutex<GenericPolicy> >::enter
-    5.49%     4.80%  mysqld   mysqld               [.] unlikely          
   - 3.89% start_thread            
        pfs_spawn_thread           
        handle_connection          
        do_command                 
        dispatch_command           
        dispatch_sql_command       
        mysql_execute_command      
        Sql_cmd_dml::execute       
        Sql_cmd_dml::execute_inner 
        Query_expression::execute  
      - Query_expression::ExecuteIteratorQuery 
         - 3.37% Query_result_insert::send_data  
              write_record         
              handler::ha_write_row            
              ha_innobase::write_row           
              row_insert_for_mysql 
              row_insert_for_mysql_using_ins_graph 
              row_ins_step         
              row_ins              
            - row_ins_index_entry_step         
               - 3.33% row_ins_index_entry     
                    row_ins_clust_index_entry  
                  - row_ins_clust_index_entry_low  
                     - 1.34% btr_pcur_t::open  
                        - 1.34% btr_cur_search_to_nth_level               
                             0.87% page_cur_search_with_match             
                     - 1.26% btr_cur_pessimistic_insert                   
                          1.19% btr_page_split_and_insert                 
         + 0.52% TableScanIterator::Read       
     0.90% 0x7ffff7958793          
     0.69% unlikely                                           

可以看到除了上面第一點提到的索引分裂的影響外,還增加了頁分裂以及頁讀寫相關的 I/O 操作影響性能,寬表情況下對於讀寫性能比短數據更加依賴機器的性能和配置,並且會隨著寫入數據的增加降低寫入效率。

同樣的,看看單線程情況下寬表的 perf 情況。

+    8.05%     0.02%  mysqld   mysqld               [.] ut::Stateful_latching_rules<buf_io_fix, 3ul>::can_leave
+    7.95%     0.00%  mysqld   mysqld               [.] mutex_enter_inline<PolicyMutex<TTASEventMutex<GenericPolicy> > >
+    7.81%     0.03%  mysqld   [kernel.kallsyms]    [k] x64_sys_call      
-    7.50%     7.50%  mysqld   mysqld               [.] ut_delay          
   - 7.41% 0x7ffff7958793          
      - 7.36% std::thread::_State_impl<std::thread::_Invoker<std::tuple<Detached_thread, void (*)(unsigned long), unsigned long> > >::_M_run
           std::thread::_Invoker<std::tuple<Detached_thread, void (*)(unsigned long), unsigned long> >::operator()
           std::thread::_Invoker<std::tuple<Detached_thread, void (*)(unsigned long), unsigned long> >::_M_invoke<0ul, 1ul, 2ul> 
           std::__invoke<Detached_thread, void (*)(unsigned long), unsigned long>         
           std::__invoke_impl<void, Detached_thread, void (*)(unsigned long), unsigned long>  
           Detached_thread::operator()<void (*)(unsigned long), unsigned long>  
           std::_Bind<void (*(unsigned long))(unsigned long)>::operator()<, void>         
           std::_Bind<void (*(unsigned long))(unsigned long)>::__call<void, , 0ul>        
           std::__invoke<void (*&)(unsigned long), unsigned long&>        
         - std::__invoke_impl<void, void (*&)(unsigned long), unsigned long&> 
            - 7.34% io_handler_thread          
                 fil_aio_wait      
               - buf_page_io_complete          
                  - 5.01% buf_flush_write_complete 
                       mutex_enter_inline<PolicyMutex<TTASEventMutex<GenericPolicy> > >   
                       PolicyMutex<TTASEventMutex<GenericPolicy> >::enter 
                       TTASEventMutex<GenericPolicy>::enter               
                       TTASEventMutex<GenericPolicy>::spin_and_try_lock   
                       TTASEventMutex<GenericPolicy>::is_free             
                       ut_delay    
                  - 1.25% ibuf_merge_or_delete_for_page                   
                       ibuf_bitmap_get_map_page  
                       buf_page_get_gen        
                       Buf_fetch<Buf_fetch_normal>::single_page           
                       Buf_fetch<Buf_fetch_normal>::mtr_add_page          
                       rw_lock_x_lock_gen      
                       pfs_rw_lock_x_lock_func 
                       rw_lock_x_lock_func     
                       ut_delay    
                  - 1.08% mutex_enter_inline<PolicyMutex<TTASEventMutex<GenericPolicy> > >    
                       PolicyMutex<TTASEventMutex<GenericPolicy> >::enter 
                       TTASEventMutex<GenericPolicy>::enter               
                       TTASEventMutex<GenericPolicy>::spin_and_try_lock   
                       TTASEventMutex<GenericPolicy>::is_free             
                       ut_delay    
+    7.30%     0.04%  mysqld   mysqld               [.] buf_page_t::Latching_rules_helpers::assert_latches_let_distinguish 
+    4.37%     0.00%  mysqld   mysqld               [.] Fil_system::flush_file_spaces     
-    4.14%     3.88%  mysqld   mysqld               [.] unlikely                                                                                            
   - 2.75% start_thread            
        pfs_spawn_thread           
        handle_connection          
        do_command                 
        dispatch_command           
        dispatch_sql_command       
        mysql_execute_command      
        Sql_cmd_dml::execute       
        Sql_cmd_dml::execute_inner 
        Query_expression::execute  
      - Query_expression::ExecuteIteratorQuery 
         - 2.46% Query_result_insert::send_data  
              write_record         
              handler::ha_write_row            
              ha_innobase::write_row           
              row_insert_for_mysql 
              row_insert_for_mysql_using_ins_graph 
              row_ins_step         
            - row_ins              
               - 2.44% row_ins_index_entry_step  
                  - 2.41% row_ins_index_entry  
                       row_ins_clust_index_entry 
                     - row_ins_clust_index_entry_low                      
                        - 0.97% btr_pcur_t::open 
                           - btr_cur_search_to_nth_level                  
                                0.55% page_cur_search_with_match          
                        - 0.80% btr_cur_pessimistic_insert                
                             0.70% btr_page_split_and_insert              
   - 1.13% 0x7ffff7958793          
      - 1.02% std::thread::_State_impl<std::thread::_Invoker<std::tuple<Detached_thread, void (*)(unsigned long), unsigned long> > >::_M_run
           std::thread::_Invoker<std::tuple<Detached_thread, void (*)(unsigned long), unsigned long> >::operator() 
           std::thread::_Invoker<std::tuple<Detached_thread, void (*)(unsigned long), unsigned long> >::_M_invoke<0ul, 1ul, 2ul> 
           std::__invoke<Detached_thread, void (*)(unsigned long), unsigned long>         
           std::__invoke_impl<void, Detached_thread, void (*)(unsigned long), unsigned long>  
           Detached_thread::operator()<void (*)(unsigned long), unsigned long>  
           std::_Bind<void (*(unsigned long))(unsigned long)>::operator()<, void>         
           std::_Bind<void (*(unsigned long))(unsigned long)>::__call<void, , 0ul>        
           std::__invoke<void (*&)(unsigned long), unsigned long&>        
         - std::__invoke_impl<void, void (*&)(unsigned long), unsigned long&> 
            - 0.70% io_handler_thread          
               - fil_aio_wait      
                  - 0.65% buf_page_io_complete 
                       buf_flush_write_complete  
                       dblwr::write_complete   
                       Double_write::write_complete                       
                       fil_flush_file_spaces   
                       Fil_system::flush_file_spaces                      
                     - Fil_shard::flush_file_spaces                       
                        + 0.65% Fil_shard::acquire            
+    3.97%     0.58%  mysqld   mysqld               [.] Fil_shard::flush_file_spaces

對比多線程和單線程的堆棧信息,可以看到多線程下搶 I/O 資源情況變嚴重,同時索引分裂和頁分裂更嚴重,要花更多時間進行頁位置比較、計算數據占用的空間和插入,另外由於搶鎖導致多線程性能劣化更嚴重。

三、問題解決方案

通過上面分析發現,要想保證多線程插入速度比單線程快需要滿足一定的條件:

  1. 目標表有主鍵,當主鍵列沒有設置自增屬性的情況下,每個線程間的主鍵值需要是離散且單個線程內主鍵值需要連續,這是為了保證索引插入的性能最高。比如線程1主鍵值為[1-1000],線程2主鍵值為[10000-11000],線程3主鍵值為[30000-31000]這樣排列效率會比[1-3000]分三個線程高很多。
  2. 如果目標表主鍵是自增主鍵的話,因為無法定義自增主鍵的值,只能按照插入時候確定鍵值,因此自增主鍵會比非自增主鍵多線程離散值性能慢,但是因為自增主鍵持有的是區段鎖,因此不會頻繁持鎖方面性能又會比非自增主鍵好。實際使用的時候還是要看源表的數據分佈情況以及目標表結構來決定要怎麼分配多線程的插入主鍵值。
  3. 目標表是寬表時,從上面的測試數據來看單行數據超過 520Bytes 多線程就開始劣化了,因此多線程插入只針對窄表有效。

四、問題總結

一般我們都認為多線程插入數據肯定比單線程插入快,但是通過本次的測試和分析可以看到實際情況需要結合資料庫參數配置、索引、存儲頁以及磁碟的 I/O 性能等一起看,還要看源表主鍵值分佈情況和目標表的表結構,並不是所有多線程插入都能產生更好的效果節省時間,有時候反而可能多線程比單線程更耗時間以及資源。


Enjoy GreatSQL

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Oracle資料庫中如果標準大頁設置不合理,可能導致物理記憶體被浪費掉。下麵介紹一個案例: 查看標準大頁的信息,如下所示: $ grep HugePages /proc/meminfoAnonHugePages: 0 kBShmemHugePages: 0 kBFileHugePages: 0 kBH ...
  • 上一篇文章《使用 Categraf 快速建設 MySQL 監控,同時介紹夜鶯模板中心》我們已經瞭解瞭如何使用夜鶯配合 Categraf 監控 MySQL,本節我們重點看看 Redis 監控的實操方案。 Redis 監控資料 首先還是去模板中心找到 Redis 插件相關的說明和各類模板,菜單位置在:集 ...
  • 問題 MGR 中,新節點在加入時,為了與組內其它節點的數據保持一致,它會首先經歷一個分散式恢復階段。在這個階段,新節點會隨機選擇組內一個節點(Donor)來同步差異數據。 在 MySQL 8.0.17 之前,同步的方式只有一種,即基於 Binlog 的非同步複製,這種方式適用於差異數據較少或需要的 B ...
  • MDB (Lightning Memory-Mapped Database) 是一個高性能的嵌入式鍵值存儲資料庫,由Symas Corporation開發,並作為OpenLDAP項目的一部分發佈。LMDB被設計為輕量級、快速且可靠,適合在各種應用環境中使用,從伺服器端應用到移動設備和嵌入式系統。 L ...
  • 引言 隨著雲計算技術的發展,Amazon Web Services (AWS) 作為一個開放的平臺,一直在幫助開發者更好的在雲上構建和使用開源軟體,同時也與開源社區緊密合作,推動開源項目的發展。 本文主要探討2024年值得關註的一些開源軟體及其在AWS上的應用情況,希望能夠給大家參考使用! 2024 ...
  • 本文分享自天翼雲開發者社區《快照技術對比學習》,作者:z****n 1.快照的分類 根據 SNIA 的定義, 快照有全量快照 (full snapshot) 和增量快照 (incremental snapshot) 兩種類型。 2.全量快照 克隆(Clone): 與備份操作類似,克隆技術是一種數據復 ...
  • Zabbix監控 MS SqlServer2019 環境: Zabbix 7.0 LTS, sqlserver 2019 在mssql server的伺服器上安裝好agent2和插件: zabbix_agent2_plugins-7.0.0-windows-amd64.msi, 其中有mssql的必 ...
  • 前言 Oracle公司(甲骨文)是全球最大的信息管理軟體及服務供應商,成立於1977年,總部位於美國加州Redwood shore,面向全球開放oracle認證。 Oracle開發的關係資料庫產品因性能卓越而聞名,Oracle資料庫產品為財富排行榜上的前1000家公司所採用,許多大型網站也選用了Or ...
一周排行
    -Advertisement-
    Play Games
  • 前言 微服務架構已經成為搭建高效、可擴展系統的關鍵技術之一,然而,現有許多微服務框架往往過於複雜,使得我們普通開發者難以快速上手並體驗到微服務帶了的便利。為瞭解決這一問題,於是作者精心打造了一款最接地氣的 .NET 微服務框架,幫助我們輕鬆構建和管理微服務應用。 本框架不僅支持 Consul 服務註 ...
  • 先看一下效果吧: 如果不會寫動畫或者懶得寫動畫,就直接交給Blend來做吧; 其實Blend操作起來很簡單,有點類似於在操作PS,我們只需要設置關鍵幀,滑鼠點來點去就可以了,Blend會自動幫我們生成我們想要的動畫效果. 第一步:要創建一個空的WPF項目 第二步:右鍵我們的項目,在最下方有一個,在B ...
  • Prism:框架介紹與安裝 什麼是Prism? Prism是一個用於在 WPF、Xamarin Form、Uno 平臺和 WinUI 中構建鬆散耦合、可維護和可測試的 XAML 應用程式框架 Github https://github.com/PrismLibrary/Prism NuGet htt ...
  • 在WPF中,屏幕上的所有內容,都是通過畫筆(Brush)畫上去的。如按鈕的背景色,邊框,文本框的前景和形狀填充。藉助畫筆,可以繪製頁面上的所有UI對象。不同畫筆具有不同類型的輸出( 如:某些畫筆使用純色繪製區域,其他畫筆使用漸變、圖案、圖像或繪圖)。 ...
  • 前言 嗨,大家好!推薦一個基於 .NET 8 的高併發微服務電商系統,涵蓋了商品、訂單、會員、服務、財務等50多種實用功能。 項目不僅使用了 .NET 8 的最新特性,還集成了AutoFac、DotLiquid、HangFire、Nlog、Jwt、LayUIAdmin、SqlSugar、MySQL、 ...
  • 本文主要介紹攝像頭(相機)如何採集數據,用於類似攝像頭本地顯示軟體,以及流媒體數據傳輸場景如傳屏、視訊會議等。 攝像頭採集有多種方案,如AForge.NET、WPFMediaKit、OpenCvSharp、EmguCv、DirectShow.NET、MediaCaptre(UWP),網上一些文章以及 ...
  • 前言 Seal-Report 是一款.NET 開源報表工具,擁有 1.4K Star。它提供了一個完整的框架,使用 C# 編寫,最新的版本採用的是 .NET 8.0 。 它能夠高效地從各種資料庫或 NoSQL 數據源生成日常報表,並支持執行複雜的報表任務。 其簡單易用的安裝過程和直觀的設計界面,我們 ...
  • 背景需求: 系統需要對接到XXX官方的API,但因此官方對接以及管理都十分嚴格。而本人部門的系統中包含諸多子系統,系統間為了穩定,程式間多數固定Token+特殊驗證進行調用,且後期還要提供給其他兄弟部門系統共同調用。 原則上:每套系統都必須單獨接入到官方,但官方的接入複雜,還要官方指定機構認證的證書 ...
  • 本文介紹下電腦設備關機的情況下如何通過網路喚醒設備,之前電源S狀態 電腦Power電源狀態- 唐宋元明清2188 - 博客園 (cnblogs.com) 有介紹過遠程喚醒設備,後面這倆天瞭解多了點所以單獨加個隨筆 設備關機的情況下,使用網路喚醒的前提條件: 1. 被喚醒設備需要支持這WakeOnL ...
  • 前言 大家好,推薦一個.NET 8.0 為核心,結合前端 Vue 框架,實現了前後端完全分離的設計理念。它不僅提供了強大的基礎功能支持,如許可權管理、代碼生成器等,還通過採用主流技術和最佳實踐,顯著降低了開發難度,加快了項目交付速度。 如果你需要一個高效的開發解決方案,本框架能幫助大家輕鬆應對挑戰,實 ...