【笔记】sysbench bulk_insert 的实现和改造

1,169 阅读2分钟

这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战.

实现

Sysbench is a benchmark suite which allows you to quickly get an impression of system performance which is important if you plan to run a database under intensive load.

sysbench 是一个常用的负载测试套装,bulk_insert 是其中用于对数据库进行批量写入的测试 lua。

执行 sysbench 测试用例需要用户执行 prepare 和 run 命令,prepare 时调用一次测试 lua 中的 prepare 函数,run 时不断调用测试 lua 中的 event 函数。

在 bulk_insert 中,prepare 负责在目标数据库建好 threads 张表,表名分别是 sbtest1, sbtest2, ...

bulk_insert 的 run 命令包含了以下部分: 在这里插入图片描述

  1. 全局变量 cursize 初始为 0
  2. 调用 bulk_insert_init("insert into sbtest1 values")
  3. 每次 event,cursize++,调用 bulk_insert_next("(cursize,cursize)")
  4. 当测试结束时,调用 bulk_insert_done.

第一反应内部的执行逻辑是这样的:内建函数 init 和 next 完成了类似于查询字符串拼接的工作,done 时实际提交查询。

但如果是这样,整个线程运行过程只会执行一次查询,与预期结果不符。

查阅实现代码得知,bulk_insert_next 时如果发现当前查询字符串长度大于了预设的常数 con->bulk_buflen 也就是 BULK_PACKET_SIZE 也就是 512*1024 也就是 524288,就会将当前查询执行掉,然后从头开始拼接字符串。

改造

我的需求有两个:

  1. 让单次 query 的插入条数固定。 bulk_insert 单次执行的插入条数不是固定的,而是会随着 cur_size 变大,数据长度变大,单次 query 的数据量越来越少,初始时约为 39000,之后稳定在 33000+.
  2. 在查询字符串的数据部分结束后,写一些字符,如 on conflict do nothing.

这些都可以通过手动控制提交时间来实现:

function event()
   if (cursize % 10000 ~= 0) then
      con:bulk_insert_next("(" .. 10000000+cursize .. "," .. 10000000+cursize .. ")")
   elseif (cursize ~= 0) then
      con:bulk_insert_next("(" .. 10000000+cursize .. "," .. 10000000+cursize .. ")")
      con:bulk_insert_done()
      con:bulk_insert_init("INSERT INTO sbtest" .. sysbench.tid+1 .. " VALUES")
   else
      con:bulk_insert_init("INSERT INTO sbtest" .. sysbench.tid+1 .. " VALUES")
   end

   cursize = cursize + 1
end

function thread_done()
   con:bulk_insert_done()
   con:disconnect()
end

小声 bb

其实完全可以自己写个 lua 实现,为什么要用 bulk_insert 呢?主要是因为好奇 bulk_insert 的实现,以及懒得查语法(

为什么这些 c 语言项目不用 cpp 写啊,看代码看到手动虚表真的很不友好。

为什么会有 3 空格缩进的代码(


本文也发表于我的 csdn 博客中。