SQLTest系列之INSERT语句测试

原文地址:https://yq.aliyun.com/articles/64375?spm=5176.100239.blogcont69187.22.fhUpoZ

摘要: 一款可以测试MSSQL Server的工具,这篇文章主要是分享下SQLTest之Insert语句测试。

场景引入

菜鸟不断又猛又持久的给老鸟惊喜以后,老鸟开始不断的折腾菜鸟:“鸟,你研究下有没有一款可以测试MSSQL Server的工具吧?”。
“这还不简单,用Red Gate的SQLTest呗”,于是菜鸟开始了工具的研究之旅:“要不,今天就分享下SQLTest之Insert语句测试吧”。

SQLTest简介

领了任务的菜鸟,由于之前对这个工具有所了解,所以还是比较轻车熟路的。让我们先来看看SQLTest是干什么的吧。
SQLTest是一款简单易用,非常容易上手的SQL Server性能、压力和单元测试工具。它既可以测试本地环境的SQL Server工作负载,也可以测试云环境的SQL Server服务。

SQLTest一键安装

SQLTest就是一个简单的SQL Server测试工具,所以,它的安装过程也简单。官方推荐一键安装,简单到令人发指的地步。

下载地址:
http://www.sqltest.org/Download

测试环境

在测试之前,菜鸟汇总自己的测试环境信息:
CPU:4 cores
Memory:4 GB
Disk: SSD
SQL Server: SQL Server 2008R2 SP2

SQLTest INSERT语句测试

老实讲,上面都不重要,看好了,这里才是本文的重点:如何使用SQLTest来测试INSERT的效率呢?如何测试INSERT语句在不同线程数量下的效率?不同的数据类型选择对INSERT效率的影响如何?
这里虚拟一个场景,假设我们有一张名为Orders的订单表,我们会根据Orders的主键数据类型的不同来测试INSERT的效率。

INT IDENTITY

创建测试数据库和Orders表

use master;

IF DB_ID(‘SQLTestDemo‘) IS NULL
    CREATE DATABASE SQLTestDemo
go

use SQLTestDemo
go
IF OBJECT_ID(‘Orders‘,‘U‘) IS NOT NULL
BEGIN
    TRUNCATE TABLE Orders
    DROP TABLE Orders
END
GO
CREATE TABLE Orders (
OrderID INT NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED
, OrderDate datetime
, CustomerID int
, SourceID int
, StatusID int
, Amount decimal (18, 2)
, OrderDetails char(7000)
)
GO

所有准备工作就绪,菜鸟迫不及待的开始测试了,开启SQLTest,设置SQLClient Connection String

Data Source=(local);Database=SQLTestDemo;Integrated Security=true;Pooling=false

SQL Command

insert into Orders values (getdate (), 1, 1, 1, 1, replicate (‘a‘, 7000))
go

Number of Threads

点击Start Current按钮,测试时间10秒后,得到如下截图:
1个线程运行10秒钟,迭代了12471次,每次迭代消耗数据库时间0.000秒。(由于这里精确到千分之一秒,也就是一毫秒,说明每次迭代耗时少于1毫秒)。

现在我们分别将线程数调整为2,4,8,16,32,64,128,256来测试,为了测试的相对准确性,请在测试之前执行“创建测试数据库和Orders表”中的代码,重新创建Orders表。SQLTest返回结果的设置方法如下:Settings => Workload Settings

测试完毕后,我们可以得到如下表格数据:

将这些数据绘制成直方图和折线图:

从这个图中,可以很直观的得出如下结论:

  • 从吞吐量来看:无输出结果方式远远大于有输出结果方式,前者是后者的两倍还多;
  • 从数据库平均耗时来看:无输出结果效率也远远高于有输出结果方式,后者是前者的两倍;
  • 从线程数量来看:并不是线程数开得越多,SQL Server吞吐量越大,效率越高;无论是有输出结果方式还是无输出结果方式,并发8到16个线程SQL Server的吞吐量达到最大,效率最高;

注意:
最后一个结论不一定适用于所有的SQL Server,因为这个和SQL Server的版本,机器的CPU,Memory,磁盘等有密切的关系,用户在得到这个值之前需要自己严格测试。

提供INT值

完成了主键值INT IDENTITY的测试后,菜鸟陷入了疑惑:每个线程如何插入不同的值呢?于是有了这个测试方法:

use SQLTestDemo
go
IF OBJECT_ID(‘Orders‘,‘U‘) IS NOT NULL
begin
    truncate table Orders
    drop table Orders
end
go
create table Orders (OrderID int primary key clustered
, OrderDate datetime
, CustomerID int
, SourceID int
, StatusID int
, Amount decimal (18, 2)
, OrderDetails char (7000)
)
go

让每个线程生成不同的OrderID,我们可以使用SQLTest_Thread来代替线程数,SQLTest_Iteration代替迭代次数,最终将SQL Command修改为:

insert into Orders values (({SQLTest_Thread} * 100000) + {SQLTest_Iteration}, getdate(), 1, 1, 1, 1, replicate (‘a‘, 7000))
go

UNIQUEIDENTIFIER with NEWID()

测试方法类似于“INT IDENTITY”章节,只是Orders表结构和SQL Command不一致。

use SQLTestDemo
go
IF OBJECT_ID(‘Orders‘,‘U‘) IS NOT NULL
begin
    truncate table Orders
    drop table Orders
end
go
create table Orders (
OrderID uniqueidentifier not null default newid () primary key clustered
, OrderDate datetime
, CustomerID int
, SourceID int
, StatusID int
, Amount decimal (18, 2)
, OrderDetails char (7000))
go
SQL Command
insert into Orders values (NEWID(),getdate (), 1, 1, 1, 1, replicate (‘a‘, 7000))
go

UNIQUEIDENTIFIER with NEWSEQUENTIALID()

同上,测试方法类似于“INT IDENTITY”章节,只是Orders表结构和SQL Command不一致。

use SQLTestDemo
go
IF OBJECT_ID(‘Orders‘,‘U‘) IS NOT NULL
BEGIN
    TRUNCATE TABLE Orders
    DROP TABLE Orders
END
GO
CREATE TABLE Orders (
OrderID uniqueidentifier default newsequentialid () primary key clustered
, OrderDate datetime
, CustomerID int
, SourceID int
, StatusID int
, Amount decimal (18, 2)
, OrderDetails char (7000))
GO
SQL Command
insert into Orders(OrderDate,CustomerID,SourceID,StatusID,Amount,OrderDetails) values (getdate (), 1, 1, 1, 1, replicate (‘a‘, 7000))
go

总结

将四种数据类型在No Result输出情况汇总统计如下表:

做一个漂亮炫酷的图表出来对比下:

从这个图标,我们可以发现如下规律:

  • 从吞吐量角度来看:所有数据类型,并发量聚集在8到16时,INSERT操作吞吐量达到最大值;
  • 吞吐量表现最好的是int identity数据类型和uniqueidentifier + newsequentialid做为主键的表;
  • 从数据库平均耗时角度:所有数据类型,并发量在8到16时,INSERT操作的平均时间消耗最小,接近64个线程时,平均耗时会急剧上升;
  • 平均耗时表现最好的是int identity和Newsequentialid类型。

从结果来看,UNIQUEIDENTIFIER + NEWSEQUENTIALID和INT IDENTITY性能和吞吐量表现都非常好,我们到底该选择哪一个更好一些呢? 我的结论是选择IDENTITY属性的数字类型字段做为主键,因为它占的空间更小,INT为4个字节,BIGINT为8个字节而UNIQUEIDENTIFIER 占了36个字节。

时间: 2024-10-14 00:04:11

SQLTest系列之INSERT语句测试的相关文章

Sql Server系列:Insert语句

1. INSERT语法 [ WITH <common_table_expression> [ ,...n ] ] INSERT { [ TOP ( expression ) [ PERCENT ] ] [ INTO ] { <object> | rowset_function_limited [ WITH ( <Table_Hint_Limited> [ ...n ] ) ] } { [ ( column_list ) ] [ <OUTPUT Clause>

将表里的数据批量生成INSERT语句的存储过程 继续增强版

文章继续 桦仔兄的文章 将表里的数据批量生成INSERT语句的存储过程 增强版 继续增强... 本来打算将该内容回复于桦仔兄的文章的下面的,但是不知为何博客园就是不让提交!.... 所以在这里贴出来吧,算作继续增加文章中解决的:根据查询条件自动生成插入脚本的需求,其实这种需求还是蛮常见的. 本文着重解决了文中的脚本的schema问题,给调整了下,现在脚本能自动识别出不同的schema下同名的表的语句 修改后脚本如下: -- Author: <桦仔> -- Blog: <http://ww

SQL注入测试平台 SQLol -3.INSERT注入测试

访问首页的insert模块,http://127.0.0.1/sql/insert.php,开始对insert模块进行测试. insert语句: INSERT INTO [users] ([username], isadmin) VALUES (['1'], [0]) 接收的参数可能拼接到上述语句中[]的任一个位置. 在这里我们一般使用 1.报错注入 2.盲注(布尔类型.时间延迟类型) 有的注入点可以同时使用多种方法注入,这里只演示一种. 下面演示注入到不同位置的方法. 一.Value(stri

Oracle&gt;&gt;通过PL/SQL程序块判断,指定用户的指定数据表和序列是否存在,如果存在则删除,否则新创建。并且为表添加含有字符串数据,execute immediate执行insert语句中有字符串解决办法

--变量声明 declare num0 number; num1 number; begin --判断用户为:SYSTEM的数据库中是否存在相关数据表和序列,存在则删除,不存在则新创建,DBMS_OUTPUT.put_line等同java中的System.out.println输出语句 DBMS_OUTPUT.put_line('正在初始化数据库信息,请稍后......'); --以下参数说明: --所涉及到的参数值必须为大写 --sequence_owner:指定哪个数据库用户的序列: seq

将表里的数据批量生成INSERT语句的存储过程 增强版

原文:将表里的数据批量生成INSERT语句的存储过程 增强版 将表里的数据批量生成INSERT语句的存储过程 增强版 有时候,我们需要将某个表里的数据全部或者根据查询条件导出来,迁移到另一个相同结构的库中 目前SQL Server里面是没有相关的工具根据查询条件来生成INSERT语句的,只有借助第三方工具(third party tools) 这种脚本网上也有很多,但是网上的脚本还是欠缺一些规范和功能,例如:我只想导出特定查询条件的数据,网上的脚本都是导出全表数据 如果表很大,对性能会有很大影响

一条诡异的insert语句

问题背景 有同事反馈在mysql上面执行一条普通的insert语句,结果报错, execute failed due to >>> Incorrect string value: '\xA1;offl...' for column 'biz_info' at row 1 经过半天的折腾,终于搞清楚了来龙去脉,这里简单给大家分享下.为了方便说明,我将测试例子中的表和语句简化,但不影响问题重现. 问题复现 连接字符集:UTF8 表结构: CREATE TABLE `ggg` (   `id`

把表里的数据转换为insert 语句

当表里面有数据时,怎么把表里的数据转换为insert 语句 (从别人那里看来的用SQLServer 2008 R2测试可用) CREATE PROC spGenInsertSQL @TableName AS VARCHAR(100)ASDECLARE xCursor CURSORFORSELECT NAME ,xusertypeFROM syscolumnsWHERE (id = OBJECT_ID(@TableName)) DECLARE @F1 VARCHAR(100)DECLARE @F2

Insert语句加/*+APPEND */在循环中单条提交对系统的影响分析

1./*+APPEND */提示的用途 /*+APPEND */提示,是一个INSERT语句专有的hint,它的作用,大家都知道是用来提升insert速度的,并且效果非常的明显,至于它的提升速度的工作原理,在笔者的另一篇博文<用直接路径(direct-path)insert提升性能的两种方法>中有提到(以优点方式提出),该文地址为:http://blog.csdn.net/ljunjie82/article/details/42615233 2.单条循环提交中使用/*+APPEND */的巨大

关于加快INSERT语句执行速度和HINT /*+ append */及/*+ append nologging */的使用

(非归档模式下)创建表T01: SQL> create table t01 as select * from dba_objects where 1=2; Table created. (非归档模式下)查看当前redo大小: SQL> select value 2 from v$mystat,v$statname 3 where v$mystat.statistic#=v$statname.statistic# 4 and v$statname.name='redo size' 5 / VAL