自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

BenchmarkSQL 對(duì) MySQL 測(cè)試時(shí)請(qǐng)注意隔離級(jí)別!

數(shù)據(jù)庫(kù) MySQL
在使用 BenchmarkSQL(版本為 5.0)壓測(cè)一段時(shí)間后,會(huì)出現(xiàn)卡住的現(xiàn)象,即 tpm TOTAL? 的值不再發(fā)生變化,但通過(guò) top 命令觀測(cè)到 MySQL 當(dāng)前的壓力還是很大。

1背景

最近在使用 BenchmarkSQL[1] 工具對(duì) MySQL 進(jìn)行性能測(cè)試的過(guò)程中,遇到一個(gè)比較有意思的問(wèn)題,Share 給大家。

BenchmarkSQL 是一款經(jīng)典的開源數(shù)據(jù)庫(kù)測(cè)試工具,內(nèi)含了TPC-C測(cè)試腳本,可支持 Oracle、MySQL、PostgreSQL、SQL Server以及一些國(guó)產(chǎn)數(shù)據(jù)庫(kù)的基準(zhǔn)測(cè)試。

2問(wèn)題描述

如下圖,在使用 BenchmarkSQL(版本為 5.0)壓測(cè)一段時(shí)間后,會(huì)出現(xiàn)卡住的現(xiàn)象,即 tpm TOTAL 的值不再發(fā)生變化,但通過(guò) top 命令觀測(cè)到 MySQL 當(dāng)前的壓力還是很大。

登錄 MySQL,通過(guò) information_schema.innodb_trx 表可以看到,MySQL 一直在重復(fù)執(zhí)行這兩個(gè) SQL:

mysql> select * from information_schema.innodb_trx\G
*************************** 1. row ***************************
                    trx_id: 685907
                 trx_state: RUNNING
               trx_started: 2024-05-28 11:14:21
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 2
       trx_mysql_thread_id: 157
                 trx_query: SELECT no_o_id FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 ORDER BY no_o_id ASC
       trx_operation_state: NULL
         trx_tables_in_use: 0
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 1128
           trx_rows_locked: 1
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
       trx_schedule_weight: NULL
1 row in set (0.00 sec)
mysql> select * from information_schema.innodb_trx\G
*************************** 1. row ***************************
                    trx_id: 685907
                 trx_state: RUNNING
               trx_started: 2024-05-28 11:14:21
     trx_requested_lock_id: NULL
          trx_wait_started: NULL
                trx_weight: 2
       trx_mysql_thread_id: 157
                 trx_query: DELETE FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 AND no_o_id = 2102
       trx_operation_state: NULL
         trx_tables_in_use: 1
         trx_tables_locked: 1
          trx_lock_structs: 2
     trx_lock_memory_bytes: 1128
           trx_rows_locked: 1
         trx_rows_modified: 0
   trx_concurrency_tickets: 0
       trx_isolation_level: REPEATABLE READ
         trx_unique_checks: 1
    trx_foreign_key_checks: 1
trx_last_foreign_key_error: NULL
 trx_adaptive_hash_latched: 0
 trx_adaptive_hash_timeout: 0
          trx_is_read_only: 0
trx_autocommit_non_locking: 0
       trx_schedule_weight: NULL
1 row in set (0.00 sec)

多次執(zhí)行 show master status\G 也可以看到 GTID 不再發(fā)生變化。為了更好的分析,打開 MySQL 的 general log 后重新壓測(cè)抓取 SQL:

可以看到確實(shí)出現(xiàn)了重復(fù) DELETE FROM 和 SELECT 的情況,再往前多看幾個(gè)事務(wù),你會(huì)發(fā)現(xiàn)前幾個(gè)事務(wù)均對(duì) 2102 這條記錄進(jìn)行了 DELETE 的操作。

3源碼探索

為什么會(huì)有這種類似死循環(huán)的情況出現(xiàn)呢?懷著探索精神,我們一起去看看 BenchmarkSQL 的源代碼。

  • 首先下載對(duì)應(yīng)的源碼包,通過(guò) for 循環(huán)找出 SQL 文件對(duì)應(yīng)的代碼文件。
[root@lucky src]$ pwd
/root/packages/BenchmarkSQL-5.0/src

[root@lucky src]$ for dic in client  jdbc  LoadData  OSCollector
do
 echo $dic
 for file in `ls $dic`
 do
     echo $file && cat $dic/$file | grep -Ein 'bmsql_customer|grep bmsql_customer|bmsql_customer|bmsql_oorder|bmsql_new_order|bmsql_order_line|bmsql_stock|bmsql_item|bmsql_history'
 done
done
  • 執(zhí)行以上命令,可以定位到事務(wù) SQL 的代碼在 ./client/jTPCCConnection.java 文件中,通過(guò)搜索 DELETE FROM bmsql_new_order 和 SELECT no_o_id FROM bmsql_new_order,找到對(duì)應(yīng)的 stmtDeliveryBGSelectOldestNewOrder 和 stmtDeliveryBGDeleteOldestNewOrder 關(guān)鍵字。

圖片圖片

  • 再次通過(guò)關(guān)鍵字 stmtDeliveryBGDeleteOldestNewOrder 搜索,最終可以定位到 ./BenchmarkSQL-5.0/src/client/jTPCCTData.java 的這部分代碼:

圖片圖片

看到這部分注釋,也許你已經(jīng)知道了問(wèn)題所在,下面我們結(jié)合代碼、注釋和實(shí)驗(yàn),來(lái)探究卡住的原因。

  • 事務(wù)A:DELETE FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 AND no_o_id = 2102;
  • 事務(wù)B:DELETE FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 AND no_o_id = 2102;執(zhí)行時(shí)被阻塞。
  • 事務(wù)A:提交。
  • 事務(wù)B:繼續(xù)執(zhí)行 DELETE 語(yǔ)句,但因?yàn)槭聞?wù)A已經(jīng)刪除了這行數(shù)據(jù),故刪除的記錄數(shù)為 0。BenchmarkSQL 中使用了 JDBC 的 executeUpdate() 方法,該方法會(huì)返回一個(gè) INT 類型的值,即本次操作在數(shù)據(jù)庫(kù)中改變的行數(shù)。
  • 結(jié)合代碼分析,在執(zhí)行 stmt2.executeUpdate() 后,rc=0,o_id=-1。又因?yàn)?o_id<0,故執(zhí)行了 continue,繼續(xù)下一個(gè) while 循環(huán)。
// 重點(diǎn)簡(jiǎn)要代碼
while (o_id < 0)
{
   rs = stmt1.executeQuery();
   rc = stmt2.executeUpdate();
   if (rc == 0)
   {
       o_id = -1;
   }
}

if (o_id < 0)
{
   continue;
}
  1. 因?yàn)楫?dāng)前隔離級(jí)別配置為 REPEATABLE-READ 級(jí)別,故在同一事務(wù)中執(zhí)行 SELECT no_o_id FROM bmsql_new_order ...ASC 進(jìn)行排序后,查詢結(jié)果依舊為 no_o_id=2102 的數(shù)據(jù),由此 rc 再次被賦值為 0,進(jìn)入到無(wú)限的 while 死循環(huán)中。

4場(chǎng)景實(shí)驗(yàn)

下面我們基于 REPEATABLE-READ 級(jí)別和 READ-COMMITTED 級(jí)別,進(jìn)行類似場(chǎng)景的實(shí)驗(yàn)。

1) REPEATABLE-READ 場(chǎng)景

sessionA

sessionB

set autocommit=0;

set autocommit=0;

SELECT no_o_id FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 ORDER BY no_o_id ASC limit 1; # 結(jié)果=2542

SELECT no_o_id FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 ORDER BY no_o_id ASC limit 1; # 結(jié)果=2542

DELETE FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 AND no_o_id = 2542;

DELETE FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 AND no_o_id = 2542; # 鎖等待

commit;

# 上一條 DELETE 語(yǔ)句執(zhí)行成功,返回 0 rows affected


SELECT no_o_id FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 ORDER BY no_o_id ASC limit 1; # 結(jié)果=2542


DELETE FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 AND no_o_id = 2542; # 執(zhí)行成功,返回0 rows affected


SELECT no_o_id FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 ORDER BY no_o_id ASC limit 1; # 結(jié)果=2542


...

2)READ-COMMITTED 場(chǎng)景

sessionA

sessionB

set autocommit=0;

set autocommit=0;

SELECT no_o_id FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 ORDER BY no_o_id ASC limit 1; # 結(jié)果=2543

SELECT no_o_id FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 ORDER BY no_o_id ASC limit 1; # 結(jié)果=2543

DELETE FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 AND no_o_id = 2543;

DELETE FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 AND no_o_id = 2543; # 鎖等待

commit;

# 上一條 DELETE 語(yǔ)句執(zhí)行成功,返回 0 rows affected


SELECT no_o_id FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 ORDER BY no_o_id ASC limit 1; # 結(jié)果=2544


...

5總結(jié)

由此我們可以得出結(jié)論,因?yàn)?MySQL 配置的隔離級(jí)別是 REPEATABLE-READ,導(dǎo)致 BenchmarkSQL 出現(xiàn)了死循環(huán)的問(wèn)題,將其修改為 READ-COMMITTED 級(jí)別后,問(wèn)題得以解決。

參考資料

[1]benchmarksql: https://benchmarksql.readthedocs.io/en/latest/

責(zé)任編輯:武曉燕 來(lái)源: 愛可生開源社區(qū)
相關(guān)推薦

2022-06-10 11:51:49

MySQL事務(wù)隔離

2018-12-19 16:46:38

MySQL事務(wù)隔離數(shù)據(jù)庫(kù)

2021-07-26 10:28:13

MySQL事務(wù)隔離

2024-04-26 09:17:20

MySQL事務(wù)隔離

2021-08-04 13:19:42

MySQL 事務(wù)隔離

2024-12-02 08:37:04

2021-10-19 10:10:51

MySQL事務(wù)隔離級(jí)別數(shù)據(jù)庫(kù)

2024-04-23 08:17:14

MySQL數(shù)據(jù)庫(kù)隔離

2022-05-23 13:36:31

惡意軟件網(wǎng)絡(luò)攻擊

2025-03-03 08:20:00

MySQL事務(wù)隔離數(shù)據(jù)庫(kù)

2010-11-19 16:13:06

oracle事務(wù)隔離級(jí)

2022-09-08 08:02:26

MySQL隔離

2020-10-13 10:32:24

MySQL事務(wù)MVCC

2025-01-13 13:12:54

2009-06-29 17:54:47

Spring事務(wù)隔離

2011-05-07 10:47:29

Oracle大小寫

2021-08-30 20:12:11

MySQL事務(wù)隔離

2022-06-29 11:01:05

MySQL事務(wù)隔離級(jí)別

2018-01-03 08:52:27

MySQL數(shù)據(jù)庫(kù)級(jí)別

2023-10-24 08:37:00

git工具開源
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)