测试要解决的问题
索引字段上是否存在空数据,对查询性能的影响有多大?
基本步骤概括
测试的准备可以分为两大部分:准备测试数据和配置smack文件。
Super Smack和其他的一些benchmark工具一样,可以把“测试数据准备”也做了,包括按需建表、导入数据等等。我原本也想让Super Smack把这一步包了,但经过反复尝试后还是放弃了:
1. Super Smack的建表和导数据的触发条件比较复杂,又老是出各种各样的错,很难解决。与其让它代劳,还不如自己执行load data更可控。
2. 在测试执行过程中临时删表(drop)、建表、导数据,这种方案本身并不可取。日常开发中,我们的表本来就建好了,不需要依赖测试工具来临时创建,而且我们也不能容许测试工具在测试过程中或测试完成后自动删除表格.
所以,
我建议使用的基本方案是:
1. 自己手动完成测试数据的准备。
2. Super Smack只管执行测试语句。
测试数据准备
--建两张表,一张允许索引字段为空,另一张不允许为空
drop table if exists index_nullable;
drop table if exists index_not_nullable;
create table index_nullable (
id bigint unsigned not null auto_increment,
name varchar(50) default null,
key idx_name (name),
primary key(id)
);
create table index_not_nullable (
id bigint unsigned not null auto_increment,
name varchar(50) not null,
key idx_name (name),
primary key(id)
);
load data local infile '/Users/kent/smack-temp/for-loading-null.txt' into table index_nullable fields terminated by ',' lines terminated by '\n' (name); --可空表的数据,里面有空值 load data local infile '/Users/kent/smack-temp/for-loading-not-null.txt' into table index_not_nullable fields terminated by ',' lines terminated by '\n' (name); --非空表的数据
这两个数据文件可以用下面的JAVA代码生成:
package my.tools.mysql.supersmack;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.math.RandomUtils;
/**
*
* @author chennjianjx
*
*/
public class GenIndexNullSmack {
public static void main(String[] args) throws IOException {
File dir = new File(System.getProperty("user.home") + "/smack-temp");
File nullForLoading = new File(dir, "/for-loading-null.txt");
File notNullForLoading = new File(dir, "/for-loading-not-null.txt");
//第三个数据文件,让Super Smack生成查询sql时填充sql参数。后文会讲到
File forQuerying = new File(dir, "/for-query.txt");
int numOfRows = 1000000;
List<String> linesForNullLoading = new ArrayList<String>();
List<String> linesForNotNulLoading = new ArrayList<String>();
List<String> linesForQuerying = new ArrayList<String>();
for (int i = 1; i <= numOfRows; i++) {
String name = RandomStringUtils.randomAlphanumeric(10);
linesForNotNulLoading.add(name);
if (RandomUtils.nextBoolean() && RandomUtils.nextBoolean()
&& RandomUtils.nextBoolean()) {
linesForNullLoading.add(null);
} else {
linesForNullLoading.add(name);
}
linesForQuerying.add(name);
}
FileUtils.writeLines(nullForLoading, linesForNullLoading);
FileUtils.writeLines(forQuerying, linesForQuerying);
FileUtils.writeLines(notNullForLoading, linesForNotNulLoading);
System.out.println("Done. please check " + dir);
}
}
配置smack
这里需要先说一下smack文件的大致内容。基本上,我们需要配两样东西:
1. MySQL的访问url, 用户名,密码,库我,表名等参数。
2. 要执行的测试语句,包括SQL模板和用于填充模板的SQL参数(称为dictionary)。 dictionary一般配在一个文本文件中. 对我们来说,要做的就是把上面Java代码生成的for-query.txt复制到Super Smack所在的机器上,然后把它的路径配到smack文件中。
可空表测试配置:nullable.smack
dictionary "word"
{
type "rand"; // words are retrieved in random order
source_type "file";
source "/root/software/Super-Smack-master/index-null-smacks/for-query.txt" ;
file_size_equiv "45000";
}
query "select_by_name"
{
query "select * from index_nullable where name = '$word'";
type "select_index";
has_result_set "y";
parsed "y";
}
client "myclient"
{
user "root";
pass "root";
host "localhost";
db "kentbench";
socket "/var/lib/mysql/mysql.sock";
query_barrel "1 select_by_name";
}
main
{
myclient.init();
myclient.set_num_rounds($2);
myclient.create_threads($1);
myclient.connect();
myclient.unload_query_barrel();
myclient.collect_threads();
myclient.disconnect();
}
可空表测试配置:not-nullable.smack
将nullabel.smack复制一份,修改一下表名即可。
执行测试
如,
$super-smack index-null-smacks/nullable.smack 10 1000 $super-smack index-null-smacks/not-nullable.smack 10 1000
可以多做几轮,取均值;另外还应该尝试使用不同的并发数。
测试结果
| 表中数据量 | 并发数 | 可空表QPS | 非空表QPS |
| 5百万 | 10 | 12839 | 12707 |
| 5百万 | 100 | 10758 | 10808 |
注:每轮执行完后都会重启MySQL, 以消除缓存的影响
两个表的QPS完全是一个量级的,而且偏差很小; 有时可空表的QPS还更高一点。
结论:被索引字段中是否有空值,对查询性能的影响是很小很小的。表设计时字段是否允许为空,根据业务来决定来即可,不必考虑性能问题
补充:软硬件规格
1. MySQL Server: 阿里云服务器,CPU 2核, 内存4GB, 64位CentOS, MySQL版本5.1.73,InnoDB
2. Super Smack和数据库服务器放在同一台机器上