文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

BenchmarkSQL 对 MySQL 测试时请注意隔离级别!

2024-11-29 21:06

关注

BenchmarkSQL 是一款经典的开源数据库测试工具,内含了TPC-C测试脚本,可支持 Oracle、MySQL、PostgreSQL、SQL Server以及一些国产数据库的基准测试。

2问题描述

如下图,在使用 BenchmarkSQL(版本为 5.0)压测一段时间后,会出现卡住的现象,即 tpm TOTAL 的值不再发生变化,但通过 top 命令观测到 MySQL 当前的压力还是很大。

登录 MySQL,通过 information_schema.innodb_trx 表可以看到,MySQL 一直在重复执行这两个 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)

多次执行 show master status\G 也可以看到 GTID 不再发生变化。为了更好的分析,打开 MySQL 的 general log 后重新压测抓取 SQL:

可以看到确实出现了重复 DELETE FROM 和 SELECT 的情况,再往前多看几个事务,你会发现前几个事务均对 2102 这条记录进行了 DELETE 的操作。

3源码探索

为什么会有这种类似死循环的情况出现呢?怀着探索精神,我们一起去看看 BenchmarkSQL 的源代码。

[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

图片

图片

看到这部分注释,也许你已经知道了问题所在,下面我们结合代码、注释和实验,来探究卡住的原因。

// 重点简要代码
while (o_id < 0)
{
   rs = stmt1.executeQuery();
   rc = stmt2.executeUpdate();
   if (rc == 0)
   {
       o_id = -1;
   }
}

if (o_id < 0)
{
   continue;
}
  1. 因为当前隔离级别配置为 REPEATABLE-READ 级别,故在同一事务中执行 SELECT no_o_id FROM bmsql_new_order ...ASC 进行排序后,查询结果依旧为 no_o_id=2102 的数据,由此 rc 再次被赋值为 0,进入到无限的 while 死循环中。

4场景实验

下面我们基于 REPEATABLE-READ 级别和 READ-COMMITTED 级别,进行类似场景的实验。

1) REPEATABLE-READ 场景

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; # 结果=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; # 结果=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 语句执行成功,返回 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; # 结果=2542


DELETE FROM bmsql_new_order WHERE no_w_id = 1 AND no_d_id = 1 AND no_o_id = 2542; # 执行成功,返回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; # 结果=2542


...

2)READ-COMMITTED 场景

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; # 结果=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; # 结果=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 语句执行成功,返回 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; # 结果=2544


...

5总结

由此我们可以得出结论,因为 MySQL 配置的隔离级别是 REPEATABLE-READ,导致 BenchmarkSQL 出现了死循环的问题,将其修改为 READ-COMMITTED 级别后,问题得以解决。

参考资料

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

来源:爱可生开源社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯