独家揭秘丨GreatSQL 没开Binlog时多线程插入数据性能劣化之谜

GreatSQL与MySQL性能对比测试,带您一同探索数据库的速度差异 在选择适合自己的数据库时,性能是一个至关重要的考虑因素。本文将介绍GreatSQL和MySQL两个常见的关系型数据库,并通过性能测试来比较它们之间的速度差异。除了查询性能之外,我们还可以比较GreatSQL和MySQL在插入和更新操作方面的性能差异。除了查询性能之外,我们还可以比较GreatSQL和MySQL在插入和更新操作方面的性能差异。然后,我们分别在GreatSQL和MySQL中执行了一个查询,并记录了执行时间。然后,我们分别在GreatSQL和MySQL中执行了一个查询,并记录了执行时间。 阅读详情

一、问题发现

在一次数据迁移中,用到了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;21 min 15.45 sec
1000万行insert into t2 select * from t1;655.74 sec
1000万行insert into t2 select * from t1;1045.34 sec
1000万行insert into t2 select * from t1;1643.78 sec最佳
1000万行insert into t2 select * from t1;21 min 11.62 sec
1000万行insert into t2 select * from t1;61 min 2.53 sec
1000万行insert into t2 select * from t1;101 min 0.55 sec
1000万行insert into t2 select * from t1;1655.46 sec
1000万行insert into t2 select * from t1;21 min 24.13 sec
1000万行insert into t2 select * from t1;61 min 14.43 sec
1000万行insert into t2 select * from t1;101 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;24 min 36.58 sec效率无提升
1000万行insert into t2 select * from t1;64 min 46.58 sec效率无提升
1000万行insert into t2 select * from t1;104 min 50.43 sec效率无提升
1000万行insert into t2 select * from t1;24 min 26.28 sec效率无提升
1000万行insert into t2 select * from t1;64 min 38.84 sec效率无提升
1000万行insert into t2 select * from t1;104 min 49.42 sec效率无提升
1000万行insert into t2 select * from t1;24 min 25.67 sec效率无提升
1000万行insert into t2 select * from t1;64 min 40.42 sec效率无提升
1000万行insert into t2 select * from t1;104 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;24 min 52.36 sec性能劣化
100万行insert into t2 select * from t1;24 min 52.31 sec性能劣化
100万行insert into t2 select * from t1;65 min 36.07 sec性能劣化
100万行insert into t2 select * from t1;24 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;21 min 38.84 sec性能劣化
1000万行insert into t2 select * from t1;62 min 18.88 sec性能劣化
1000万行insert into t2 select * from t1;102 min 14.51 sec性能劣化
1000万行insert into t2 select * from t1;21 min 35.96 sec性能劣化
1000万行insert into t2 select * from t1;62 min 3.55 sec性能劣化
1000万行insert into t2 select * from t1;102 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 :)

关于 GreatSQL

GreatSQL是适用于金融级应用的国内自主开源数据库,具备高性能、高可靠、高易用性、高安全等多个核心特性,可以作为MySQL或Percona Server的可选替换,用于线上生产环境,且完全免费并兼容MySQL或Percona Server。

相关链接: GreatSQL社区 Gitee GitHub Bilibili

GreatSQL社区:

image

社区有奖建议反馈: https://greatsql.cn/thread-54-1-1.html

社区博客有奖征稿详情: https://greatsql.cn/thread-100-1-1.html

(对文章有疑问或者有独到见解都可以去社区官网提出或分享哦~)

技术交流群:

微信&QQ群:

QQ群:533341697

微信群:添加GreatSQL社区助手(微信号:wanlidbc )好友,待社区助手拉您进群。

科技中介服务机构如何利用数智工具提升服务效率?.docx 科技中介服务机构如何利用数智工具提升服务效率? 立即下载

相关推荐

基于非对称纳什谈判的多微网电能共享运行优化策略(Matlab代码实现)

基于非对称纳什谈判的多微网电能共享运行优化策略(Matlab代码实现)内容概要:本文档标题为《Plecs全桥LLC谐振变换器仿真模型.txt》,但实际上内容并未围绕Plecs或全桥LLC谐振变换器展开详细论述,而是罗列了大量基于Matlab/Simulink和Python的科研仿真项目标题及相关技术方向,涵盖电力系统、无人机控制、微电网优化、路径规划、状态估计、信号处理、电动汽车调度、电力电子变换器等多个领域。其中包括多种优化算法(如粒子群、遗传算法、NSGA-II)、控制策略(如PID、MPC、滑模控制)、仿真建模(如LLC谐振变换器、DAB变换器、PWM整流器)以及具体应用场景的研究实现。尽管提及“隔离型全桥LLC谐振变换器建模及参数设计资料”,但全文缺乏对该主题的具体描述、模型细节或仿真分析,仅作为条目之一出现。因此,该文档实质是一份科研项目资源清单或代码合集目录,而非针对某一主题的深入文章。; 适合人群:具备一定Matlab/Simulink或Python编程基础,从事电气工程、自动化、控制科学、电力电子、新能源系统等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①为科研工作者提供丰富的课题参考与复现资源,涵盖优化调度、控制系统设计、电力电子仿真等方向;②辅助完成硕士/博士论文、期刊论文复现、课程设计或项目开发,提升研究效率与创新性;③通过已有模型和代码快速搭建仿真平台,聚焦算法改进与性能优化。; 阅读建议:此文档应作为科研资源索引使用,读者可根据自身研究方向筛选相关条目,结合配套代码与参考资料进行深入学习与实践。对于希望研究全桥LLC谐振变换器的用户,需注意本文档未提供完整内容,建议查找标注的“仿真+设计报告+计算书”等附件资源以获取详细信息。

mysql kill 不掉_内核分析之mysql诡异重启故障

1.前言如果mysql实例连接数满掉了,脑袋里蹦出的第一个想法是先增大max_connection,但有种情况,解决方案却是减少max_connection。2.冰中火看看这张图:各位看完后一定很愤怒,CPU Util,CPU Load,磁盘IO和网络IO指标都很低,毫无性能压力的服务器指标,有啥好看的(其实是有指标异常的)。冰块中的火别急,在毫无波澜的服务器上,mysql实例内部已经翻...

weixin_39753747的博客 399

高校技术转移办公室在推动成果转化过程中,如何高效完成技术成果的信息整合与价值挖掘.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

mysql gen lock_MySQL代码学习第十——跟踪rw_lock收集更多需求

跟踪一把rw_lock方面的代码。[root@localhost source]# more gdb.rw_lockset height unlimitedb rw_lock_s_lock_func(rw_lock_t*, unsigned long, char const*, unsigned long)b rw_lock_s_unlock_func(ulint, rw_lock_t*)b rw...

weixin_35417196的博客 248

高校技术转移办公室人员,如何精准挖掘并分析企业的技术需求?.docx

科易网基于AI模型+行业大数据,在技术转移、成果转化、技术经纪、知识产权、产业创新、科技招商等垂直领域的多样化应用场景,推出科技创新领域的AI+工具与数智化解决方案,推动科技创新与产业创新智能化发展。

隔离型全桥LLC谐振变化器建模及参数设计资料【仿真+设计报告+计算书】

内容概要:本文档是一套关于隔离型全桥LLC谐振变换器的综合性技术资料,系统涵盖了拓扑建模、参数设计、闭环控制策略及仿真验证等关键环节。资料整合了Simulink仿真模型、详细设计报告、Mathcad计算书以及控制算法说明文档,深入探讨了恒压恒流双闭环控制、变频与移相混合控制、软启动机制等核心技术,并提供了多应用场景实例,包括双向全桥LLC、多相交错LLC以及电动汽车V2G系统中的CLLC变换器设计。此外,配套资源还包含了多种先进控制与状态估计算法(如EKF、UKF、PF及其与神经网络融合算法)的Matlab实现代码,强化了科研复现与工程实践能力。; 适合人群:适用于电气工程、电力电子及相关专业的研究生、科研人员,以及从事高频开关电源、新能源变换器开发的工程师;需具备扎实的电路理论基础与一定的仿真软件操作经验。; 使用场景及目标:①支持全桥LLC变换器的高效参数设计与动态性能优化;②服务于高校或企业的科研项目,助力拓扑创新与控制系统开发;③作为毕业设计、学术论文或工业级产品原型开发的重要技术参考,提升系统效率、稳定性和响应速度。; 阅读建议:建议结合Simulink仿真模型与Mathcad计算书同步学习,重点关注谐振元件匹配、控制环路设计与系统稳定性分析,充分利用提供的Matlab/Simulink环境进行仿真调试与二次开发,深化理论认知与实际工程应用的融合。

linux rwlock 读写锁实现

inux 内核中的rwlock类型的读写锁是基于spinlock来实现的。 读写锁具有如下特性: 允许多个读者同时进入临界区,但同一时刻写者不能进入。 同一时刻只允许一个写者进入临界区。 读者和写者不能同时进入临界区。

Amelio Ming 575

顺序功能图基本结构

顺序功能图(Sequential Function Chart,SFC)是一种用于描述工业控制系统中顺序控制流程的图形化编程语言,广泛应用于PLC(可编程逻辑控制器)编程。其核心思想是将复杂的控制流程分解为多个有序的步骤,通过逻辑条件实现步骤间的切换。顺序功能图通过图形化的方式简化了复杂控制逻辑的设计,尤其适用于需要严格顺序控制的工业自动化场景。[初始步] → 转换条件1 → [步1] → 转换条件2 → [步2] → ...[步X] → → [步B] → 转换条件B → → [合并步]

ayingqin1的博客 1226

MySQL truncate导致慢查询根因竟然是“多此一举”

trucate为什么会导致慢查询?居然是因为多此一举!多少线上故障,皆付笑谈中。。。

postgres20的博客 2389

XR Interaction Toolkit实战:为HTC Vive Cosmos打造抓取、投掷与UI交互(Unity 2023教程)

本文详细介绍了如何使用Unity 2023和XR Interaction Toolkit为HTC Vive Cosmos开发抓取、投掷与UI交互系统。通过实战案例'VR投掷训练室',从基础配置到高级功能实现,涵盖物理抓取、精准投掷机制和VR UI交互设计,帮助开发者提升VR交互开发技能。

weixin_30562507的博客 255

内窥镜胶囊(胶囊内镜)硬件方案

内窥镜胶囊(胶囊内镜)硬件方案 前言 说明:该方案为作者2018年上半年完成的第一版,后来搁置了一段时间,才重启这个项目。目前(2020.07)第二版已经快要完成。[联系v:1#7#6#3#3#3#5#0#8#7#0]先给一下第一版和第二版的基本参数。 第一版: 续航时间:3h 帧率:0.5fps 尺寸:12mm * 25mm 角度:45° 第二版: 续航时间:12h 帧率:2-6fps 尺寸:9.8mm * 25mm 角度:130° 第一版属于尝试版,整体方案不是很成熟。第二版这个数据就非常优秀了。我拿了

CrekerLi的博客 4780

Linux内核同步机制之(七):RCU基础

http://www.wowotech.net/kernel_synchronization/rcu_fundamentals.html 一、前言 关于RCU的文档包括两份,一份讲基本的原理(也就是本文了),一份讲linux kernel中的实现。第二章描述了为何有RCU这种同步机制,特别是在cpu core数目不断递增的今天,一个性能更好的同步机制是如何解决问题的,当然,再好的工

zdy0_2004的专栏 1221

RIGOL DS1102E示波器新手必看:从开机到捕获第一个波形的5分钟指南

本文为RIGOL DS1102E示波器新手提供了一份快速上手指南。内容涵盖从开机、探头校准到捕获第一个波形的完整流程,重点解析了触发设置、自动测量等核心操作,并指出了探头衰减比设置等常见误区,帮助用户快速掌握这款经典数字示波器的基本使用方法。

dream的博客 740

【Linux内核】RW读写锁机制

Linux内核中读写锁的机制是一种多读单写的锁机制,它允许多个读操作同时进行,但只能有一个写操作进行。当有写操作时,所有读操作都会被阻塞,直到写操作完成。rwlock_t:这个结构体定义了一个读写锁对象,它包含了锁状态、等待队列等信息。:这个结构体定义了一个读写信号量,它用于控制读写操作的并发性。内核中的读写锁被广泛地应用在文件系统、网络协议栈、设备驱动等各个子系统中,例如在文件系统中,读写锁用于保护文件的读写操作,以确保同一时间只有一个线程可以写入文件,而多个线程可以同时读取文件。

逆风水手的博客 1056

Agentic AI为教育行业赋能,提示工程架构师解析应用潜力

然而,即便是最先进的 LLMs,在面对复杂、动态、需要持续规划和调整的教育场景时,也常常显得力不从心,它们更像是强大的“问答机器”,而非真正意义上的“学习伙伴”或“教学助手”。在教育场景中,传统的 AI 工具可能只能回答学生提出的特定问题,或者根据预设的规则推送一些学习材料。无论您是教育技术领域的开发者、产品经理,还是一线的教育工作者、教育管理者,抑或是对 AI 教育应用充满好奇的研究者,本文都将为您提供宝贵的 insights,助您把握 Agentic AI 时代教育创新的脉搏。

架构师的AI之路,分享AI应用开发架构的学习与实践。 466

OPC通信从入门到精通_1_OPC基础知识及简单C#程序编写(OPCDA,OPCUA简介;OPC通信数据流框架图;C#程序编写)

ModbusTCP通信是采用直接方式进行通信,用OPC的方式如何去做呢?PLC作为ModbusTCP服务器,用KepServer作为ModbusTCP客户端,同时作为OPC服务器,PC作为OPC客户端新建项目,加载dll库(利用COM技术写的)添加引用,查看到其中包含了众多方法其中OPCGroups继承于IOPCGroups接口。

分享学习成长历程,Winter is coming! 1万+

MySQL Page读取和淘汰过程分析

目录 Page磁盘读取过程 申请空闲PAGE空间 刷脏页和LRU链表 Page内存读取和Page淘汰的互斥 Page磁盘读取过程 buf_page_get_gen | | ==> rw_lock_s_lock(hash_lock); | | ==> block = (buf_block_t*) buf_page_hash_get_low(buf_pool, s...

duxingxia356的专栏 1269

在 SAP HANA 里为视图创建 Analytic Privilege,真正把同一份数据按角色切开

摘要:本文介绍了SAP HANA中基于业务角色的动态数据权限控制方法。通过Analytic Privilege技术,可以在同一视图上为不同角色设置不同的数据访问范围,实现行级安全控制。核心机制包括:1) 创建带有STRUCTURED PRIVILEGE CHECK的视图;2) 建立授权对象和用户映射表;3) 开发条件提供过程动态生成过滤条件;4) 创建结构化权限对象绑定条件提供器。这种设计使权限规则与业务数据解耦,便于维护变更,适合销售区域、财务数据等多角色访问控制场景。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 2392

mysql 申请读锁 再申请写锁_MySQL源代码:如何对读写锁进行处理

2.加锁加锁函数由宏定义,实际调用函数为:1)写锁[cpp]#definerw_lock_x_lock(M)\rw_lock_x_lock_func((M),0,__FILE__,__LINE__)当申请写锁时,执行如下步骤:(1).调用rw_lock_x_lock_low函数去获取锁,如果得到锁,则rw_...

weixin_36245388的博客 259

零基础DSP实战TMS320F28035:第九节,ADC比较器&EPWM

ADC比较器框图如下所示:-电压-----------------------------输出-电压A>电压B------------------ 1-电压A

sinat_30943509的博客 2535

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

MySQL系列:innodb源码分析之线程并发同步机制

innodb是一个多线程并发的存储引擎,内部的读写都是用多线程来实现的,所以innodb内部实现了一个比较高效的并发同步机制。innodb并没有直接使用系统提供的锁(latch)同步结构,而是对其进行自己的封装和实现优化,但是也兼容系统的锁。我们先看一段innodb内部的注释(MySQL-3.23): Semaphore operations in operating systems are s

zerok的专栏 6894

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Mysql同步机制—自旋互斥锁

参考:《mysql内核:innodb存储引擎》 第三章 淘宝内核月报:MySQL · 引擎特性 · InnoDB 同步机制 :http://mysql.taobao.org/monthly/2017/01/01/ MySQL源代码:如何对读写锁进行处理:https://blog.youkuaiyun.com/zhaiwx1987/article/details...

翔之天空的专栏 932

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

MySQL源代码:如何对读写锁进行处理

转载请署名:印风 ----------------------------------------------------------- 最近碰到一个问题,线上一台机器在等待信号量时间过长,mysql的监控线程认为此时mysqld已经hang住了,于是自杀重启。这里涉及到一个有趣的问题,也就是mysql如何对读写锁进行处理。 主要包括三个部分: 1. 建锁 2. 加锁 3. 解锁 4

记录成长之路 5667

mysql创建读写锁命令_MySQL源代码:如何对读写锁进行处理

看起来实际的加锁和解锁操作是通过对计数器来控制的,(1)在函数rw_lock_s_lock_low中rw_lock_lock_word_decr (lock, 1),对lock->lock_word减去1减数成功返回true,否则返回false这部分的逻辑还是很简单的。(2)在函数rw_lock_x_lock_low中,调用:rw_lock_lock_word_decr(lock, X_LO...

weixin_42659194的博客 313

转: Linux spinlock_t

我的经验:如果出现死锁的情况,检查:1. lock 和 unlock是否成对出现了,检查所有的程序分支。2.是否有同时需要2个和2个以上的锁的情况,避免掉这种情况。3.如果在timer等软中断中出现死锁,可能是没有使用spin_lock_bh这一类的锁。reference: http://www.chinaitpower.com/2005September/2005-09-13/200...

weixin_30877181的博客 676
上一篇: GreatSQL 构建高效 HTAP 服务架构指南(主从复制)
下一篇: GreatSQL 构建高效 HTAP 服务架构指南(MGR)
GreatSQL社区
博客等级 码龄5年 1210粉丝 390原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值