原文地址: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個位元組。