MySQL中2個select被阻塞場景的原因
第一種情況: 執行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部落格 ” ,連結:http://blog.itpub.net/25719946/viewspace-2899813/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL 由於MDL讀鎖select被阻塞MySql
- MySQL 中如何定位 DDL 被阻塞的問題MySql
- 【Mysql】MySQL 5.6中如何定位DDL被阻塞的問題MySql
- MySQL 5.6中如何定位DDL被阻塞的問題MySql
- SQL Server中的SELECT會阻塞SELECT相關資料SQLServer
- Oracle中查詢阻塞與被阻塞SID的方法Oracle
- android手機安全:被攻陷的一個場景Android
- 模擬RI鎖定導致阻塞的場景
- MySQL單表模擬鎖的幾個場景MySql
- django ORM 中 select_related 與 prefetch_related 的使用場景DjangoORM
- 在jsavaScript中設定select的某個選項被選中JS
- JS 中 this 在各個場景下的指向JS
- MySql 中 select 使用MySql
- 解決一個C#中定時任務被阻塞問題C#
- spring事務失效的幾種場景以及原因Spring
- 需要恢復中斷狀態的一個場景
- MySQL和Elasticsearch使用場景MySqlElasticsearch
- 解析MySQL中INSERT INTO SELECT的使用MySql
- 查詢阻塞與被阻塞SQL語句SQL
- 【mysql】mysql select中包括計算公式MySql公式
- docker Redis 被挖礦場景復現DockerRedis
- Redis 中 BitMap 的使用場景Redis
- SQLServer DML操作阻塞SELECT查詢SQLServer
- Bash 中為 _ 變數賦空值的三個場景變數
- 不同場景下 MySQL 的遷移方案MySql
- JQuery 獲取select被選中的value和textjQuery
- 關於電梯阻塞原因的小思考
- sudo命令使用的幾個場景
- 遊戲場景中的光影設計遊戲
- Unity製作遊戲中的場景Unity遊戲
- 在Unity中快速搭建一個3A級別的場景Unity
- QTP中為什麼恢復場景(Recovery Scenario)沒有被觸發?QT
- HHMySQL?中定位?DDL?被阻塞的問題及解決方案xmwMySql
- [原]不同場景下MySQL的遷移方案MySql
- mysql與redis的區別與使用場景MySqlRedis
- mysql 聯合索引的兩種特殊場景MySql索引
- MySQL表結構變更引起的Metadata Lock|如何定位DDL被阻塞MySql
- mysql 連線超慢的一個原因MySql