為什麼MySQL沒有負載,但交易卻跑不動?
來源:oracleace
關於號主,姚遠:
Oracle ACE(Oracle和MySQL資料庫方向)
華為雲最有價值專家
《MySQL 8.0運維與最佳化》的作者
擁有 Oracle 10g、12c和19c OCM等數十項資料庫認證
曾任IBM公司資料庫部門經理
20+年DBA經驗,服務2萬+客戶
精通C和Java,發明兩項計算機專利
5.7版本中查詢鎖競爭
在MySQL 8.0 之前,必須SET GLOBAL innodb_status_output_locks=ON後才能在SHOW ENGINE INNODB STATUS中查到資料鎖,例如下面這個事務:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 where intcol1=0 for update;
...
900 rows in set (0.00 sec)
在SHOW ENGINE INNODB STATUS中查到
---TRANSACTION 7827, ACTIVE 11 sec
222 lock struct(s), heap size 24784, 5720 row lock(s)
MySQL thread id 9912, OS thread handle 139967683151616, query id 11123 localhost root
TABLE LOCK table `mysqlslap`.`t1` trx id 7827 lock mode IX
RECORD LOCKS space id 25 page no 37 n bits 1056 index in_1 of table `mysqlslap`.`t1` trx id 7827 lock_mode X
...
修改了900行,卻鎖住了5720行。查詢space id為25對應的物件:
mysql> select * from information_schema.INNODB_SYS_DATAFILES where space=25;+-------+--------------------+| SPACE | PATH |+-------+--------------------+| 25 | ./mysqlslap/t1.ibd |+-------+--------------------+1 row in set (0.00 sec)
在另外一個session裡執行
mysql> update t1 set intcol1=1 where intcol1=0;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
查詢鎖的情況
mysql> select * from information_schema.innodb_lock_waits;
+-------------------+-------------------+-----------------+------------------+
| requesting_trx_id | requested_lock_id | blocking_trx_id | blocking_lock_id |
+-------------------+-------------------+-----------------+------------------+
| 7829 | 7829:25:4:2 | 7827 | 7827:25:4:2 |
+-------------------+-------------------+-----------------+------------------+
1 row in set, 1 warning (0.00 sec)
mysql> select * from information_schema.innodb_locks;
+-------------+-------------+-----------+-----------+------------------+-----------------+------------+-----------+----------+----------------+
| lock_id | lock_trx_id | lock_mode | lock_type | lock_table | lock_index | lock_space | lock_page | lock_rec | lock_data |
+-------------+-------------+-----------+-----------+------------------+-----------------+------------+-----------+----------+----------------+
| 7829:25:4:2 | 7829 | X | RECORD | `mysqlslap`.`t1` | GEN_CLUST_INDEX | 25 | 4 | 2 | 0x000000000200 |
| 7827:25:4:2 | 7827 | X | RECORD | `mysqlslap`.`t1` | GEN_CLUST_INDEX | 25 | 4 | 2 | 0x000000000200 |
+-------------+-------------+-----------+-----------+------------------+-----------------+------------+-----------+----------+----------------+
2 rows in set, 1 warning (0.00 sec)
查詢阻塞的執行緒:
SELECT b.trx_mysql_thread_id AS 'blocked_thread_id'
,b.trx_query AS 'blocked_sql_text'
,c.trx_mysql_thread_id AS 'blocker_thread_id'
,c.trx_query AS 'blocker_sql_text'
,( Unix_timestamp() - Unix_timestamp(c.trx_started) )
AS 'blocked_time'
FROM information_schema.innodb_lock_waits a
INNER JOIN information_schema.innodb_trx b
ON a.requesting_trx_id = b.trx_id
INNER JOIN information_schema.innodb_trx c
ON a.blocking_trx_id = c.trx_id
WHERE ( Unix_timestamp() - Unix_timestamp(c.trx_started) ) > 4;
+-------------------+-----------------------------------------+-------------------+------------------+--------------+
| blocked_thread_id | blocked_sql_text | blocker_thread_id | blocker_sql_text | blocked_time |
+-------------------+-----------------------------------------+-------------------+------------------+--------------+
| 9921 | update t1 set intcol1=1 where intcol1=0 | 9917 | NULL | 782 |
+-------------------+-----------------------------------------+-------------------+------------------+--------------+
1 row in set, 1 warning (0.00 sec)
根據執行緒號查詢執行的SQL
SELECT a.sql_text,
c.id,
d.trx_started
FROM performance_schema.events_statements_current a
join performance_schema.threads b
ON a.thread_id = b.thread_id
join information_schema.processlist c
ON b.processlist_id = c.id
join information_schema.innodb_trx d
ON c.id = d.trx_mysql_thread_id
where c.id=9917
ORDER BY d.trx_started\G
*************************** 1. row ***************************
sql_text: select * from t1 where intcol1=0 for update
id: 9917
trx_started: 2023-05-26 13:24:59
1 row in set (0.00 sec)
解決鎖競爭
mysql> create index in_1 on t1(intcol1);
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table t1\G
*************************** 1. row ***************************
Table: t1
Create Table: CREATE TABLE `t1` (
`intcol1` int(32) DEFAULT NULL,
`intcol2` int(32) DEFAULT NULL,
`charcol1` varchar(128) DEFAULT NULL,
`charcol2` varchar(128) DEFAULT NULL,
`charcol3` varchar(128) DEFAULT NULL,
KEY `in_1` (`intcol1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
再鎖住同樣的行
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t1 where intcol1=0 for update;
...
900 rows in set (0.00 sec)
在SHOW ENGINE INNODB STATUS中查到
---TRANSACTION 7841, ACTIVE 15 sec
155 lock struct(s), heap size 24784, 1801 row lock(s)
MySQL thread id 9917, OS thread handle 139966608627456, query id 11227 localhost root
TABLE LOCK table `mysqlslap`.`t1` trx id 7841 lock mode IX
RECORD LOCKS space id 25 page no 37 n bits 1056 index in_1 of table `mysqlslap`.`t1` trx id 7841 lock_mode X
...
被鎖住的記錄從之前的5720條減少到1801條。
有索引後執行計劃也不同,加索引之前的執行計劃
mysql> explain select * from t1 where intcol1=0 for update;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | t1 | NULL | ALL | NULL | NULL | NULL | NULL | 6143 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
加了索引後的執行計劃是:
mysql> explain select * from t1 where intcol1=0 for update;
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | SIMPLE | t1 | NULL | ref | in_1 | in_1 | 5 | const | 900 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
8.0版本
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70027826/viewspace-2991976/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 為什麼我寫了路由懶載入但程式碼卻沒有分割?路由
- 為什麼說Docker 不適合跑 MySQL?DockerMySql
- MySQL Connectors為什麼沒有javaMySqlJava
- 為什麼藍芽耳機連上卻沒有聲音 藍芽明明已連線但就是沒聲音藍芽
- 為什麼動態CMOS沒有上拉延時?
- 為什麼Hook沒有ErrorBoundary?HookErrorORB
- 為什麼別人手握幾十個offer,而你卻一個也沒有?
- Twitter為什麼沒有當機?
- OptionalInt為什麼沒有ofNullable()方法Null
- 負載均衡和動態負載均衡分別是什麼?-VeCloud負載Cloud
- 為什麼 SQL 語句使用了索引,但卻還是慢查詢?SQL索引
- 什麼是負載均衡?有哪幾種策略?負載
- 【轉載】為什麼 MySQL 不推薦使用子查詢和 joinMySql
- [轉載] 為什麼 MySQL 不推薦使用子查詢和 joinMySql
- 為什麼 php empty 函式判斷結果為空,但實際值卻為非空PHP函式
- 為什麼?為什麼?Java處理排序後的陣列比沒有排序的快?想過沒有?Java排序陣列
- [20220415]為什麼沒有子子池.txt
- Ubuntu 安裝後為什麼沒有中文?Ubuntu
- 為什麼對gRPC做負載均衡會很棘手?RPC負載
- 跑批為什麼會這麼難?
- 沒有學不會的C++:為什麼不要使用全域性變數C++變數
- 什麼是負載均衡–SLB負載
- 刀牌就這麼死了,但Valve仍沒搞明白它為什麼失敗
- 研究生程式設計師買不起房,但本科生老爹卻有幾套房,讀書沒用了嗎?程式設計師
- [20230501]為什麼沒有顯示輸出.txt
- 為什麼前端不能沒有監控系統?前端
- 為什麼CAD匯出PDF沒有顏色
- 抖音 apk 為什麼沒有 launchable-activityAPK
- 朝鮮為什麼沒有肺炎確診病例?
- 為什麼我沒有收到贈送的流量
- 為什麼react-redux沒有更新hooks APIReactReduxHookAPI
- 藍芽配對成功但沒有聲音怎麼辦 藍芽明明已連線但沒有聲音藍芽
- 既然有MySQL了,為什麼還要有MongoDB?MySqlMongoDB
- 為什麼 Python 沒有函式過載?如何用裝飾器實現函式過載?Python函式
- python有pypi.org,為什麼golang沒有gopi.orgPythonGolang
- 優惠券有什麼用,為什麼不直接降價呢?
- Google 工程師:為什麼 CDN 對移動客戶端加速“沒有”效果Go工程師客戶端
- (4)什麼是Ribbon負載均衡負載