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】MySQL 5.6中如何定位DDL被阻塞的問題MySql
- MySQL 中如何定位 DDL 被阻塞的問題MySql
- MySQL 5.6中如何定位DDL被阻塞的問題MySql
- SQL Server中的SELECT會阻塞SELECT相關資料SQLServer
- django ORM 中 select_related 與 prefetch_related 的使用場景DjangoORM
- MySql 中 select 使用MySql
- 解析MySQL中INSERT INTO SELECT的使用MySql
- SQLServer DML操作阻塞SELECT查詢SQLServer
- JS 中 this 在各個場景下的指向JS
- spring事務失效的幾種場景以及原因Spring
- JQuery 獲取select被選中的value和textjQuery
- 解決一個C#中定時任務被阻塞問題C#
- 【Mysql原理與實踐】2020-08-03-景羅-MySQL中select count(col) 底層實現探索MySql
- MySQL表結構變更引起的Metadata Lock|如何定位DDL被阻塞MySql
- MySQL和Elasticsearch使用場景MySqlElasticsearch
- 一個 Pipeline 的使用場景
- mysql select稽核MySql
- 使用 strace 查詢 Emacs 啟動阻塞的原因Mac
- docker Redis 被挖礦場景復現DockerRedis
- 使用select,兩個case 讀取 同一個chan 中的資料,兩個case都可能被執行到
- 盤點MySQL慢查詢的12個原因MySql
- Redis 中 HyperLogLog 的使用場景Redis
- Redis 中 BitMap 的使用場景Redis
- HHMySQL?中定位?DDL?被阻塞的問題及解決方案xmwMySql
- mysql 聯合索引的兩種特殊場景MySql索引
- [原]不同場景下MySQL的遷移方案MySql
- mysql與redis的區別與使用場景MySqlRedis
- Redis學習五(Redis 阻塞的原因及其排查方向).Redis
- MySQL資料SQL優化中,索引不被使用的典型場景總結MySql優化索引
- 故障分析 | MySQL 使用 load data 匯入資料錯誤的一個場景MySql
- MySQL系列:索引失效場景總結MySql索引
- 在Unity中快速搭建一個3A級別的場景Unity
- linux非阻塞式socket程式設計之select()用法Linux程式設計
- 記一次ios系統select標籤第一個選項不能被選中的bugiOS
- 學習MySQL的select語句MySql
- mysql insert into ... select的鎖問題MySql
- MySQL 留存率和復購率的場景分析MySql