diff --git a/multi_index_bench/README.md b/multi_index_bench/README.md new file mode 100644 index 000000000..8b729cb65 --- /dev/null +++ b/multi_index_bench/README.md @@ -0,0 +1,24 @@ +## 使用方法 +把该文件夹的两个文件放在执行sysbench命令的当前目录,sysbench会自动识别替换安装内容。 + +## 主要修改内容: +1. 在数据表中添加索引数据项,用于测试带有索引的操作内容。 +2. select_random_ranges 可以测试多个库,同时完成随机选择数据库和索引。 + +## 添加参数: +``` +index_num = + {"number of indexes, such number of integer columns will be created for those secondary indexes", 0}, +table_with_index = + {"if index_nums > 0, indexes will be created at table creation", false}, +db_prefix = + {"manual create database prefix, this will disable mysql-db param", "sysbench"}, +db_num = + {"manual create database number, this will disable mysql-db param", 20} +``` + +## 用法: +1. 设置 index_num 为需要创建的次级索引的个数,这会创建相同数量的额外整数列(k_1, k_2, ...)。table_with_index 表示是否在创建表是包含索引。 +2. select_random_ranges 需要使用的多个数据库需要通过 1,手动完成创建。(当前默认数据名是 sysbench1, sysbench2, sysbench3 ... ) + + diff --git a/multi_index_bench/oltp_common.lua b/multi_index_bench/oltp_common.lua new file mode 100755 index 000000000..e17cd5315 --- /dev/null +++ b/multi_index_bench/oltp_common.lua @@ -0,0 +1,610 @@ +-- Copyright (C) 2006-2018 Alexey Kopytov + +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. + +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. + +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +-- ----------------------------------------------------------------------------- +-- Common code for OLTP benchmarks. +-- ----------------------------------------------------------------------------- + +function init() + assert(event ~= nil, + "this script is meant to be included by other OLTP scripts and " .. + "should not be called directly.") +end + +if sysbench.cmdline.command == nil then + error("Command is required. Supported commands: prepare, warmup, run, " .. + "cleanup, help") +end + +-- Command line options +sysbench.cmdline.options = { + table_size = + {"Number of rows per table", 10000}, + range_size = + {"Range size for range SELECT queries", 100}, + tables = + {"Number of tables", 1}, + point_selects = + {"Number of point SELECT queries per transaction", 10}, + simple_ranges = + {"Number of simple range SELECT queries per transaction", 1}, + secondary_ranges = + {"Number of secondary range SELECT queries per transaction", 1}, + sum_ranges = + {"Number of SELECT SUM() queries per transaction", 1}, + order_ranges = + {"Number of SELECT ORDER BY queries per transaction", 1}, + distinct_ranges = + {"Number of SELECT DISTINCT queries per transaction", 1}, + index_updates = + {"Number of UPDATE index queries per transaction", 1}, + non_index_updates = + {"Number of UPDATE non-index queries per transaction", 1}, + delete_inserts = + {"Number of DELETE/INSERT combinations per transaction", 1}, + range_selects = + {"Enable/disable all range SELECT queries", true}, + auto_inc = + {"Use AUTO_INCREMENT column as Primary Key (for MySQL), " .. + "or its alternatives in other DBMS. When disabled, use " .. + "client-generated IDs", true}, + create_table_options = + {"Extra CREATE TABLE options", ""}, + skip_trx = + {"Don't start explicit transactions and execute all queries " .. + "in the AUTOCOMMIT mode", false}, + secondary = + {"Use a secondary index in place of the PRIMARY KEY", false}, + create_secondary = + {"Create a secondary index in addition to the PRIMARY KEY", true}, + reconnect = + {"Reconnect after every N events. The default (0) is to not reconnect", + 0}, + use_file = + {"If use a text file as dataset", false}, + mysql_storage_engine = + {"Storage engine, if MySQL is used", "innodb"}, + pgsql_variant = + {"Use this PostgreSQL variant when running with the " .. + "PostgreSQL driver. The only currently supported " .. + "variant is 'redshift'. When enabled, " .. + "create_secondary is automatically disabled, and " .. + "delete_inserts is set to 0"}, + index_num = + {"create table index numbers", 0}, + table_with_index = + {"if index_num > 0 create table with index", false}, + db_prefix = + {"manual create database prefix, this will disable mysql-db param", "sysbench"}, + db_num = + {"manual create database number, this will disable mysql-db param", 20} +} + +-- Prepare the dataset. This command supports parallel execution, i.e. will +-- benefit from executing with --threads > 1 as long as --tables > 1 +function cmd_prepare() + local drv = sysbench.sql.driver() + local con = drv:connect() + + for i = sysbench.tid % sysbench.opt.threads + 1, sysbench.opt.tables, + sysbench.opt.threads do + create_table(drv, con, i) + end +end + +-- Preload the dataset into the server cache. This command supports parallel +-- execution, i.e. will benefit from executing with --threads > 1 as long as +-- --tables > 1 +-- +-- PS. Currently, this command is only meaningful for MySQL/InnoDB benchmarks +function cmd_warmup() + local drv = sysbench.sql.driver() + local con = drv:connect() + + assert(drv:name() == "mysql", "warmup is currently MySQL only") + + -- Do not create on disk tables for subsequent queries + con:query("SET tmp_table_size=2*1024*1024*1024") + con:query("SET max_heap_table_size=2*1024*1024*1024") + + for i = sysbench.tid % sysbench.opt.threads + 1, sysbench.opt.tables, + sysbench.opt.threads do + local t = "sbtest" .. i + print("Preloading table " .. t) + con:query("ANALYZE TABLE sbtest" .. i) + con:query(string.format( + "SELECT AVG(id) FROM " .. + "(SELECT * FROM %s FORCE KEY (PRIMARY) " .. + "LIMIT %u) t", + t, sysbench.opt.table_size)) + con:query(string.format( + "SELECT COUNT(*) FROM " .. + "(SELECT * FROM %s WHERE k LIKE '%%0%%' LIMIT %u) t", + t, sysbench.opt.table_size)) + end +end + +-- Implement parallel prepare and warmup commands, define 'prewarm' as an alias +-- for 'warmup' +sysbench.cmdline.commands = { + prepare = {cmd_prepare, sysbench.cmdline.PARALLEL_COMMAND}, + warmup = {cmd_warmup, sysbench.cmdline.PARALLEL_COMMAND}, + prewarm = {cmd_warmup, sysbench.cmdline.PARALLEL_COMMAND} +} + + +-- Template strings of random digits with 11-digit groups separated by dashes + +-- 10 groups, 119 characters +local c_value_template = "###########-###########-###########-" .. + "###########-###########-###########-" .. + "###########-###########-###########-" .. + "###########" + +-- 5 groups, 59 characters +local pad_value_template = "###########-###########-###########-" .. + "###########-###########" + +function get_c_value() + return sysbench.rand.string(c_value_template) +end + +function get_pad_value() + return sysbench.rand.string(pad_value_template) +end + +function get_str_value() + return sysbench.rand.filestr() +end + +function create_table(drv, con, table_num) + local id_index_def, id_def + local engine_def = "" + local query + + if sysbench.opt.secondary then + id_index_def = "KEY xid" + else + id_index_def = "PRIMARY KEY" + end + + if drv:name() == "mysql" + then + if sysbench.opt.auto_inc then + id_def = "INTEGER NOT NULL AUTO_INCREMENT" + else + id_def = "INTEGER NOT NULL" + end + engine_def = "/*! ENGINE = " .. sysbench.opt.mysql_storage_engine .. " */" + elseif drv:name() == "pgsql" + then + if not sysbench.opt.auto_inc then + id_def = "INTEGER NOT NULL" + elseif pgsql_variant == 'redshift' then + id_def = "INTEGER IDENTITY(1,1)" + else + id_def = "SERIAL" + end + else + error("Unsupported database driver:" .. drv:name()) + end + + print(string.format("Creating table 'sbtest%d'...", table_num)) + + local t_keys = {} + local t_keys_define = {} + local t_index = {} + for i = 1, sysbench.opt.index_num do + table.insert(t_keys, string.format([[k%d,]], i)) + table.insert(t_keys_define, string.format([[k%d INTEGER DEFAULT '0' NOT NULL,]], i)) + table.insert(t_index, string.format([[INDEX(k%d),]], i)) + end + local string_keys=table.concat(t_keys) + local string_keys_define=table.concat(t_keys_define) + local string_index="" + if sysbench.opt.table_with_index then + string_index=table.concat(t_index) + end + + if sysbench.opt.use_file then + query = string.format([[ + CREATE TABLE sbtest%d( + id %s, + k INTEGER DEFAULT '0' NOT NULL, + %s + c VARBINARY(32000) DEFAULT '' NOT NULL, + pad MEDIUMBLOB, + %s + %s (id) + ) %s %s]], + table_num, id_def, string_keys_define, string_index, id_index_def, engine_def, + sysbench.opt.create_table_options) + else + query = string.format([[ + CREATE TABLE sbtest%d( + id %s, + k INTEGER DEFAULT '0' NOT NULL, + %s + c BINARY(120) DEFAULT '' NOT NULL, + pad BINARY(60) DEFAULT '' NOT NULL, + %s (id) + ) %s %s]], + table_num, id_def, string_keys_define, id_index_def, engine_def, + sysbench.opt.create_table_options) + end + + con:query(query) + + if (sysbench.opt.table_size > 0) then + print(string.format("Inserting %d records into 'sbtest%d'", + sysbench.opt.table_size, table_num)) + end + + if sysbench.opt.auto_inc then + query = "INSERT INTO sbtest" .. table_num .. "(k, " .. string_keys .. "c, pad) VALUES" + else + query = "INSERT INTO sbtest" .. table_num .. "(id, k, " .. string_keys .. "c, pad) VALUES" + end + + con:bulk_insert_init(query) + + local c_val + local pad_val + + for i = 1, sysbench.opt.table_size do + + if sysbench.opt.use_file then + c_val, pad_val = get_str_value() + else + c_val = get_c_value() + pad_val = get_pad_value() + end + + + local t_query = {} + for i = 1, sysbench.opt.index_num do + table.insert(t_query, string.format([[%d,]], sysbench.rand.default(1, sysbench.opt.table_size))) + end + string_query=table.concat(t_query, " ") + + if (sysbench.opt.auto_inc) then + query = string.format("(%d, %s \"%s\", \"%s\")", + sysbench.rand.default(1, sysbench.opt.table_size), + string_query, + c_val, pad_val) + else + query = string.format("(%d, %d, %s \"%s\", \"%s\")", + i, + sysbench.rand.default(1, sysbench.opt.table_size), + string_query, + c_val, pad_val) + end + + con:bulk_insert_next(query) + end + + con:bulk_insert_done() + + if sysbench.opt.create_secondary then + print(string.format("Creating a secondary index on 'sbtest%d'...", + table_num)) + con:query(string.format("CREATE INDEX k_%d ON sbtest%d(k)", + table_num, table_num)) + end +end + +local t = sysbench.sql.type +local stmt_defs = { + point_selects = { + "SELECT length(c) FROM sbtest%u WHERE id=?", + t.INT}, + simple_ranges = { + "SELECT length(c) FROM sbtest%u WHERE id BETWEEN ? AND ?", + t.INT, t.INT}, + secondary_ranges = { + "SELECT length(c) FROM sbtest%u WHERE k >= ? AND ? >=0 LIMIT %u", + t.INT, t.INT}, + sum_ranges = { + "SELECT SUM(k) FROM sbtest%u WHERE id BETWEEN ? AND ?", + t.INT, t.INT}, + order_ranges = { + "SELECT length(c) as lenc FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY lenc", + t.INT, t.INT}, + distinct_ranges = { + "SELECT DISTINCT length(c) as lenc FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY lenc", + t.INT, t.INT}, + index_updates = { + "UPDATE sbtest%u SET k=k+1 WHERE id=?", + t.INT}, + non_index_updates = { + "UPDATE sbtest%u SET c=? WHERE id=?", + {t.CHAR, 120}, t.INT}, + deletes = { + "DELETE FROM sbtest%u WHERE id=?", + t.INT}, + inserts = { + "INSERT INTO sbtest%u (id, k, c, pad) VALUES (?, ?, ?, ?)", + t.INT, t.INT, {t.CHAR, 120}, + {t.VARCHAR, 4194000}}, --lua bind VARCHAR can be larger than MySQL(65535) +} + +function prepare_begin() + stmt.begin = con:prepare("BEGIN") +end + +function prepare_commit() + stmt.commit = con:prepare("COMMIT") +end + +function prepare_for_each_table(key) + for t = 1, sysbench.opt.tables do + if key == "secondary_ranges" then + stmt[t][key] = con:prepare(string.format(stmt_defs[key][1], t, sysbench.opt.range_size)) + else + stmt[t][key] = con:prepare(string.format(stmt_defs[key][1], t)) + end + + local nparam = #stmt_defs[key] - 1 + + if nparam > 0 then + param[t][key] = {} + end + + for p = 1, nparam do + local btype = stmt_defs[key][p+1] + local len + + if type(btype) == "table" then + len = btype[2] + btype = btype[1] + end + if btype == sysbench.sql.type.VARCHAR or + btype == sysbench.sql.type.CHAR then + param[t][key][p] = stmt[t][key]:bind_create(btype, len) + else + param[t][key][p] = stmt[t][key]:bind_create(btype) + end + end + + if nparam > 0 then + stmt[t][key]:bind_param(unpack(param[t][key])) + end + end +end + +function prepare_point_selects() + prepare_for_each_table("point_selects") +end + +function prepare_simple_ranges() + prepare_for_each_table("simple_ranges") +end + +function prepare_secondary_ranges() + prepare_for_each_table("secondary_ranges") +end + +function prepare_sum_ranges() + prepare_for_each_table("sum_ranges") +end + +function prepare_order_ranges() + prepare_for_each_table("order_ranges") +end + +function prepare_distinct_ranges() + prepare_for_each_table("distinct_ranges") +end + +function prepare_index_updates() + prepare_for_each_table("index_updates") +end + +function prepare_non_index_updates() + prepare_for_each_table("non_index_updates") +end + +function prepare_delete_inserts() + prepare_for_each_table("deletes") + prepare_for_each_table("inserts") +end + +function thread_init() + drv = sysbench.sql.driver() + con = drv:connect() + + -- Create global nested tables for prepared statements and their + -- parameters. We need a statement and a parameter set for each combination + -- of connection/table/query + stmt = {} + param = {} + + for t = 1, sysbench.opt.tables do + stmt[t] = {} + param[t] = {} + end + + -- This function is a 'callback' defined by individual benchmark scripts + prepare_statements() +end + +-- Close prepared statements +function close_statements() + for t = 1, sysbench.opt.tables do + for k, s in pairs(stmt[t]) do + stmt[t][k]:close() + end + end + if (stmt.begin ~= nil) then + stmt.begin:close() + end + if (stmt.commit ~= nil) then + stmt.commit:close() + end +end + +function thread_done() + close_statements() + con:disconnect() +end + +function cleanup() + local drv = sysbench.sql.driver() + local con = drv:connect() + + for i = 1, sysbench.opt.tables do + print(string.format("Dropping table 'sbtest%d'...", i)) + con:query("DROP TABLE IF EXISTS sbtest" .. i ) + end +end + +local function get_table_num() + return sysbench.rand.uniform(1, sysbench.opt.tables) +end + +local function get_id() + return sysbench.rand.default(1, sysbench.opt.table_size) +end + +function begin() + stmt.begin:execute() +end + +function commit() + stmt.commit:execute() +end + +function execute_point_selects() + local tnum = get_table_num() + local i + + for i = 1, sysbench.opt.point_selects do + param[tnum].point_selects[1]:set(get_id()) + + stmt[tnum].point_selects:execute() + end +end + +local function execute_range(key) + local tnum = get_table_num() + + for i = 1, sysbench.opt[key] do + local id = get_id() + + param[tnum][key][1]:set(id) + param[tnum][key][2]:set(id + sysbench.opt.range_size - 1) + + stmt[tnum][key]:execute() + end +end + +function execute_simple_ranges() + execute_range("simple_ranges") +end + +function execute_secondary_ranges() + execute_range("secondary_ranges") +end + +function execute_sum_ranges() + execute_range("sum_ranges") +end + +function execute_order_ranges() + execute_range("order_ranges") +end + +function execute_distinct_ranges() + execute_range("distinct_ranges") +end + +function execute_index_updates() + local tnum = get_table_num() + + for i = 1, sysbench.opt.index_updates do + param[tnum].index_updates[1]:set(get_id()) + + stmt[tnum].index_updates:execute() + end +end + +function execute_non_index_updates() + local tnum = get_table_num() + local c_val; + + for i = 1, sysbench.opt.non_index_updates do + if sysbench.opt.use_file then + c_val = get_str_value() + else + c_val = get_c_value() + end + param[tnum].non_index_updates[1]:set(c_val) + param[tnum].non_index_updates[2]:set(get_id()) + + stmt[tnum].non_index_updates:execute() + end +end + +function execute_delete_inserts() + local tnum = get_table_num() + local file_c_val + local file_pad_val + + for i = 1, sysbench.opt.delete_inserts do + local id = get_id() + local k = get_id() + + param[tnum].deletes[1]:set(id) + + param[tnum].inserts[1]:set(id) + param[tnum].inserts[2]:set(k) + if sysbench.opt.use_file then + file_c_val, file_pad_val = get_str_value() + param[tnum].inserts[3]:set(file_c_val) + param[tnum].inserts[4]:set(file_pad_val) + else + param[tnum].inserts[3]:set_rand_str(c_value_template) + param[tnum].inserts[4]:set_rand_str(pad_value_template) + end + + stmt[tnum].deletes:execute() + stmt[tnum].inserts:execute() + end +end + +-- Re-prepare statements if we have reconnected, which is possible when some of +-- the listed error codes are in the --mysql-ignore-errors list +function sysbench.hooks.before_restart_event(errdesc) + if errdesc.sql_errno == 2013 or -- CR_SERVER_LOST + errdesc.sql_errno == 2055 or -- CR_SERVER_LOST_EXTENDED + errdesc.sql_errno == 2006 or -- CR_SERVER_GONE_ERROR + errdesc.sql_errno == 2011 -- CR_TCP_CONNECTION + then + close_statements() + prepare_statements() + end +end + +function check_reconnect() + if sysbench.opt.reconnect > 0 then + transactions = (transactions or 0) + 1 + if transactions % sysbench.opt.reconnect == 0 then + close_statements() + con:reconnect() + prepare_statements() + end + end +end diff --git a/multi_index_bench/select_random_ranges.lua b/multi_index_bench/select_random_ranges.lua new file mode 100755 index 000000000..3d062e7f9 --- /dev/null +++ b/multi_index_bench/select_random_ranges.lua @@ -0,0 +1,116 @@ +#!/usr/bin/env sysbench +-- This test is designed for testing MariaDB's key_cache_segments for MyISAM, +-- and should work with other storage engines as well. +-- +-- For details about key_cache_segments please refer to: +-- http://kb.askmonty.org/v/segmented-key-cache +-- + +require("oltp_common") + +-- Add --number-of-ranges and --delta to the list of standard OLTP options +sysbench.cmdline.options.number_of_ranges = + {"Number of random BETWEEN ranges per SELECT", 10} +sysbench.cmdline.options.delta = + {"Size of BETWEEN ranges", 5} + +-- Override standard prepare/cleanup OLTP functions, as this benchmark does not +-- support multiple tables +oltp_prepare = prepare +oltp_cleanup = cleanup + +function prepare() + assert(sysbench.opt.tables == 1, "this benchmark does not support " .. + "--tables > 1") + oltp_prepare() +end + +function cleanup() + assert(sysbench.opt.tables == 1, "this benchmark does not support " .. + "--tables > 1") + oltp_cleanup() +end + +function thread_init() + stmt = {} + params = {} + drv = sysbench.sql.driver() + con = drv:connect() + for db_id = 1, sysbench.opt.db_num do + local db_name = string.format("%s%d",sysbench.opt.db_prefix, db_id) + stmt[db_id] = {} + params[db_id] = {} + for kid = 1, sysbench.opt.index_num do + stmt[db_id][kid] = {} + local k_name = string.format("k%d",kid) + local ranges = string.rep(k_name .. " BETWEEN ? AND ? OR ", + sysbench.opt.number_of_ranges - 1) .. + k_name .. " BETWEEN ? AND ?" + + if (sysbench.opt.secondary_ranges == 0) then + stmt[db_id][kid] = con:prepare(string.format([[ + SELECT count(k) + FROM %s.sbtest1 + WHERE %s]], db_name, ranges)) + elseif (sysbench.opt.secondary_ranges == 2) then + -- MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery, + -- So we create an extra nested subquery + stmt[db_id][kid] = con:prepare(string.format([[ + SELECT count(*), sum(length(c)) FROM %s.sbtest1 WHERE id IN + (SELECT * FROM (SELECT id FROM %s.sbtest1 WHERE %s LIMIT %d) as t)]], + db_name, db_name, ranges, sysbench.opt.range_size)) + elseif (sysbench.opt.secondary_ranges == 3) then + -- MySQL does not generate MRR query plan for secondary_ranges == 2, + -- We add secondary_ranges == 3 as the query for get range_size rows + -- by MRR, secondary_ranges == 1 likely get more rows than range_size. + stmt[db_id][kid] = con:prepare(string.format([[ + SELECT length(c) + FROM %s.sbtest1 + WHERE %s LIMIT %d]], db_name, ranges, sysbench.opt.range_size)) + else + stmt[db_id][kid] = con:prepare(string.format([[ + SELECT sum(length(c)) + FROM %s.sbtest1 + WHERE %s]], db_name, ranges)) + end + params[db_id][kid] = {} + for j = 1, sysbench.opt.number_of_ranges*2 do + params[db_id][kid][j] = stmt[db_id][kid]:bind_create(sysbench.sql.type.INT) + end + + stmt[db_id][kid]:bind_param(unpack(params[db_id][kid])) + end + end + + rlen = sysbench.opt.table_size / sysbench.opt.threads + + thread_id = sysbench.tid % sysbench.opt.threads +end + +function thread_done() + for db_id = 1, sysbench.opt.db_num do + for kid = 1, sysbench.opt.index_num do + stmt[db_id][kid]:close() + end + end + con:disconnect() +end + +function event() + -- To prevent overlapping of our range queries we need to partition the whole + -- table into 'threads' segments and then make each thread work with its + -- own segment. + local lkid = sysbench.rand.default(1, sysbench.opt.index_num) + local db_id = sysbench.rand.default(1, sysbench.opt.db_num) + for i = 1, sysbench.opt.number_of_ranges*2, 2 do + local rmin = rlen * thread_id + local rmax = rmin + rlen + local val = sysbench.rand.default(rmin, rmax) + params[db_id][lkid][i]:set(val) + params[db_id][lkid][i+1]:set(val + sysbench.opt.delta) + end + + stmt[db_id][lkid]:execute() + + check_reconnect() +end diff --git a/src/db_driver.c b/src/db_driver.c index 97310a66f..db161ecd7 100644 --- a/src/db_driver.c +++ b/src/db_driver.c @@ -40,10 +40,11 @@ #include "sb_ck_pr.h" /* Query length limit for bulk insert queries */ -#define BULK_PACKET_SIZE (512*1024) +static unsigned int BULK_PACKET_SIZE = 5120*1024; +static unsigned int MAX_BULK_CNT = 1000; /* How many rows to insert before COMMITs (used in bulk insert) */ -#define ROWS_BEFORE_COMMIT 1000 +static int ROWS_BEFORE_COMMIT = 1000; /* Global variables */ db_globals_t db_globals CK_CC_CACHELINE; @@ -131,7 +132,7 @@ void db_print_help(void) log_text(LOG_NOTICE, "General database options:\n"); sb_print_options(db_args); log_text(LOG_NOTICE, ""); - + log_text(LOG_NOTICE, "Compiled-in database drivers:"); SB_LIST_FOR_EACH(pos, &drivers) { @@ -841,7 +842,7 @@ int db_parse_arguments(void) db_globals.driver = sb_get_value_string("db-driver"); db_globals.debug = sb_get_value_flag("db-debug"); - + return 0; } @@ -859,7 +860,7 @@ int db_print_value(db_bind_t *var, char *buf, int buflen) n = snprintf(buf, buflen, "NULL"); return (n < buflen) ? n : -1; } - + switch (var->type) { case DB_TYPE_TINYINT: n = snprintf(buf, buflen, "%hhd", *(char *)var->buffer); @@ -943,6 +944,9 @@ int db_bulk_insert_init(db_conn_t *con, const char *query, size_t query_len) return 1; } + BULK_PACKET_SIZE = atoi(getenv("BULK_PACKET_SIZE")?:"5242880"); + MAX_BULK_CNT = atoi(getenv("MAX_BULK_CNT")?:"1000"); + /* Allocate query buffer */ if (query_len + 1 > BULK_PACKET_SIZE) { @@ -955,7 +959,9 @@ int db_bulk_insert_init(db_conn_t *con, const char *query, size_t query_len) con->bulk_buffer = (char *)malloc(con->bulk_buflen); if (con->bulk_buffer == NULL) return 1; - + + ROWS_BEFORE_COMMIT = atoi(getenv("ROWS_BEFORE_COMMIT")?:"1000"); + con->bulk_commit_max = driver_caps.needs_commit ? ROWS_BEFORE_COMMIT : 0; con->bulk_commit_cnt = 0; strcpy(con->bulk_buffer, query); @@ -993,7 +999,8 @@ int db_bulk_insert_next(db_conn_t *con, const char *query, size_t query_len) Reserve space for '\0' and ',' (if not the first chunk in a bulk insert */ - if (con->bulk_ptr + query_len + 1 + (con->bulk_cnt>0) > con->bulk_buflen) + if (con->bulk_cnt >= MAX_BULK_CNT || + con->bulk_ptr + query_len + 1 + (con->bulk_cnt>0) > con->bulk_buflen) { /* Is this a first row? */ if (!con->bulk_cnt) diff --git a/src/drivers/mysql/drv_mysql.c b/src/drivers/mysql/drv_mysql.c index 58600b8e0..177166553 100644 --- a/src/drivers/mysql/drv_mysql.c +++ b/src/drivers/mysql/drv_mysql.c @@ -411,6 +411,10 @@ static int mysql_drv_real_connect(db_mysql_conn_t *db_mysql_con) DEBUG("mysql_options(%p, %s, %s)",con, "MYSQL_OPT_COMPRESS", "NULL"); mysql_options(con, MYSQL_OPT_COMPRESS, NULL); } + const char* cs = getenv("MYSQL_CONN_CHARSET"); + if (cs) { + mysql_options(con, MYSQL_SET_CHARSET_NAME, cs); + } DEBUG("mysql_real_connect(%p, \"%s\", \"%s\", \"%s\", \"%s\", %u, \"%s\", %s)", con, diff --git a/src/lua/internal/sysbench.rand.lua b/src/lua/internal/sysbench.rand.lua index 2a05aade7..69451998d 100644 --- a/src/lua/internal/sysbench.rand.lua +++ b/src/lua/internal/sysbench.rand.lua @@ -33,6 +33,14 @@ uint32_t sb_rand_unique(void); void sb_rand_str(const char *, char *); uint32_t sb_rand_varstr(char *, uint32_t, uint32_t); double sb_rand_uniform_double(void); +struct SbKeyVal { + size_t cap; + size_t klen; + size_t vlen; + char* str; // also key + char* val; // ptr after tab char +}; +struct SbKeyVal* sb_file_str(void); ]] function sysbench.rand.uniform_uint64() @@ -82,3 +90,8 @@ end function sysbench.rand.uniform_double() return ffi.C.sb_rand_uniform_double() end + +function sysbench.rand.filestr() + local ms = ffi.C.sb_file_str() + return ffi.string(ms.str, ms.klen), ffi.string(ms.val, ms.vlen) +end \ No newline at end of file diff --git a/src/lua/oltp_common.lua b/src/lua/oltp_common.lua index fdc5c83ed..c4361be0e 100644 --- a/src/lua/oltp_common.lua +++ b/src/lua/oltp_common.lua @@ -33,6 +33,14 @@ end sysbench.cmdline.options = { table_size = {"Number of rows per table", 10000}, + start_id = + {"Start id of rows for prepare insert into table, " .. + "used for parallel prepare data into one table, " .. + "users can run multiple sysbench process with different start_id concurrently. " .. + "in this case, range_size is the number of rows to be inserted, id of inserted " .. + "rows are {start_id, start_id + 1, ..., start_id + range_size - 1}. " .. + "this option should not be used with auto_inc. " .. + "default is 0 to conform origin sysbench", 0}, range_size = {"Range size for range SELECT queries", 100}, tables = @@ -41,6 +49,8 @@ sysbench.cmdline.options = { {"Number of point SELECT queries per transaction", 10}, simple_ranges = {"Number of simple range SELECT queries per transaction", 1}, + secondary_ranges = + {"Number of secondary range SELECT queries per transaction", 1}, sum_ranges = {"Number of SELECT SUM() queries per transaction", 1}, order_ranges = @@ -71,6 +81,8 @@ sysbench.cmdline.options = { reconnect = {"Reconnect after every N events. The default (0) is to not reconnect", 0}, + use_file = + {"If use a text file as dataset", false}, mysql_storage_engine = {"Storage engine, if MySQL is used", "innodb"}, pgsql_variant = @@ -154,10 +166,13 @@ function get_pad_value() return sysbench.rand.string(pad_value_template) end +function get_str_value() + return sysbench.rand.filestr() +end + function create_table(drv, con, table_num) local id_index_def, id_def local engine_def = "" - local extra_table_options = "" local query if sysbench.opt.secondary then @@ -189,16 +204,29 @@ function create_table(drv, con, table_num) print(string.format("Creating table 'sbtest%d'...", table_num)) - query = string.format([[ -CREATE TABLE sbtest%d( - id %s, - k INTEGER DEFAULT '0' NOT NULL, - c CHAR(120) DEFAULT '' NOT NULL, - pad CHAR(60) DEFAULT '' NOT NULL, - %s (id) -) %s %s]], - table_num, id_def, id_index_def, engine_def, - sysbench.opt.create_table_options) + if sysbench.opt.use_file then + query = string.format([[ + CREATE TABLE IF NOT EXISTS sbtest%d( + id %s, + k INTEGER DEFAULT '0' NOT NULL, + c VARCHAR(512) DEFAULT '' NOT NULL, + pad MEDIUMTEXT, + %s (id) + ) %s %s]], + table_num, id_def, id_index_def, engine_def, + sysbench.opt.create_table_options) + else + query = string.format([[ + CREATE TABLE IF NOT EXISTS sbtest%d( + id %s, + k INTEGER DEFAULT '0' NOT NULL, + c CHAR(120) DEFAULT '' NOT NULL, + pad CHAR(60) DEFAULT '' NOT NULL, + %s (id) + ) %s %s]], + table_num, id_def, id_index_def, engine_def, + sysbench.opt.create_table_options) + end con:query(query) @@ -217,18 +245,32 @@ CREATE TABLE sbtest%d( local c_val local pad_val + local start_id; + local finish_id; + + if sysbench.opt.start_id == 0 then + start_id = 1; + finish_id = sysbench.opt.table_size; + else + start_id = sysbench.opt.start_id; + finish_id = start_id + sysbench.opt.range_size - 1; + end - for i = 1, sysbench.opt.table_size do + for i = start_id, finish_id do - c_val = get_c_value() - pad_val = get_pad_value() + if sysbench.opt.use_file then + c_val, pad_val = get_str_value() + else + c_val = get_c_value() + pad_val = get_pad_value() + end if (sysbench.opt.auto_inc) then - query = string.format("(%d, '%s', '%s')", + query = string.format("(%d, \"%s\", \"%s\")", sysbench.rand.default(1, sysbench.opt.table_size), c_val, pad_val) else - query = string.format("(%d, %d, '%s', '%s')", + query = string.format("(%d, %d, \"%s\", \"%s\")", i, sysbench.rand.default(1, sysbench.opt.table_size), c_val, pad_val) @@ -250,19 +292,22 @@ end local t = sysbench.sql.type local stmt_defs = { point_selects = { - "SELECT c FROM sbtest%u WHERE id=?", + "SELECT length(c) FROM sbtest%u WHERE id=?", t.INT}, simple_ranges = { - "SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ?", + "SELECT length(c) FROM sbtest%u WHERE id BETWEEN ? AND ?", + t.INT, t.INT}, + secondary_ranges = { + "SELECT length(c) FROM sbtest%u WHERE k >= ? AND ? >=0 LIMIT %u", t.INT, t.INT}, sum_ranges = { "SELECT SUM(k) FROM sbtest%u WHERE id BETWEEN ? AND ?", t.INT, t.INT}, order_ranges = { - "SELECT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c", + "SELECT length(c) as lenc FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY lenc", t.INT, t.INT}, distinct_ranges = { - "SELECT DISTINCT c FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY c", + "SELECT DISTINCT length(c) as lenc FROM sbtest%u WHERE id BETWEEN ? AND ? ORDER BY lenc", t.INT, t.INT}, index_updates = { "UPDATE sbtest%u SET k=k+1 WHERE id=?", @@ -275,7 +320,8 @@ local stmt_defs = { t.INT}, inserts = { "INSERT INTO sbtest%u (id, k, c, pad) VALUES (?, ?, ?, ?)", - t.INT, t.INT, {t.CHAR, 120}, {t.CHAR, 60}}, + t.INT, t.INT, {t.CHAR, 120}, + {t.VARCHAR, 4194000}}, --lua bind VARCHAR can be larger than MySQL(65535) } function prepare_begin() @@ -288,7 +334,11 @@ end function prepare_for_each_table(key) for t = 1, sysbench.opt.tables do - stmt[t][key] = con:prepare(string.format(stmt_defs[key][1], t)) + if key == "secondary_ranges" then + stmt[t][key] = con:prepare(string.format(stmt_defs[key][1], t, sysbench.opt.range_size)) + else + stmt[t][key] = con:prepare(string.format(stmt_defs[key][1], t)) + end local nparam = #stmt_defs[key] - 1 @@ -326,6 +376,10 @@ function prepare_simple_ranges() prepare_for_each_table("simple_ranges") end +function prepare_secondary_ranges() + prepare_for_each_table("secondary_ranges") +end + function prepare_sum_ranges() prepare_for_each_table("sum_ranges") end @@ -444,6 +498,10 @@ function execute_simple_ranges() execute_range("simple_ranges") end +function execute_secondary_ranges() + execute_range("secondary_ranges") +end + function execute_sum_ranges() execute_range("sum_ranges") end @@ -468,9 +526,15 @@ end function execute_non_index_updates() local tnum = get_table_num() + local c_val; for i = 1, sysbench.opt.non_index_updates do - param[tnum].non_index_updates[1]:set_rand_str(c_value_template) + if sysbench.opt.use_file then + c_val = get_str_value() + else + c_val = get_c_value() + end + param[tnum].non_index_updates[1]:set(c_val) param[tnum].non_index_updates[2]:set(get_id()) stmt[tnum].non_index_updates:execute() @@ -479,6 +543,8 @@ end function execute_delete_inserts() local tnum = get_table_num() + local file_c_val + local file_pad_val for i = 1, sysbench.opt.delete_inserts do local id = get_id() @@ -488,8 +554,14 @@ function execute_delete_inserts() param[tnum].inserts[1]:set(id) param[tnum].inserts[2]:set(k) - param[tnum].inserts[3]:set_rand_str(c_value_template) - param[tnum].inserts[4]:set_rand_str(pad_value_template) + if sysbench.opt.use_file then + file_c_val, file_pad_val = get_str_value() + param[tnum].inserts[3]:set(file_c_val) + param[tnum].inserts[4]:set(file_pad_val) + else + param[tnum].inserts[3]:set_rand_str(c_value_template) + param[tnum].inserts[4]:set_rand_str(pad_value_template) + end stmt[tnum].deletes:execute() stmt[tnum].inserts:execute() diff --git a/src/lua/oltp_insert.lua b/src/lua/oltp_insert.lua index 3035d40b4..dd0b92cf4 100755 --- a/src/lua/oltp_insert.lua +++ b/src/lua/oltp_insert.lua @@ -43,12 +43,18 @@ end function event() local table_name = "sbtest" .. sysbench.rand.uniform(1, sysbench.opt.tables) local k_val = sysbench.rand.default(1, sysbench.opt.table_size) - local c_val = get_c_value() - local pad_val = get_pad_value() + local c_val + local pad_val + if sysbench.opt.use_file then + c_val, pad_val = get_str_value() + else + c_val = get_c_value() + pad_val = get_pad_value() + end if (drv:name() == "pgsql" and sysbench.opt.auto_inc) then con:query(string.format("INSERT INTO %s (k, c, pad) VALUES " .. - "(%d, '%s', '%s')", + "(%d, \"%s\", \"%s\")", table_name, k_val, c_val, pad_val)) else if (sysbench.opt.auto_inc) then @@ -59,8 +65,8 @@ function event() end con:query(string.format("INSERT INTO %s (id, k, c, pad) VALUES " .. - "(%d, %d, '%s', '%s')", - table_name, i, k_val, c_val, pad_val)) + "(%d, %d, \"%s\", \"", + table_name, i, k_val, c_val) .. pad_val .. "\")") end check_reconnect() diff --git a/src/lua/oltp_read_only.lua b/src/lua/oltp_read_only.lua index ee7ca37e0..941c96fad 100755 --- a/src/lua/oltp_read_only.lua +++ b/src/lua/oltp_read_only.lua @@ -31,6 +31,9 @@ function prepare_statements() if sysbench.opt.range_selects then prepare_simple_ranges() + if (sysbench.opt.secondary_ranges > 0) then + prepare_secondary_ranges() + end prepare_sum_ranges() prepare_order_ranges() prepare_distinct_ranges() @@ -46,6 +49,9 @@ function event() if sysbench.opt.range_selects then execute_simple_ranges() + if (sysbench.opt.secondary_ranges > 0) then + execute_secondary_ranges() + end execute_sum_ranges() execute_order_ranges() execute_distinct_ranges() diff --git a/src/lua/oltp_read_write.lua b/src/lua/oltp_read_write.lua index 9b5cf6eba..de9c4559c 100755 --- a/src/lua/oltp_read_write.lua +++ b/src/lua/oltp_read_write.lua @@ -31,6 +31,9 @@ function prepare_statements() if sysbench.opt.range_selects then prepare_simple_ranges() + if (sysbench.opt.secondary_ranges > 0) then + prepare_secondary_ranges() + end prepare_sum_ranges() prepare_order_ranges() prepare_distinct_ranges() @@ -50,6 +53,9 @@ function event() if sysbench.opt.range_selects then execute_simple_ranges() + if (sysbench.opt.secondary_ranges > 0) then + execute_secondary_ranges() + end execute_sum_ranges() execute_order_ranges() execute_distinct_ranges() diff --git a/src/lua/select_random_points.lua b/src/lua/select_random_points.lua index 0afe2c941..2a65251d4 100755 --- a/src/lua/select_random_points.lua +++ b/src/lua/select_random_points.lua @@ -36,7 +36,7 @@ function thread_init() local points = string.rep("?, ", sysbench.opt.random_points - 1) .. "?" stmt = con:prepare(string.format([[ - SELECT id, k, c, pad + SELECT id, k, length(c), length(pad) FROM sbtest1 WHERE k IN (%s) ]], points)) diff --git a/src/lua/select_random_ranges.lua b/src/lua/select_random_ranges.lua index bea8b9741..b72f82132 100755 --- a/src/lua/select_random_ranges.lua +++ b/src/lua/select_random_ranges.lua @@ -39,10 +39,32 @@ function thread_init() sysbench.opt.number_of_ranges - 1) .. "k BETWEEN ? AND ?" - stmt = con:prepare(string.format([[ - SELECT count(k) - FROM sbtest1 - WHERE %s]], ranges)) + if (sysbench.opt.secondary_ranges == 0) then + stmt = con:prepare(string.format([[ + SELECT count(k) + FROM sbtest1 + WHERE %s]], ranges)) + elseif (sysbench.opt.secondary_ranges == 2) then + -- MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery, + -- So we create an extra nested subquery + stmt = con:prepare(string.format([[ + SELECT count(*), sum(length(c)) FROM sbtest1 WHERE id IN + (SELECT * FROM (SELECT id FROM sbtest1 WHERE %s LIMIT %d) as t)]], + ranges, sysbench.opt.range_size)) + elseif (sysbench.opt.secondary_ranges == 3) then + -- MySQL does not generate MRR query plan for secondary_ranges == 2, + -- We add secondary_ranges == 3 as the query for get range_size rows + -- by MRR, secondary_ranges == 1 likely get more rows than range_size. + stmt = con:prepare(string.format([[ + SELECT length(c) + FROM sbtest1 + WHERE %s LIMIT %d]], ranges, sysbench.opt.range_size)) + else + stmt = con:prepare(string.format([[ + SELECT sum(length(c)) + FROM sbtest1 + WHERE %s]], ranges)) + end params = {} for j = 1, sysbench.opt.number_of_ranges*2 do diff --git a/src/sb_rand.c b/src/sb_rand.c index 563b566e3..0446f8ce2 100644 --- a/src/sb_rand.c +++ b/src/sb_rand.c @@ -40,6 +40,8 @@ #endif #include +#include +#include #ifdef HAVE_STRING_H # include #endif @@ -50,11 +52,13 @@ # include #endif +#include "sysbench.h" #include "sb_options.h" #include "sb_rand.h" #include "sb_logger.h" #include "sb_ck_pr.h" +#include TLS sb_rng_state_t sb_rng_state CK_CC_CACHELINE; @@ -456,6 +460,81 @@ uint32_t sb_rand_zipfian(uint32_t a, uint32_t b) sb_rand_zipfian_int(b - a + 1, zipf_exp, zipf_s, zipf_hIntegralX1) - 1; } +struct SbKeyVal { + size_t cap; + size_t klen; + size_t vlen; + char* str; // also key + char* val; // ptr after tab char +}; +static __thread struct SbKeyVal* g_kv = NULL; + +static FILE* file = NULL; + +int sb_file_init() +{ + assert(sb_globals.filename != NULL); + + file = fopen(sb_globals.filename, "r"); + if (file == NULL) + { + log_text(LOG_FATAL, "Invalid filename: %s", sb_globals.filename); + return 1; + } + + return 0; +} + +struct SbKeyVal* sb_file_str() +{ + assert(file != NULL); + + if (NULL == g_kv) { + g_kv = (struct SbKeyVal*)malloc(sizeof(struct SbKeyVal)); + g_kv->klen = 0; + g_kv->vlen = 0; + g_kv->cap = 4*1024*1024; + g_kv->str = (char*)malloc(g_kv->cap); + g_kv->val = NULL; + } + while (true) { + ssize_t read = getline(&g_kv->str, &g_kv->cap, file); + if (read != -1) { + char* str = g_kv->str; + while (read > 0 && isspace((unsigned char)str[read])) { + str[--read] = '\0'; // trim trailing spaces + } + char* tab = (char*)memchr(str, '\t', read); + if (NULL == tab) { + g_kv->val = str + read; // empty c string + g_kv->vlen = 0; + g_kv->klen = read; + } + else { + tab[0] = '\0'; + g_kv->klen = tab - str; + g_kv->vlen = read - (tab - str) - 1; + g_kv->val = tab + 1; + } + break; + } + else { + rewind(file); + fprintf(stderr, "sb_file_str: read eof, rewind(%s)\n", sb_globals.filename); + } + } + return g_kv; +} + +void sb_file_done() +{ + if (file) + { + fclose(file); + } +} + + /* H(x) is defined as diff --git a/src/sb_rand.h b/src/sb_rand.h index 6cb3dab2d..66073a277 100644 --- a/src/sb_rand.h +++ b/src/sb_rand.h @@ -71,4 +71,8 @@ uint32_t sb_rand_unique(void); void sb_rand_str(const char *, char *); uint32_t sb_rand_varstr(char *, uint32_t, uint32_t); +int sb_file_init(void); +struct SbKeyVal* sb_file_str(void); +void sb_file_done(void); + #endif /* SB_RAND_H */ diff --git a/src/sysbench.c b/src/sysbench.c index fb83bef45..3ca5c64b8 100644 --- a/src/sysbench.c +++ b/src/sysbench.c @@ -32,7 +32,7 @@ # include #endif -#ifdef HAVE_UNISTD_H +#ifdef HAVE_UNISTD_H # include # include #endif @@ -119,6 +119,7 @@ sb_arg_t general_args[] = SB_OPT("luajit-cmd", "perform LuaJIT control command. This option is " "equivalent to 'luajit -j'. See LuaJIT documentation for more " "information", NULL, STRING), + SB_OPT("filename", "use filename as data source", "", STRING), SB_OPT_END }; @@ -471,7 +472,7 @@ void print_help(void) { sb_list_item_t *pos; sb_test_t *test; - + printf("Usage:\n"); printf(" sysbench [options]... [testname] [command]\n\n"); printf("Commands implemented by most tests: prepare run cleanup help\n\n"); @@ -657,7 +658,7 @@ void print_run_mode(sb_test_t *test) if (sb_globals.debug) log_text(LOG_NOTICE, "Debug mode enabled.\n"); - + if (sb_globals.validate) log_text(LOG_NOTICE, "Validation checks: on.\n"); @@ -678,7 +679,7 @@ void print_run_mode(sb_test_t *test) if (sb_globals.force_shutdown) log_text(LOG_NOTICE, "Forcing shutdown in %u seconds", (unsigned) NS2SEC(sb_globals.max_time_ns) + sb_globals.timeout); - + log_text(LOG_NOTICE, ""); if (test->ops.print_mode != NULL) @@ -1066,7 +1067,7 @@ static int run_test(sb_test_t *test) /* initialize test */ if (test->ops.init != NULL && test->ops.init() != 0) return 1; - + /* print test mode */ print_run_mode(test); @@ -1301,7 +1302,7 @@ static int init(void) sb_globals.threads = sb_get_value_int("threads"); thread_init_timeout = sb_get_value_int("thread-init-timeout"); - + if (sb_globals.threads <= 0) { log_text(LOG_FATAL, "Invalid value for --threads: %d.\n", @@ -1345,7 +1346,7 @@ static int init(void) else if (strcasecmp(tmp, "off")) { char *endptr; - + sb_globals.force_shutdown = 1; sb_globals.timeout = (unsigned) strtol(tmp, &endptr, 10); if (*endptr == '%') @@ -1373,7 +1374,7 @@ static int init(void) if (opt != NULL) set_option(opt->name, "5", opt->type); } - + sb_globals.validate = sb_get_value_flag("validate"); if (sb_rand_init()) @@ -1382,6 +1383,14 @@ static int init(void) } sb_globals.tx_rate = sb_get_value_int("rate"); + sb_globals.filename = sb_get_value_string("filename"); + if (sb_globals.filename) + { + if (sb_file_init()) + { + return 1; + } + } sb_globals.report_interval = sb_get_value_int("report-interval"); @@ -1473,7 +1482,7 @@ int main(int argc, char *argv[]) printf("%s\n", VERSION_STRING); return EXIT_SUCCESS; } - + /* Initialize global variables and logger */ if (init() || log_init() || sb_counters_init()) return EXIT_FAILURE; @@ -1598,6 +1607,11 @@ int main(int argc, char *argv[]) sb_thread_done(); + if (sb_globals.filename) + { + sb_file_done(); + } + free(timers); free(timers_copy); diff --git a/src/sysbench.h b/src/sysbench.h index 2fb2ad89d..ffd12e403 100644 --- a/src/sysbench.h +++ b/src/sysbench.h @@ -208,6 +208,7 @@ typedef struct int warmup_time; /* warmup time */ uint64_t nevents CK_CC_CACHELINE; /* event counter */ const char *luajit_cmd; /* LuaJIT command */ + const char *filename; /*if use a text file as dataset*/ } sb_globals_t; extern sb_globals_t sb_globals CK_CC_CACHELINE; diff --git a/tests/t/script_oltp_help.t b/tests/t/script_oltp_help.t index c29f853a6..fe622597c 100644 --- a/tests/t/script_oltp_help.t +++ b/tests/t/script_oltp_help.t @@ -4,7 +4,7 @@ OLTP usage information test $ sysbench $SBTEST_SCRIPTDIR/oltp_read_write.lua help sysbench * (glob) - + oltp_read_write.lua options: --auto_inc[=on|off] Use AUTO_INCREMENT column as Primary Key (for MySQL), or its alternatives in other DBMS. When disabled, use client-generated IDs [on] --create_secondary[=on|off] Create a secondary index in addition to the PRIMARY KEY [on] @@ -14,6 +14,7 @@ OLTP usage information test --index_updates=N Number of UPDATE index queries per transaction [1] --mysql_storage_engine=STRING Storage engine, if MySQL is used [innodb] --non_index_updates=N Number of UPDATE non-index queries per transaction [1] + --secondary_ranges=[0|1|2] Secondary index to fetch table SELECT queries per transaction [1] --order_ranges=N Number of SELECT ORDER BY queries per transaction [1] --pgsql_variant=STRING Use this PostgreSQL variant when running with the PostgreSQL driver. The only currently supported variant is 'redshift'. When enabled, create_secondary is automatically disabled, and delete_inserts is set to 0 --point_selects=N Number of point SELECT queries per transaction [10] @@ -26,4 +27,4 @@ OLTP usage information test --sum_ranges=N Number of SELECT SUM() queries per transaction [1] --table_size=N Number of rows per table [10000] --tables=N Number of tables [1] - +