内容简介:sysbench测试Oracle时写一个lua脚本调用sqlload快速造数据
Posted on 2016-03-13 10:20:48 by osdba
1. 背景
如果用sysbench默认的功能来造数据,其原理是一条一条insert进数据库,同时其使用prepare命令是不能并行执行的,所以当要造几百G以上的数据时,会很慢,为此我写了一个sysbench的 lua 脚本,此脚本会启动多个线程并行调用sqlload快速造出大量的数据。
2. 实现过程
2.1 如何实现并行
我们知道在sysbench0.5中可以在命令行中指定测试时启动的并行线程数,这个测试过程是使用run命令,而且是多线程并发的,所以我们可以使用sysbench的run命令来造数据,而不再使用其提供的prepare命令的方法来造数据。run命令会根据命令行参数--num-threads来指定并发线程数的多少。
在sysbench中自定义的lua脚本中要求实现以下几个函数:
- function thread_init(thread_id): 此函数在线程创建后只被执行一次
- function event(thread_id): 每执行一次就会被调用一次。
由上可以知道,本次造数据的脚本我们只需要实现thread_init()函数就可以了,在此函数内调用sqlload装载数据即可。
2.2 生成数据的效率问题
我们知道sqlload工具是把一个文件中的数据快速装载到Oracle数据库中,但如果我们生成的数据是几百G以上,那么生成一个放在头盘上的文本文件不仅会占用空间,在读写过程中也会产生IO导致慢,所以最好的方案是程序直接生成数据,然后直接就通过sqlload装载到数据库中,这样的性能是最高的,这可以通过管道文件的方式来实现。造数据的程序把造的数据往管道中写,而sqlload从管道中读,这样就避免了数据需要落磁盘产生IO导致慢的问题。
虽然通过lua脚本也能生成sysbench要的测试数据,但其中的sysbench在lua脚本中提供的随机函数sb_rand及sb_rand_uniform还是太够快,这会影响数据的装载速度,为了达到一种极致的性能,我们可以写一个 C语言 的程序来生成所需要的数据。 此C程序为gendata.c,内容如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <sys/time.h>
uint64_t my_rand(struct random_data * r1, struct random_data * r2)
{
uint64_t rand_max = 100000000000LL;
uint64_t result;
uint32_t u1, u2;
random_r(r1, &u1);
random_r(r2, &u2);
result = (int64_t)u1 * (int64_t)u2;
result = result % rand_max;
return result;
}
int main(int argc, char *argv[])
{
struct timeval tpstart;
struct random_data r1, r2;
int i;
int r;
int max_value;
char rand_state1[128];
char rand_state2[128];
if (argc !=2)
{
printf("Usage: %s <rownums>\n", argv[0]);
return 1;
}
max_value = atoi(argv[1]);
gettimeofday(&tpstart,NULL);
initstate_r(tpstart.tv_usec,rand_state1,sizeof(rand_state1),&r1);
srandom_r(tpstart.tv_usec, &r1);
gettimeofday(&tpstart,NULL);
initstate_r(tpstart.tv_usec,rand_state2,sizeof(rand_state1),&r2);
srandom_r(tpstart.tv_usec, &r2);
for (i=1; i<max_value+1; i++)
{
r = my_rand(&r1, &r2) % max_value;
printf("%d,%d,%011llu-%011llu-%011llu-%011llu-%011llu-%011llu-%011llu-%011llu-%011llu-%011llu,%011llu-%011llu-%011llu-%011llu-%011llu\n",
i,
r,
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2),
my_rand(&r1, &r2)
);
}
return 0;
}
编译此C语言程序的方法如下:
gcc gendata.c -o gendata
2.3 装载数据的lua脚本的设计
为了使用sqlload,需要生成一个控制文件,这个控制文件可由lua脚本自动生成,格式类似如下:
unrecoverable load data infile 'sbtest9.dat' append into table sbtest9 fields terminated by "," (id,k,c,pad)
其中的“infile 'sbtest9.dat'”中的sbtest9.dat文件是一个管道文件,这个管道文件也由lua脚本自动生成。
实现以上功能的lua脚本sqlload_prepare2.lua的内容如下:
pathtest = string.match(test, "(.*/)") or ""
dofile(pathtest .. "common.lua")
function sqlload(table_id)
local ctl
local f
local i
local c_val
local pad_val
local content
local query
query = [[
CREATE TABLE sbtest]] .. table_id .. [[ (
id INTEGER NOT NULL,
k INTEGER,
c CHAR(120) DEFAULT '' NOT NULL,
pad CHAR(60) DEFAULT '' NOT NULL,
PRIMARY KEY (id)
) ]]
db_query(query)
content = [[
unrecoverable
load data
infile 'sbtest]] .. table_id .. [[.dat'
append into table sbtest]]..table_id..[[
fields terminated by ","
(id,k,c,pad)
]]
f = assert(io.open('sbtest'..table_id .. '.ctl', 'w'))
f:write(content)
f:close()
os.execute('mknod sbtest'..table_id..'.dat p')
os.execute ('./gendata ' .. oltp_table_size .. ' >> sbtest'..table_id ..'.dat &')
os.execute ('sqlldr -skip_unusable_indexes userid='..oracle_user.. '/'..oracle_password .. ' control=sbtest'..table_id ..'.ctl direct=true')
end
function create_index_and_seq(table_id)
db_query("CREATE SEQUENCE sbtest" .. table_id .. "_seq CACHE 10 START WITH ".. (oltp_table_size+1) )
db_query([[CREATE TRIGGER sbtest]] .. table_id .. [[_trig BEFORE INSERT ON sbtest]] .. table_id .. [[
FOR EACH ROW BEGIN SELECT sbtest]] .. table_id .. [[_seq.nextval INTO :new.id FROM DUAL; END;]])
db_query("COMMIT")
db_query("CREATE INDEX k_" .. table_id .. " on sbtest" .. table_id .. "(k)")
end
function thread_init(thread_id)
local index_name
local i
set_vars()
print("thread prepare"..thread_id)
if (oltp_secondary) then
index_name = "KEY xid"
else
index_name = "PRIMARY KEY"
end
for i=thread_id+1, oltp_tables_count, num_threads do
sqlload(i)
create_index_and_seq(i)
end
end
function event(thread_id)
os.exit()
end
3. 使用此脚本造数据
假设sqlload_prepare2.lua此脚本放在当前目录下的子目录lua下,我们需要把生成数据的程序也拷贝到当前目录下,然后运行下面的命令就可以并行装载数据了:
./sysbench_ora --test=lua/sqlload_prepare2.lua \
--oltp-table-name=sysbench \
--oltp-table-size=10000000 \
--oltp-tables-count=320 \
--oracle-db=bcache \
--oracle-user=sysbench \
--oracle-password=sysbench \
--max-time=7200 \
--max-requests=0 \
--num-threads=32 \
--db-driver=oracle \
--report-interval=1 \
run
上面的命令会开32个sqlload并发的装载数据。
4. 此脚本的下载及其它
- sysbench程序可以从github上下载: https://github.com/osdba/sysbench_bin
- gendata.c下载:gendata.c
- sqlload_prepare2.lua下载:sqlload_prepare2.lua
以上所述就是小编给大家介绍的《sysbench测试Oracle时写一个lua脚本调用sqlload快速造数据》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Ordering Disorder
Khoi Vinh / New Riders Press / 2010-12-03 / USD 29.99
The grid has long been an invaluable tool for creating order out of chaos for designers of all kinds—from city planners to architects to typesetters and graphic artists. In recent years, web designers......一起来看看 《Ordering Disorder》 这本书的介绍吧!
XML 在线格式化
在线 XML 格式化压缩工具
HEX CMYK 转换工具
HEX CMYK 互转工具