W3Cschool
恭喜您成為首批注冊用戶
獲得88經驗值獎勵
pgbench — 在PostgreSQL上運行一個基準測試
pgbench
-i
[option
...] [dbname
]
pgbench
[option
...] [dbname
]
pgbench是一種在PostgreSQL上運行基準測試的簡單程序。它可能在并發(fā)的數(shù)據庫會話中一遍一遍地運行相同序列的 SQL 命令,并且計算平均事務率(每秒的事務數(shù))。默認情況下,pgbench會測試一種基于 TPC-B 但是要更寬松的場景,其中在每個事務中涉及五個SELECT
、
UPDATE
以及INSERT
命令。但是,通過編寫自己的事務腳本文件很容易用來測試其他情況。
pgbench的典型輸出像這樣:
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 10
query mode: simple
number of clients: 10
number of threads: 1
number of transactions per client: 1000
number of transactions actually processed: 10000/10000
tps = 85.184871 (including connections establishing)
tps = 85.296346 (excluding connections establishing)
前六行報告一些最重要的參數(shù)設置。接下來的行報告完成的事務數(shù)以及預期的事務數(shù)(后者就是客戶端數(shù)量與每個客戶端事務數(shù)的乘積),除非運行在完成之前失敗,這些值應該是相等的(在-T
模式中,只有實際的事務數(shù)會被打印出來)。最后兩行報告每秒的事務數(shù),分別代表包括和不包括開始數(shù)據庫會話所花時間的情況。
默認的類 TPC-B 事務測試要求預先設置好特定的表。可以使用-i
(初始化)選項調用pgbench來創(chuàng)建并且填充這些表(當你在測試一個自定義腳本時,你不需要這一步,但是需要按你自己的測試需要做一些設置工作)。初始化類似這樣:
pgbench -i [ other-options
] dbname
其中dbname
是要在其中進行測試的預先創(chuàng)建好的數(shù)據庫的名稱(你可能還需要-h
、-p
或-U
選項來指定如何連接到數(shù)據庫服務器)。
pgbench -i
會創(chuàng)建四個表pgbench_accounts
、 pgbench_branches
、pgbench_history
以及pgbench_tellers
,如果同名表已經存在會被先刪除。如果你已經有同名表,一定注意要使用另一個數(shù)據庫!
在默認的情況下“比例因子”為 1,這些表初始包含的行數(shù)為:
table # of rows
---------------------------------
pgbench_branches 1
pgbench_tellers 10
pgbench_accounts 100000
pgbench_history 0
你可以使用-s
(比例因子)選項增加行的數(shù)量。-F
(填充因子)選項也可以在這里使用。
一旦你完成了必要的設置,你就可以用不包括-i
的命令運行基準,也就是:
pgbench [ options
] dbname
在近乎所有的情況中,你將需要一些選項來做一次有用的測試。最重要的選項是-c
(客戶端數(shù)量)、 -t
(事務數(shù)量)、-T
(時間限制)以及-f
(指定一個自定義腳本文件)。完整的列表見下文。
下面分成三個部分。數(shù)據庫初始化期間使用的選項和運行基準時會使用不同的選項,但也有一些選項在兩種情況下都使用。
pgbench接受下列命令行初始化參數(shù):
-i
--initialize
要求調用初始化模式。
-I init_steps
--init-steps=init_steps
只執(zhí)行選出的一組普通初始化步驟。init_steps
指定要被執(zhí)行的初始化步驟,每一個步驟使用一個字符代表。每一個步驟都以指定的順序被調用。默認是dtgvp
??捎玫牟襟E是:
d
(刪除)刪除任何已有的pgbench表。
t
(創(chuàng)建表)創(chuàng)建標準pgbench場景使用的表,即pgbench_accounts
、pgbench_branches
、pgbench_history
以及pgbench_tellers
。
g
或G
(生成數(shù)據、客戶端或服務器端)生成數(shù)據并且裝入到標準的表中,替換掉已經存在的任何數(shù)據。
使用 g
(客戶端數(shù)據生成),數(shù)據在 pgbench
客戶端生成,然后發(fā)送到服務器。 這通過 COPY
廣泛使用客戶端/服務器帶寬。 使用 g
會導致日志記錄每 100,000 行打印一條消息,同時為 pgbench_accounts
表生成數(shù)據。
使用G
(服務器端數(shù)據生成),僅從pgbench
客戶端發(fā)送少量查詢,然后在服務器中實際生成數(shù)據。 此變體不需要大量帶寬,但服務器將完成更多工作。 使用G
會導致日志記錄在生成數(shù)據時不打印任何進度消息。
默認的初始化行為使用客戶端數(shù)據生成(相當于g
)。
v
(清理)在標準的表上調用VACUUM
。
p
(創(chuàng)建主鍵)在標準的表上創(chuàng)建主鍵索引。
f
(創(chuàng)建外鍵)在標準的表之間創(chuàng)建外鍵約束(注意這一步默認不會被執(zhí)行)。
-F
fillfactor
--fillfactor=
fillfactor
用給定的填充因子創(chuàng)建表pgbench_accounts
、pgbench_tellers
以及pgbench_branches
。默認是100。
-n
--no-vacuum
在初始化期間不執(zhí)行清理(這個選項會抑制v
初始化步驟,即便在-I
中指定了該步驟)。
-q
--quiet
把記錄切換到安靜模式,只是每 5 秒產生一個進度消息。默認的記錄會每 100,000 行打印一個消息,這經常會在每秒鐘輸出很多行(特別是在好的硬件上)。
如果在 -I
中指定了 G
,則此設置無效。
-s
scale_factor
--scale=
scale_factor
將生成的行數(shù)乘以比例因子。例如,-s 100
將在pgbench_accounts
表中創(chuàng)建 10,000,000 行。默認為 1。當比例為 20,000 或更高時,用來保存賬號標識符的列(aid
列)將切換到使用更大的整數(shù)(bigint
),這樣才能足以保存賬號標識符。
--foreign-keys
在標準的表之間創(chuàng)建外鍵約束(如果f
在初始化步驟序列中不存在,這個選項會把它加入)。
--index-tablespace=index_tablespace
在指定的表空間而不是默認表空間中創(chuàng)建索引。
--partition-method=NAME
使用 NAME
方法創(chuàng)建一個分區(qū)的 pgbench_accounts
表。 預期值為 range
或 hash
。 此選項要求 --partitions
設置為非零。 如果未指定,默認值為 range
。
--partitions=NUM
創(chuàng)建一個分區(qū) pgbench_accounts
表,其中 NUM
分區(qū)的大小與按比例縮放的帳戶數(shù)幾乎相等。 默認為 0
,表示沒有分區(qū)。
--tablespace=tablespace
在指定的表空間而不是默認表空間中創(chuàng)建表。
--unlogged-tables
把所有的表創(chuàng)建為非日志記錄表而不是永久表。
pgbench接受下列命令行基準參數(shù):
-b
scriptname[@weight]
--builtin
=scriptname[@weight]
把指定的內建腳本加入到要執(zhí)行的腳本列表中。@
之后是一個可選的整數(shù)權重,它允許調節(jié)抽取該腳本的可能性。如果沒有指定,它會被設置為 1??捎玫膬冉_本有:tpcb-like
、simple-update
和select-only
。這里也接受內建名稱無歧義的前綴縮寫。如果用上特殊的名字
list
,將會顯示內建腳本的列表并且立刻退出。
-c
clients
--client=
clients
模擬的客戶端數(shù)量,也就是并發(fā)數(shù)據庫會話數(shù)量。默認為 1。
-C
--connect
為每一個事務建立一個新連接,而不是只為每個客戶端會話建立一個連接。這對于度量連接開銷有用。
-d
--debug
打印調試輸出。
-D
varname
=
value
--define=
varname
=
value
定義一個由自定義腳本(見下文)使用的變量。允許多個-D
選項。
-f
filename[@weight]
--file=
filename[@weight]
把一個從filename
讀到的事務腳本加入到被執(zhí)行的腳本列表中。@
后面是一個可選的整數(shù)權重,它允許調節(jié)抽取該測試的可能性。詳見下文。
-j
threads
--jobs=
threads
pgbench中的工作者線程數(shù)量。在多 CPU 機器上使用多于一個線程會有用??蛻舳藭M可能均勻地分布到可用的線程上。默認為 1。
-l
--log
把與每一個事務相關的信息寫到一個日志文件中。詳見下文。
-L
limit
--latency-limit=
limit
對持續(xù)超過limit
毫秒的事務進行獨立的計數(shù)和報告, 這些事務被認為是遲到(late)了的事務。
在使用限流措施時(--rate=...
),滯后于計劃超過 limit
毫秒并且因此沒有希望滿足延遲限制的事務根本 不會被發(fā)送給服務器。這些事務被認為是被跳過(skipped)
的事務,它們會被單獨計數(shù)并且報告。
-M
querymode
--protocol=
querymode
要用來提交查詢到服務器的協(xié)議:
simple
:使用簡單查詢協(xié)議。
extended
使用擴展查詢協(xié)議。
prepared
:使用帶預備語句的擴展查詢語句。
在prepared
模式中,pgbench重用從第二次查詢迭代開始的語法分析結果,因此pgbench運行速度比其他模式快。
默認是簡單查詢協(xié)議(詳見第 52 章)。
-n
--no-vacuum
在運行測試前不進行清理。如果你在運行一個不包括標準的表pgbench_accounts
、 pgbench_branches
、pgbench_history
和 pgbench_tellers
的自定義測試場景時,這個選項是必需的。
-N
--skip-some-updates
運行內建的簡單更新腳本。這是-b simple-update
的簡寫。
-P
sec
--progress=
sec
每sec
秒顯示進度報告。該報告包括運行了多長時間、從上次報告以來的 tps 以及從上次報告以來事務延遲的平均值和標準偏差。如果低于限流值(-R
),延遲會相對于事務預定的開始時間(而不是實際的事務開始時間)計算,因此其中也包括了平均調度延遲時間。
-r
--report-latencies
在基準結束后,報告平均的每個命令的每語句等待時間(從客戶端的角度來說是執(zhí)行時間)。詳見下文。
-R
rate
--rate=
rate
按照指定的速率執(zhí)行事務而不是盡可能快地執(zhí)行(默認行為)。該速率 以 tps(每秒事務數(shù))形式給定。如果目標速率高于最大可能速率,則 該速率限制不會影響結果。
該速率的目標是按照一條泊松分布的調度時間線開始事務。期望的開始 時間表會基于客戶端第一次開始的時間(而不是上一個事務結束的時 間)前移。這種方法意味著當事務超過它們的原定結束時間時,更遲的 那些有機會再次追趕上來。
當限流措施被激活時,運行結束時報告的事務延遲是從預訂的開始時間計 算而來的,因此它包括每一個事務不得不等待前一個事務結束所花的時 間。該等待時間被稱作調度延遲時間,并且它的平均值和最大值也會被 單獨報告。關于實際事務開始時間的事務延遲(即在數(shù)據庫中執(zhí)行事務 所花的時間)可以用報告的延遲減去調度延遲時間計算得到。
如果把--latency-limit
和--rate
一起使用, 當一個事務在前一個事務結束時已經超過了延遲限制時,它可能會滯后 非常多,因為延遲是從計劃的開始時間計算得來。這類事務不會被發(fā)送 給服務器,而是一起被跳過并且被單獨計數(shù)。
一個高的調度延遲時間表示系統(tǒng)無法用選定的客戶端和線程數(shù)按照指定 的速率處理事務。當平均的事務執(zhí)行時間超過每個事務之間的調度間隔 時,每一個后續(xù)事務將會落后更多,并且隨著測試運行時間越長,調度 延遲時間將持續(xù)增加。發(fā)生這種情況時,你將不得不降低指定的事務速率。
-s
scale_factor
--scale=
scale_factor
在pgbench的輸出中報告指定的比例因子。對于內建測試,這并非必需;正確的比例因子將通過對pgbench_branches
表中的行計數(shù)來檢測。不過,當只測試自定義基準(-f
選項)時,比例因子將被報告為 1(除非使用了這個選項)。
-S
--select-only
執(zhí)行內建的只有選擇的腳本。是-b select-only
簡寫形式。
-t
transactions
--transactions=
transactions
每個客戶端運行的事務數(shù)量。默認為 10。
-T
seconds
--time=
seconds
運行測試這么多秒,而不是為每個客戶端運行固定數(shù)量的事務。-t
和-T
是互斥的。
-v
--vacuum-all
在運行測試前清理所有四個標準的表。在沒有用-n
以及-v
時, pgbench將清理pgbench_tellers
和pgbench_branches
表,并且截斷pgbench_history
。
--aggregate-interval=seconds
聚集區(qū)間的長度(單位是秒)。僅可以與-l
選項一起使用。通過這個選項,日志會包含針對每個區(qū)間的概要數(shù)據,如下文所述。
--log-prefix=prefix
設置--log
創(chuàng)建的日志文件的文件名前綴。默認是pgbench_log
。
--progress-timestamp
當顯示進度(選項-P
)時,使用一個時間戳(Unix 時間)取代從運行開始的秒數(shù)。單位是秒,在小數(shù)點后是毫秒精度。這可以有助于比較多種工具生成的日志。
--random-seed=
seed
設置隨機數(shù)生成器種子。為系統(tǒng)的隨機數(shù)生成器提供種子,然后隨機數(shù)生成器會產生一個初始生成器狀態(tài)序列,每一個線程一個狀態(tài)。seed
的值可以是:time
(默認值,種子基于當前時間)、rand
(使用一種強隨機源,如果沒有可用的源則失?。┗蛘咭粋€無符號十進制整數(shù)值。一個pgbench腳本中會顯式(
random...
函數(shù))地或者隱式地(如--rate
使用隨機數(shù)生成器調度事務)調用隨機數(shù)生成器。在被明確設置時,用作種子的值會顯示在終端上。 還可以通過環(huán)境變量PGBENCH_RANDOM_SEED
提供用于seed
的值。為了確保所提供的種子影響所有可能的使用,把這個選項放在第一位或者使用環(huán)境變量。
明確地設置種子允許準確地再生一個pgbench
運行,對隨機數(shù)而言。因為隨機狀態(tài)是針對每個線程管理,這意味著如果每一個線程有一個客戶端并且沒有外部或者數(shù)據依賴,則對于一個相同的調用就會有完全相同的pgbench
運行。從一種統(tǒng)計的角度來看,再生運行不是什么好主意,因為它能隱藏性能可變性或者不正當?shù)馗倪M性能,即通過命中前一次運行的相同頁面來改進性能。不過,它也可以對調試起到很大幫助作用,例如重新運行一種導致錯誤的棘手用例。請善用。
--sampling-rate=rate
采樣率,在寫入數(shù)據到日志時被用來減少日志產生的數(shù)量。如果給出這個選項,只有指定比例的事務被記錄。1.0 表示所有事務都將被記錄,0.05 表示只有 5% 的事務會被記錄。
在處理日志文件時,記得要考慮這個采樣率。例如,當計算TPS值時,你需要相應地乘以這個數(shù)字(例如,采樣率是 0.01,你將只能得到實際TPS的 1/100)。
--show-script=
scriptname
在 stderr 上顯示內置腳本 scriptname
的實際代碼,并立即退出。
pgbench 還接受以下用于連接參數(shù)的常見命令行參數(shù):
-h
hostname
--host=
hostname
數(shù)據庫服務器的主機名
-p
port
--port=
port
數(shù)據庫服務器的端口號
-U
login
--username=
login
要作為哪個用戶連接
-V
--version
打印pgbench版本并退出。
-?
--help
顯示有關pgbench命令行參數(shù)的信息,并且退出。
成功運行將以狀態(tài)0退出。 退出狀態(tài)為1表示靜態(tài)問題,如無效的命令行選項。 運行過程中的錯誤,例如數(shù)據庫錯誤或腳本中的問題將導致退出狀態(tài)為2。 在后一種情況下,pgbench將打印部分結果。
PGHOST
PGPORT
PGUSER
默認連接參數(shù)。
此實用程序與大多數(shù)其他 PostgreSQL 實用程序一樣,使用 libpq 支持的環(huán)境變量(請參閱 第 33.14 節(jié))。
環(huán)境變量 PG_COLOR
指定是否在診斷消息中使用顏色。 可能的值是always
、auto
和 never
.
pgbench執(zhí)行從指定列表中隨機選中的測試腳本。它們包括帶有-b
的內建腳本和帶有-f
的用戶提供的自定義腳本。每一個腳本可以在其后用@
指定一個相對權重,這樣可以更改該腳本的抽取概率。默認權重是1
。權重為
0
的腳本會被忽略。
默認的內建事務腳本(也會被-b tpcb-like
調用)會在每個事務上發(fā)出七個從aid
、tid
、bid
和delta
中隨機選擇的命令。該場景來自于 TPC-B 基準,但并不是真正的 TPC-B,只是名字像而已。
BEGIN;
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
END;
如果選擇simple-update
內建腳本(還有-N
),第 4 和 5 步不會被包括在事務中。這將避免更新那些表中的內容,但是它會讓該測試用例更不像 TPC-B。
如果選擇select-only
內建腳本(還有-S
),只會發(fā)出SELECT
。
pgbench支持通過從一個文件中(-f
選項)讀取事務腳本替換默認的事務腳本(如上文所述)來運行自定義的基準場景。在這種情況中,一個“事務”就是一個腳本文件的一次執(zhí)行。
腳本文件包含一個或者多個被分號終結的 SQL 命令。空行以及以--
開始的行會被忽略。腳本文件也可以包含“元命令”,它會由pgbench自身解釋,詳見下文。
在PostgreSQL 9.6 之前,腳本文件中的 SQL 命令被新行終結,因此命令不能跨行?,F(xiàn)在需要分號來分隔連續(xù)的 SQL 命令(如果 SQL 命令后面跟著一個元命令則不需要一個分號)。如果需要創(chuàng)建一個能在新舊版本pgbench下工作的腳本文件,要確保把每個 SQL 命令寫在一個由分號終結的行中。
對腳本文件有一種簡單的變量替換功能。變量名必須由字母(包括非拉丁字母)、數(shù)字以及下劃線構成。如上所述,變量可以用命令行的 -D
選項設置,或者按下文所說的使用元命令設置。 除了用-D
命令行選項預先設置的任何變量之外, 還有一些被自動預先設置的變量,它們被列在 本文的表 273中。一個用
-D
為這些變量值指定的值會優(yōu)先于自動的預設值。 一旦被設置,可以在 SQL 命令中寫:
variablename
來插入一個變量的值。當運行多于一個客戶端會話時,每一個會話擁有它自己的變量集合。 pgbench在一個語句中支持使用多達255個變量。
表 273. pgbench 自動變量
變量 | 簡介 |
---|---|
client_id
|
標識客戶端會話的唯一編號(從零開始) |
default_seed
|
默認在哈希函數(shù)中使用的種子 |
random_seed
|
隨機數(shù)生成器種子(除非用-D 重載) |
scale
|
當前的縮放因子 |
腳本文件元命令以反斜線(\
)開始并且通常延伸到行的末尾,不過它們也能夠通過寫一個反斜線回車繼續(xù)到額外行。一個元命令和它的參數(shù)用空白分隔。支持的元命令是:
\gset [prefix
]
\aset [prefix
]
這些命令可以用于結束 SQL 查詢,代替終止分號 (;
)。
當使用\gset
命令時,前面的 SQL 查詢預期返回一行,存儲變量名的列在列名后面,如果已經提供的話,則以prefix
作為前綴。
使用\aset
命令時,所有組合的SQL查詢(由\;
分隔)將其列存儲到以列名命名的變量中,如果提供,則以前綴
作為前綴。如果查詢不返回任何行,則不進行賦值,并且可以測試變量是否存在以檢測這一點。如果查詢返回多行,則保留最后一個值。
下面的示例將第一個查詢中的最終帳戶余額放入變量abalance
, 并且用第三個查詢中的整數(shù)填充變量p_two
和p_three
。 第二個查詢的結果將被丟棄。 最后兩個組合查詢的結果存儲在變量four
和
five
中。
UPDATE pgbench_accounts
SET abalance = abalance + :delta
WHERE aid = :aid
RETURNING abalance \gset
-- compound of two queries
SELECT 1 \;
SELECT 2 AS two, 3 AS three \gset p_
SELECT 4 AS four \; SELECT 5 AS five \aset
\if
expression
\elif
expression
\else
\endif
這一組命令實現(xiàn)了可嵌套的條件塊,類似于psql
的\if
expression
。條件表達式與\set
的相同,非零值會被解釋為真。
\set varname
expression
設置變量varname
為一個從expression
計算出的值。該表達式可以包含NULL
常量、布爾常量TRUE
和FALSE
、5432
這樣的整數(shù)常量、
3.14159
這樣的double常量、對變量的引用:
variablename
、 本文中的 內建操作符(保持它們通常的SQL優(yōu)先級和結合性)、本文中的內建函數(shù)、 SQL CASE
一般條件表達式以及括號。
函數(shù)和大部分操作符在NULL
輸入上會返回NULL
。
對于條件目的,非零數(shù)字值是TRUE
,數(shù)字零值以及NULL
是FALSE
。
太大或太小的整數(shù)和雙常量,以及整數(shù)算術運算符(+
,-
, *
和 /
)會引發(fā)溢出錯誤。
在沒有為CASE
提供最終的ELSE
子句時,默認值是NULL
。
示例:
\set ntellers 10 * :scale
\set aid (1021 * random(1, 100000 * :scale)) % \
(100000 * :scale) + 1
\set divx CASE WHEN :x <> 0 THEN :y/:x ELSE NULL END
\sleep number
[ us | ms | s ]
導致腳本執(zhí)行休眠指定的時間,時間的單位可以是微妙(us
)、毫秒(ms
)或者秒(s
)。如果單位被忽略,則秒是默認值。number
要么是一個整數(shù)常量,要么是一個引用了具有整數(shù)值的變量的:
variablename
。
例子:
\sleep 10 ms
\setshell varname
command
[ argument
... ]
用給定的argument
設置變量varname
為 shell 命令command
的結果。該命令必須通過它的標準輸出返回一個整數(shù)值。
command
和每個argument
要么是一個文本常量,要么是一個引用了一個變量的:
variablename
。如果你想要使用以冒號開始的argument
,在
argument
的開頭寫一個額外的冒號。
例子:
\setshell variable_to_be_assigned command literal_argument :variable ::literal_starting_with_colon
\shell command
[ argument
... ]
與\setshell
相同,但是結果被拋棄。
例子:
\shell command literal_argument :variable ::literal_starting_with_colon
表 274中列舉的算數(shù)、按位、比較以及邏輯操作符都被編譯到了pgbench中并且可以被用于\set
中出現(xiàn)的表達式中。
運算符以升序排列。 除非另有說明,如果任一輸入為雙精度,則采用兩個數(shù)字輸入的運算符將產生雙精度值,否則產生整數(shù)結果。
表 274. pgbench操作符
操作符 簡介 例子 |
---|
邏輯或 |
邏輯與 |
邏輯非 |
布爾值測試 |
空測試 |
等于 |
不等于 |
不等于 |
小于 |
小于等于 |
大于 |
大于等于 |
按位或 |
按位異或 |
按位與 |
按位非 |
按位左移 |
按位右移 |
加 |
減 |
乘 |
除法(如果兩個輸入都是整數(shù),則將結果截斷為零) |
模(余數(shù)) |
取反 |
表 275中列出的函數(shù)被編譯在pgbench中,并且可能被用在出現(xiàn)于\set
的表達式中。
表 275. pgbench 函數(shù)
函數(shù) 簡介 例子 |
---|
絕對值 |
將參數(shù)打印到stderr,并返回參數(shù)。 |
造型成double。 |
指數(shù)( |
選擇參數(shù)中的最大值。 |
這是 |
計算 FNV-1a hash。 |
計算 MurmurHash2 hash. |
造型成int。 |
選擇參數(shù)中的最小值。 |
自然對數(shù) |
模(余數(shù)) |
π的近似值 |
|
計算 |
計算 |
計算 |
計算 |
平方根 |
random
函數(shù)使用均勻分布生成值,即所有的值都以相等的概率從指定的范圍中抽出。random_exponential
、random_gaussian
以及random_zipfian
函數(shù)要求一個額外的 double 參數(shù),它決定分布的精確形狀。
對于指數(shù)分布,parameter
通過在parameter
處截斷一個快速下降的指數(shù)分布來控制分布,然后投影到邊界之間的整數(shù)上。確切地來說,
f(x) = exp(-parameter * (x - min) / (max - min + 1)) / (1 - exp(-parameter))
然后min
和max
之間(包括兩者)的值i
會被以概率f(i) - f(i + 1)
抽出。
直觀上,parameter
越大,接近min
的值會被越頻繁地訪問,并且接近max
的值會被越少訪問。parameter
越接近 0,訪問分布會越平坦(更均勻)。該分布的粗近似值是范圍中當時被抽取
parameter
% 次接近min
的最頻繁的 1% 值。parameter
值必須嚴格為正。
對于高斯分布,區(qū)間被映射到一個在左邊-parameter
和右邊+parameter
截斷的標準正態(tài)分布(經典鐘型高斯曲線)。區(qū)間中間的值更可能被抽到。準確地說,如果PHI(x)
是標準正態(tài)分布的累計分布函數(shù),均值mu
定義為(max + min) / 2.0
,有
f(x) = PHI(2.0 * parameter * (x - mu) / (max - min + 1)) /
(2.0 * PHI(parameter) - 1)
則min
和max
(包括兩者)之間的值i
被抽出的概率是:f(i + 0.5) - f(i - 0.5)
。直觀上,parameter
越大,靠近區(qū)間終端的值會被越頻繁地抽出,并且靠近上下界兩端的值會被更少抽出。大約
67% 的值會被從中間1.0 / parameter
的地方抽出,即均值周圍0.5 / parameter
的地方。并且 95% 的值會被從中間2.0 / parameter
的地方抽出,即均值周圍1.0 / parameter
的地方。例如,如果parameter
是
4.0,67% 的值會被從該區(qū)間的中間四分之一(1.0 / 4.0)抽出(即從3.0 / 8.0
到5.0 / 8.0
)。并且 95% 的值會從該區(qū)間的中間一半(2.0 / 4.0
)抽出(第二和第三四分位)。最小允許的parameter
值為 2.0。
random_zipfian
生成一個有界的Zipfian分布。 parameter
定義該分布有多么傾斜。parameter
越大,繪制越接近間隔開頭的值越頻繁。 分布是這樣的,假設范圍從1開始,繪制k
與繪制
k+1
的概率之比為 ((
。 例如,k
+1)/k
)**parameter
random_zipfian(1, ..., 2.5)
生成值1
大約(2/1)**2.5 =
5.66
次,比 2
更頻繁,它本身被產生(3/2)**2.5 = 2.76
次, 比3
更頻繁,依此類推。
pgbench的實現(xiàn)是基于"Non-Uniform Random Variate Generation", Luc Devroye, p. 550-551,Springer 1986。 由于該算法的限制,parameter
值限制范圍為[1.001, 1000]。
哈希函數(shù)hash
、hash_murmur2
以及hash_fnv1a
接受一個輸入值和一個可選的種子參數(shù)。在沒有提供種子的情況下,會使用:default_seed
的值,該變量會被隨機地初始化,除非用命令行的-D
選項重載。哈希函數(shù)可以被用于分散
random_zipfian
或random_exponential
這樣的隨機函數(shù)的分布。例如,下列pgbench腳本模擬了社交媒體和博客平臺上很常見的真實負載,其中少數(shù)賬號產生了過量的負載:
\set r random_zipfian(0, 100000000, 1.07)
\set k abs(hash(:r)) % 1000000
在一些情況中需要幾個不同的分布,它們彼此之間不相關并且隱式的隨機數(shù)參數(shù)在此時就能派上用場:
\set k1 abs(hash(:r, :default_seed + 123)) % 1000000
\set k2 abs(hash(:r, :default_seed + 321)) % 1000000
作為一個例子,內建的類 TPC-B 事務的全部定義是:
\set aid random(1, 100000 * :scale)
\set bid random(1, 1 * :scale)
\set tid random(1, 10 * :scale)
\set delta random(-5000, 5000)
BEGIN;
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
END;
這個腳本允許該事務的每一次迭代能夠引用不同的、被隨機選擇的行(這個例子也展示了為什么讓每一個客戶端會話有其自己的變量很重要 — 否則它們不會獨立地接觸不同的行)。
通過-l
選項(但是沒有--aggregate-interval
選項),pgbench把關于每個事務的信息寫入到一個日志文件。該日志文件將被命名為
,其中prefix
.nnn
prefix
默認為pgbench_log
,而nnn
是pgbench進程的PID。前綴可以用--log-prefix
選項更改。如果-j
選項是2或者更高(有多個工作者線程),那么每一個工作者線程將會有它自己的日志文件。第一個工作者的日志文件的命名將和標準的單工作者情況相同。其他工作者的額外日志文件將被命名為
,其中prefix
.nnn
.mmm
mmm
是每個工作者的一個序列號,這種序列號從1開始編。
日志的格式是:
client_id
transaction_no
time
script_no
time_epoch
time_us
[ schedule_lag
]
其中client_id
表示哪個客戶端會話運行該事務,transaction_no
是那個會話已經運行了多少個事務的計數(shù),time
是以微秒計的總共用掉的事務時間,script_no
標識了要使用哪個腳本文件(當用
-f
或者-b
指定多個腳本時有用),而time_epoch
/time_us
是一個 Unix 紀元格式的時間戳以及一個顯示事務完成時間的以微秒計的偏移量(適合于創(chuàng)建一個帶有分數(shù)秒的 ISO 8601 時間戳)。 域schedule_lag
是事務的預定開始時間和實際開始時間之間的差別,以微秒計。只有使用
--rate
選項時它才存在。當--rate
和--latency-limit
同時被使用時, 一個被跳過的事務的time
會被報告為skipped
。
這里是在單個客戶端運行中生成的一個日志文件的片段:
0 199 2241 0 1175850568 995598
0 200 2465 0 1175850568 998079
0 201 2513 0 1175850569 608
0 202 2038 0 1175850569 2663
另一個例子使用的是--rate=100
以及--latency-limit=5
(注意額外的 schedule_lag
列):
0 81 4621 0 1412881037 912698 3005
0 82 6173 0 1412881037 914578 4304
0 83 skipped 0 1412881037 914578 5217
0 83 skipped 0 1412881037 914578 5099
0 83 4722 0 1412881037 916203 3108
0 84 4142 0 1412881037 918023 2333
0 85 2465 0 1412881037 919759 740
在這個例子中,事務 82 遲到了,因為它的延遲(6.173 ms)超過了 5 ms 限制。接下來的兩個事務被跳過,因為它們在開始之前就已經遲到了。
在能夠處理大量事務的硬件上運行一次長時間的測試時,日志文件可能變得非常大。--sampling-rate
選項能被用來只記錄事務的一個隨機采樣。
通過--aggregate-interval
選項,日志文件會使用一種不同的格式:
interval_start
num_transactions
? sum_latency
sum_latency_2
min_latency
max_latency
? [ sum_lag
sum_lag_2
min_lag
max_lag
[ skipped
] ]
其中interval_start
是區(qū)間的開始(作為一個Unix紀元的時間戳)、num_transactions
是該區(qū)間中的事務數(shù)、sum_latency
是該區(qū)間中事務時延的總量、sum_latency_2
是該區(qū)間中事務時延的平方和、
min_latency
是該區(qū)間中的最小時延、max_latency
是該區(qū)間中的最大時延。接下來的字段sum_lag
、sum_lag_2
、min_lag
以及max_lag
只有在使用
--rate
選項時才存在。它們提供每個事務要等待前一個事務完成所花的時間的統(tǒng)計信息,即每個事務的計劃啟動時間與實際啟動時間之間的差值。最后一個字段skipped
只有在使用--latency-limit
選項時才存在。它對因為啟動過完被跳過的事務進行計數(shù)。每一個事務被計入在其提交時的區(qū)間中。
這里是一些輸出示例:
1345828501 5601 1542744 483552416 61 2573
1345828503 7884 1979812 565806736 60 1479
1345828505 7208 1979422 567277552 59 1391
1345828507 7685 1980268 569784714 60 1398
1345828509 7073 1979779 573489941 236 1411
注意雖然純(非聚合)日志文件顯示為每個事務使用了哪個腳本,但聚合日志卻不包含索引。因此如果你需要針對每個腳本的數(shù)據,你需要自行聚合數(shù)據。
通過-r
選項,pgbench收集每一個客戶端執(zhí)行的每一個語句花費的事務時間。然后在基準完成后,它會報告這些值的平均值,作為每個語句的延遲。
對于默認腳本,輸出看起來會像這樣:
starting vacuum...end.
transaction type: <builtin: TPC-B (sort of)>
scaling factor: 1
query mode: simple
number of clients: 10
number of threads: 1
number of transactions per client: 1000
number of transactions actually processed: 10000/10000
latency average = 15.844 ms
latency stddev = 2.715 ms
tps = 618.764555 (including connections establishing)
tps = 622.977698 (excluding connections establishing)
statement latencies in milliseconds:
0.002 \set aid random(1, 100000 * :scale)
0.005 \set bid random(1, 1 * :scale)
0.002 \set tid random(1, 10 * :scale)
0.001 \set delta random(-5000, 5000)
0.326 BEGIN;
0.603 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
0.454 SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
5.528 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
7.335 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
0.371 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
1.212 END;
如果指定了多個腳本文件,會為每一個腳本文件單獨報告平均值。
注意為每個語句的延遲計算收集額外的時間信息會增加一些負荷。這將拖慢平均執(zhí)行速度并且降低計算出的 TPS。降低的總量會很顯著地依賴于平臺和硬件。對比使用和不適用延遲報告時的平均 TPS 值是評估時間開銷是否明顯的好方法。
很容易使用pgbench產生完全沒有意義的數(shù)字。這里有一些指導可以幫你得到有用的結果。
排在第一位的是,永遠不要相信任何只運行了幾秒的測試。使用-t
或-T
選項讓運行持續(xù)至少幾分鐘,這樣可以用平均值去掉噪聲。在一些情況中,你可能需要數(shù)小時來得到能重現(xiàn)的數(shù)字。多運行幾次測試是一個好主意,這樣可以看看你的數(shù)字是不是可以重現(xiàn)。
對于默認的類 TPC-B 測試場景,初始化的比例因子(-s
)應該至少和你想要測試的最大客戶端數(shù)量一樣大(-c
),否則你將主要在度量更新爭奪。在pgbench_branches
表中只有-s
行,并且每個事務都想更新其中之一,因此-c
值超過
-s
將毫無疑問地導致大量事務被阻塞來等待其他事務。
默認的測試場景也對表被初始化了多久非常敏感:表中死亡行和死亡空間的累積會改變結果。要理解結果,你必須跟蹤更新的總數(shù)以及何時發(fā)生清理。如果開啟了自動清理,它可能會在度量的性能上產生不可預估的改變。
pgbench的一個限制是在嘗試測試大量客戶端會話時,它自身可能成為瓶頸。這可以通過在數(shù)據庫服務器之外的一臺機器上運行pgbench來緩解,不過必須是具有低網絡延遲的機器。甚至可以在多個客戶端機器上針對同一個數(shù)據庫服務器并發(fā)地運行多個pgbench實例。
如果不可信用戶能夠訪問沒有采用安全方案使用模式的數(shù)據庫,不要在那個數(shù)據庫中運行pgbench。pgbench使用非限定名稱并且不會操縱搜索路徑。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: