ITPub博客

首页 > 数据库 > MySQL > MySQL中2个select被阻塞场景的原因

MySQL中2个select被阻塞场景的原因

原创 MySQL 作者:aoerqileng 时间:2022-06-10 12:15:09 0 删除 编辑

第一种情况: 执行select,慢查询,然后对表alter,被阻塞,然后其他会话执行select,被阻塞


当最后的select被阻塞时,在

open_table_get_mdl_lock中会去获取锁,先 try_acquire_lock_impl获取,成功返回,不成功向等待队列加个ticket,进入等待
mysqld!open_table_get_mdl_lock(THD*, Open_table_context*, TABLE_LIST*, unsigned int, MDL_ticket**) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:2680)
mysqld!open_table(THD*, TABLE_LIST*, Open_table_context*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:3058)
mysqld!open_and_process_table(THD*, LEX*, TABLE_LIST*, unsigned int*, Prelocking_strategy*, bool, Open_table_context*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:5018)
mysqld!open_tables(THD*, TABLE_LIST**, unsigned int*, unsigned int, Prelocking_strategy*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:5805)
mysqld!open_tables_for_query(THD*, TABLE_LIST*, unsigned int) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:6678)
mysqld!Sql_cmd_dml::prepare(THD*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_select.cc:363)
mysqld!Sql_cmd_dml::execute(THD*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_select.cc:559)
mysqld!mysql_execute_command(THD*, bool) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_parse.cc:4407)
mysqld!dispatch_sql_command(THD*, Parser_state*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_parse.cc:4988)
mysqld!dispatch_command(THD*, COM_DATA const*, enum_server_command) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_parse.cc:1836)
mysqld!do_command(THD*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_parse.cc:1320)
mysqld!handle_connection(void*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/conn_handler/connection_handler_per_thread.cc:301)
mysqld!pfs_spawn_thread(void*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/storage/perfschema/pfs.cc:2900)
libsystem_pthread.dylib!_pthread_start (Unknown Source:0)
libsystem_pthread.dylib!thread_start (Unknown Source:0)



第二种场景

第一个会话执行慢查询,第二个执行flush tables with read lock,第三个会话继续执行查询


原因是第三个被阻塞在下面的函数

tdc_wait_for_old_version
mysql_mutex_lock(&LOCK_open);
if ((share = get_cached_table_share(db, table_name)) &&
share->has_old_version()) {
struct timespec abstime;
set_timespec(&abstime, wait_timeout);
res = share->wait_for_old_version(thd, &abstime, deadlock_weight);
}
mysql_mutex_unlock(&LOCK_open);
return res;


下面的version()是在table share中获取的version,第一个select执行后没有变,refresh_version是在函数close_cached_tables中增加的,每次flush tables with read lock,都会调用。所以导致下面的判断认为存在老版本,导致第三个回话进入share->wait_for_old_version 等待中

bool has_old_version() const { return version() != refresh_version; }


等待的堆栈如下:

mysqld!tdc_wait_for_old_version(THD*, char const*, char const*, unsigned long, unsigned int) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:2717)
mysqld!open_table(THD*, TABLE_LIST*, Open_table_context*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:3303)
mysqld!open_and_process_table(THD*, LEX*, TABLE_LIST*, unsigned int*, Prelocking_strategy*, bool, Open_table_context*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:5018)
mysqld!open_tables(THD*, TABLE_LIST**, unsigned int*, unsigned int, Prelocking_strategy*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:5805)
mysqld!open_tables_for_query(THD*, TABLE_LIST*, unsigned int) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_base.cc:6678)
mysqld!Sql_cmd_dml::prepare(THD*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_select.cc:363)
mysqld!Sql_cmd_dml::execute(THD*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_select.cc:559)
mysqld!mysql_execute_command(THD*, bool) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_parse.cc:4407)
mysqld!dispatch_sql_command(THD*, Parser_state*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_parse.cc:4988)
mysqld!dispatch_command(THD*, COM_DATA const*, enum_server_command) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_parse.cc:1836)
mysqld!do_command(THD*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/sql_parse.cc:1320)
mysqld!handle_connection(void*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/sql/conn_handler/connection_handler_per_thread.cc:301)
mysqld!pfs_spawn_thread(void*) (/Users/xiaoyu.bai/Downloads/mysql-8.0.23/storage/perfschema/pfs.cc:2900)
libsystem_pthread.dylib!_pthread_start (Unknown Source:0)
libsystem_pthread.dylib!thread_start (Unknown Source:0)


refresh_version的刷新是不是能放到后面,获取锁成功后在刷,这样就不会阻塞select了。

有兴趣学习源码的加群一起学习啊 QQ:  700072075

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/25719946/viewspace-2899813/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
二手知识受害者

注册时间:2011-11-02

  • 博文量
    68
  • 访问量
    47730