pgbench — 在 PostgreSQL 上執行基準測試
pgbench
-i
[option
...] [dbname
]
pgbench
[option
...] [dbname
]
pgbench 是一個簡單的程式,用於在 PostgreSQL 上執行基準測試。它會一遍又一遍地執行相同的 SQL 命令序列,可能會在多個並行的資料庫連線中執行,然後計算平均交易速率(每秒交易數)。預設情況下,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 maximum number of tries: 1 number of transactions per client: 1000 number of transactions actually processed: 10000/10000 number of failed transactions: 0 (0.000%) latency average = 11.013 ms latency stddev = 7.351 ms initial connection time = 45.758 ms tps = 896.967014 (without initial connection time)
前七行報告了一些最重要的參數設定。第六行報告了具有序列化或死鎖錯誤的交易的最大嘗試次數(有關更多資訊,請參閱故障和序列化/死鎖重試)。第八行報告了已完成和預期的交易數量(後者只是客戶端數量和每個客戶端交易數量的乘積);除非執行在完成之前失敗或某些 SQL 命令失敗,否則這些數字將相等。(在 -T
模式下,僅列印實際的交易數量。)下一行報告了由於序列化或死鎖錯誤而失敗的交易數量(有關更多資訊,請參閱故障和序列化/死鎖重試)。最後一行報告了每秒的交易數量。
預設的類似 TPC-B 的交易測試需要事先設定特定的表格。pgbench 應該使用 -i
(初始化)選項來呼叫,以建立和填充這些表格。(當您測試自訂腳本時,您不需要此步驟,而是需要執行測試所需的任何設定。)初始化如下所示
pgbench -i [other-options
]dbname
其中 dbname
是要測試的已建立資料庫的名稱。(您可能還需要 -h
、-p
和/或 -U
選項來指定如何連線到資料庫伺服器。)
pgbench -i
會建立四個表格 pgbench_accounts
、pgbench_branches
、pgbench_history
和 pgbench_tellers
,從而銷毀任何具有這些名稱的現有表格。如果您有具有這些名稱的表格,請務必小心使用另一個資料庫!
在預設的 「比例因子」為 1 時,這些表格最初包含以下多行
table # of rows --------------------------------- pgbench_branches 1 pgbench_tellers 10 pgbench_accounts 100000 pgbench_history 0
您可以使用 -s
(比例因子)選項來增加行數(並且,對於大多數用途,可能應該這樣做)。此時也可以使用 -F
(填滿因子)選項。
完成必要的設定後,您可以使用不包含 -i
的命令來執行基準測試,即
pgbench [options
]dbname
在幾乎所有情況下,您都需要一些選項才能進行有用的測試。最重要的選項是 -c
(客戶端數量)、-t
(交易數量)、-T
(時間限制)和 -f
(指定自訂腳本檔案)。請參閱下文以取得完整列表。
以下內容分為三個小節。不同的選項在資料庫初始化和執行基準測試期間使用,但某些選項在這兩種情況下都很有用。
pgbench 接受以下命令列初始化引數
[-d] dbname
[--dbname=]dbname
#指定要測試的資料庫名稱。如果未指定,則使用環境變數 PGDATABASE
。如果未設定,則使用為連線指定的用戶名稱。
-i
--initialize
#需要呼叫初始化模式。
-I init_steps
--init-steps=init_steps
#僅執行一組選定的常規初始化步驟。init_steps
指定要執行的初始化步驟,每個步驟使用一個字元。每個步驟都按指定的順序呼叫。預設值為 dtgvp
。可用的步驟包括
d
(Drop) #捨棄任何現有的 pgbench 表格。
t
(create Tables) #建立標準 pgbench 方案使用的表格,即 pgbench_accounts
、pgbench_branches
、pgbench_history
和 pgbench_tellers
。
g
或 G
(Generate data, client-side or server-side) #產生資料並將其載入到標準表格中,取代任何已存在的資料。
使用 g
(用戶端資料生成) 時,資料會在 pgbench
用戶端生成,然後傳送到伺服器。這會透過 COPY
大量使用用戶端/伺服器頻寬。pgbench
會搭配 PostgreSQL 14 或更新版本使用 FREEZE
選項,以加速後續的 VACUUM
,除非是在啟用分割區時的 pgbench_accounts
資料表。使用 g
會導致記錄檔在為所有資料表生成資料時,每 100,000 列印出一則訊息。
使用 G
(伺服器端資料生成) 時,只會從 pgbench
用戶端傳送小型查詢,然後實際在伺服器中生成資料。這種變體不需要大量頻寬,但伺服器會執行更多工作。使用 G
會導致記錄檔在生成資料時不印出任何進度訊息。
預設的初始化行為是使用用戶端資料生成 (等同於 g
)。
v
(Vacuum) #在標準資料表上呼叫 VACUUM
。
p
(create Primary keys) #在標準資料表上建立主鍵索引。
f
(create Foreign keys) #在標準資料表之間建立外鍵約束。(請注意,預設不會執行此步驟。)
-F
fillfactor
--fillfactor=
fillfactor
#使用給定的填滿因子 (fillfactor) 建立 pgbench_accounts
、pgbench_tellers
和 pgbench_branches
資料表。預設值為 100。
-n
--no-vacuum
#在初始化期間不執行 vacuuming。(即使在 -I
中指定了 v
初始化步驟,此選項也會抑制它。)
-q
--quiet
#將記錄切換到靜音模式,每 5 秒鐘僅產生一則進度訊息。預設記錄會每 100,000 列印出一則訊息,這通常會每秒輸出許多行 (尤其是在良好的硬體上)。
如果在 -I
中指定了 G
,則此設定無效。
-s
scale_factor
--scale=
scale_factor
#將產生的列數乘以比例因子 (scale factor)。例如,-s 100
將在 pgbench_accounts
資料表中建立 10,000,000 列。預設值為 1。當比例為 20,000 或更大時,用於保存帳戶識別碼的欄位 (aid
欄位) 將切換為使用更大的整數 (bigint
),以便足以保存帳戶識別碼的範圍。
--foreign-keys
#在標準資料表之間建立外鍵約束。(如果初始化步驟序列中尚未存在 f
步驟,此選項會將其新增到序列中。)
--index-tablespace=index_tablespace
#在指定的資料表空間中建立索引,而不是在預設資料表空間中建立。
--partition-method=NAME
#使用 NAME
方法建立分割的 pgbench_accounts
資料表。預期值為 range
或 hash
。此選項要求將 --partitions
設定為非零值。如果未指定,則預設為 range
。
--partitions=NUM
#建立一個分割的 pgbench_accounts
資料表,其中包含 NUM
個大小幾乎相等的分割區,用於調整後的帳戶數量。預設值為 0
,表示不進行分割。
--tablespace=tablespace
#在指定的資料表空間中建立資料表,而不是在預設資料表空間中建立。
--unlogged-tables
#將所有資料表建立為未記錄的資料表,而不是永久資料表。
pgbench 接受以下命令列效能評估參數
-b
scriptname[@weight]
--builtin
=scriptname[@weight]
#將指定的內建指令碼新增到要執行的指令碼清單中。可用的內建指令碼有:tpcb-like
、simple-update
和 select-only
。接受內建名稱的明確前置詞。使用特殊名稱 list
,顯示內建指令碼清單並立即結束。
您可以選擇在 @
後面寫入一個整數權重,以調整選擇此指令碼相對於其他指令碼的機率。預設權重為 1。有關詳細資訊,請參閱下文。
-c
clients
--client=
clients
#模擬的用戶端數量,也就是並行資料庫連線數量。預設值為 1。
-C
--connect
#為每個事務建立一個新連線,而不是每個用戶端工作階段只建立一次。這對於測量連線開銷很有用。
-D
varname
=
value
--define=
varname
=
value
#定義一個變數以供自訂指令碼使用(請參閱下文)。允許多個 -D
選項。
-f
filename[@weight]
--file=
filename[@weight]
#將從 filename
讀取的事務指令碼新增到要執行的指令碼清單中。
您可以選擇在 @
後面寫入一個整數權重,以調整選擇此指令碼相對於其他指令碼的機率。預設權重為 1。(若要使用包含 @
字元的指令碼檔案名稱,請附加一個權重,使其沒有歧義,例如 filen@me@1
。)有關詳細資訊,請參閱下文。
-j
threads
--jobs=
threads
#pgbench 內的工作執行緒數。在多 CPU 電腦上使用多個執行緒可能會有所幫助。用戶端會盡可能均勻地分佈在可用的執行緒中。預設值為 1。
-l
--log
#將有關每個事務的資訊寫入記錄檔。有關詳細資訊,請參閱下文。
-L
limit
--latency-limit=
limit
#如果交易持續時間超過 limit
毫秒,則會將其視為 延遲 交易,並獨立計算和報告。
當使用節流 (throttling) 功能 (使用 --rate=...
) 時,如果交易的延遲時間超過排程時間 limit
毫秒,因而無法符合延遲限制,則不會將其傳送至伺服器。這些交易會被視為 略過 交易,並獨立計算和報告。
當使用 --max-tries
選項時,若交易因序列化異常 (serialization anomaly) 或死鎖而失敗,且所有重試的總時間大於 limit
毫秒,則不會重試該交易。若要僅限制重試的時間而非次數,請使用 --max-tries=0
。預設情況下,--max-tries
選項設定為 1,且具有序列化/死鎖錯誤的交易不會重試。有關重試此類交易的更多資訊,請參閱 失敗和序列化/死鎖重試。
-M
querymode
--protocol=
querymode
#用來將查詢提交到伺服器的協定。
simple
:使用簡單查詢協定。
extended
:使用擴充查詢協定。
prepared
:使用帶有預備語句 (prepared statements) 的擴充查詢協定。
在 prepared
模式下,pgbench 從第二次查詢迭代開始,重複使用解析分析結果,因此 pgbench 的運行速度比其他模式快。
預設是簡單查詢協定。(請參閱 第 53 章 以取得更多資訊。)
-n
--no-vacuum
#在執行測試之前不執行 vacuum。如果您要執行不包含標準資料表 pgbench_accounts
、pgbench_branches
、pgbench_history
和 pgbench_tellers
的自訂測試情境,則此選項是必要的。
-N
--skip-some-updates
#執行內建的 simple-update 指令碼。是 -b simple-update
的簡寫。
-P
sec
--progress=
sec
#每隔 sec
秒顯示進度報告。該報告包括自執行開始經過的時間、自上次報告以來的 TPS,以及自上次報告以來的交易延遲時間平均值、標準差和失敗交易的數量。在使用節流 (-R
) 的情況下,延遲是根據交易排定的開始時間而非實際交易開始時間來計算的,因此也包含平均排程延遲時間。當使用 --max-tries
啟用序列化/死鎖錯誤後的交易重試時,報告會包含重試交易的次數和所有重試的總和。
-r
--report-per-command
#在基準測試完成後,報告每個指令的下列統計資料:每個語句的平均延遲時間(從用戶端的角度來看的執行時間)、失敗的次數,以及在該指令中發生序列化或死鎖錯誤後重試的次數。 僅當 --max-tries
選項不等於 1 時,報告才會顯示重試統計資訊。
-R
rate
--rate=
rate
#以指定的速率執行交易,而不是盡可能快地運行(預設)。 速率以每秒交易數表示。 如果目標速率高於最大可能速率,則速率限制不會影響結果。
速率的目標是根據 Poisson 分佈排程時間軸啟動交易。預期的啟動時間排程會根據用戶端首次啟動的時間向前移動,而不是根據上一個交易結束的時間。 這種方法意味著,當交易超過其原始排定的結束時間時,後續的交易有可能再次趕上。
當節流生效時,在運行結束時報告的交易延遲時間是從排定的開始時間計算的,因此它包含每個交易必須等待上一個交易完成的時間。 等待時間稱為排程延遲時間,其平均值和最大值也會單獨報告。 相對於實際交易開始時間的交易延遲時間(即在資料庫中執行交易所花費的時間)可以透過從報告的延遲時間中減去排程延遲時間來計算。
如果 --latency-limit
與 --rate
一起使用,則交易可能會落後太多,以至於當上一個交易結束時,它已經超過延遲限制,因為延遲是從排定的開始時間計算的。 此類交易不會傳送到伺服器,而是完全略過並單獨計算。
高的排程延遲時間表示系統無法以指定的速率,以及選定的客戶端和執行緒數量處理交易。 當平均交易執行時間長於每個交易之間的排定間隔時,每個後續交易將會進一步落後,並且排程延遲時間將隨著測試運行時間的增加而持續增加。 發生這種情況時,您必須降低指定的交易速率。
-s
scale_factor
--scale=
scale_factor
#在 pgbench 的輸出中報告指定的規模因子。 對於內建測試,這不是必要的; 可以透過計算 pgbench_branches
資料表中的列數來偵測正確的規模因子。 但是,當僅測試自訂基準測試 (-f
選項) 時,除非使用此選項,否則規模因子將報告為 1。
-S
--select-only
#執行內建的 select-only 指令碼。是 -b select-only
的簡寫。
-t
transactions
--transactions=
transactions
#每個用戶端執行的交易數。預設值為 10。
-T
seconds
--time=
seconds
#執行測試指定的秒數,而不是每個用戶端執行固定數量的交易。-t
和 -T
互斥。
-v
--vacuum-all
#在執行測試之前,先清理 (vacuum) 所有四個標準資料表。如果沒有使用 -n
也沒有使用 -v
,pgbench 將會清理 pgbench_tellers
和 pgbench_branches
資料表,並且會截斷 pgbench_history
資料表。
--aggregate-interval=seconds
#彙總間隔的長度 (以秒為單位)。只能與 -l
選項一起使用。使用此選項時,日誌包含每個間隔的摘要資料,如下所述。
--exit-on-abort
#當任何用戶端由於某些錯誤而中止時,立即退出。如果沒有此選項,即使某個用戶端中止,其他用戶端也可以按照 -t
或 -T
選項的指定繼續執行,並且在這種情況下,pgbench 將列印不完整的結果。
請注意,序列化失敗或死鎖失敗不會中止用戶端,因此它們不受此選項的影響。有關更多資訊,請參閱失敗和序列化/死鎖重試。
--failures-detailed
#在每個交易和彙總日誌中,以及在主要報告和每個腳本的報告中,按以下類型分組報告失敗:
序列化失敗;
死鎖失敗;
有關更多資訊,請參閱失敗和序列化/死鎖重試。
--log-prefix=prefix
#設定由 --log
建立的日誌檔案的檔案名稱前綴。預設值為 pgbench_log
。
--max-tries=number_of_tries
#啟用對具有序列化/死鎖錯誤的交易進行重試,並設定這些重試的最大次數。此選項可以與 --latency-limit
選項結合使用,後者限制所有交易嘗試的總時間;此外,您不能在沒有 --latency-limit
或 --time
的情況下使用無限次數的嘗試 (--max-tries=0
)。預設值為 1,並且不重試具有序列化/死鎖錯誤的交易。有關重試此類交易的更多資訊,請參閱失敗和序列化/死鎖重試。
--progress-timestamp
#在顯示進度(選項 -P
)時,使用時間戳記(Unix epoch)而不是自執行開始以來的秒數。單位為秒,小數點後為毫秒精度。這有助於比較由各種工具產生的日誌。
--random-seed=
seed
#設定隨機產生器種子。為系統隨機數產生器設定種子,然後產生一系列初始產生器狀態,每個執行緒一個。 seed
的值可以是: time
(預設值,種子基於目前時間)、rand
(使用強隨機來源,如果沒有可用來源則失敗)或無符號十進制整數值。隨機產生器是從 pgbench 腳本 (random...
函數) 顯式調用的,或者隱式調用的(例如,選項 --rate
使用它來排程交易)。顯式設定時,用於設定種子的值會顯示在終端上。可以透過環境變數 PGBENCH_RANDOM_SEED
提供 seed
允許的任何值。為確保提供的種子影響所有可能的用途,請首先放置此選項或使用環境變數。
顯式設定種子允許完全重現 pgbench
執行,就隨機數而言。由於隨機狀態是按執行緒管理的,這意味著如果每個執行緒有一個用戶端,並且沒有外部或資料相依性,則對於相同的調用,pgbench
的執行完全相同。從統計學的角度來看,完全重現執行是一個壞主意,因為它可能會隱藏效能變異性或不適當地提高效能,例如,透過命中與先前執行相同的頁面。但是,它也可能對除錯大有幫助,例如,重新執行導致錯誤的棘手案例。謹慎使用。
--sampling-rate=rate
#抽樣率,用於將資料寫入日誌時,以減少產生的日誌量。如果給出此選項,則只會記錄指定比例的交易。 1.0 表示將記錄所有交易,0.05 表示只會記錄 5% 的交易。
記住在處理日誌檔案時考慮抽樣率。例如,在計算 TPS 值時,您需要相應地乘以這些數字(例如,對於 0.01 的抽樣率,您只會獲得實際 TPS 的 1/100)。
--show-script=
scriptname
#在 stderr 上顯示內建腳本 scriptname
的實際程式碼,並立即退出。
--verbose-errors
#列印有關所有錯誤和失敗的訊息(沒有重試的錯誤),包括超出重試限制以及序列化/死鎖失敗的超出程度。(請注意,在這種情況下,輸出可能會顯著增加。)有關更多資訊,請參閱失敗和序列化/死鎖重試。
成功執行將以狀態 0 結束。結束狀態 1 表示靜態問題,例如無效的命令列選項或不應該發生的內部錯誤。啟動基準測試時發生的早期錯誤,例如初始連線失敗,也會以狀態 1 結束。執行期間的錯誤,例如資料庫錯誤或腳本中的問題,將導致結束狀態 2。在後一種情況下,如果未指定 --exit-on-abort
選項,pgbench 將印出部分結果。
PGDATABASE
PGHOST
PGPORT
PGUSER
#預設連線參數。
這個工具,就像大多數其他 PostgreSQL 工具一樣,使用 libpq 支援的環境變數(請參閱第 32.15 節)。
環境變數 PG_COLOR
指定是否在診斷訊息中使用顏色。可能的值為 always
、auto
和 never
。
pgbench 執行從指定列表中隨機選擇的測試腳本。這些腳本可以包括使用 -b
指定的內建腳本和使用 -f
指定的使用者提供的腳本。每個腳本都可以指定一個在 @
之後的相對權重,以便改變其選擇機率。預設權重為 1
。權重為 0
的腳本將被忽略。
預設的內建交易腳本(也可以使用 -b tpcb-like
調用)每個交易針對隨機選擇的 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
),則只會發出 SELECT
。
pgbench 支援透過將預設交易腳本(如上所述)替換為從檔案讀取的交易腳本(-f
選項)來執行自訂基準測試情景。在這種情況下,「交易」計為一個腳本檔案的執行。
腳本檔案包含一個或多個以分號結尾的 SQL 指令。空白行和以 --
開頭的行將被忽略。腳本檔案也可以包含 「元指令」,這些元指令由 pgbench 本身解釋,如下所述。
在 PostgreSQL 9.6 之前,腳本檔案中的 SQL 指令以換行符結尾,因此它們不能跨越多行。現在 需要 使用分號來分隔連續的 SQL 指令(儘管如果 SQL 指令後面跟著元指令,則不需要分號)。如果您需要建立一個既適用於舊版本又適用於新版本的 pgbench 的腳本檔案,請務必將每個 SQL 指令寫在一行中並以分號結尾。
假定 pgbench 腳本不包含不完整的 SQL 交易區塊。如果在執行時,客戶端在沒有完成最後一個交易區塊的情況下到達腳本的末尾,它將被中止。
腳本檔案有一個簡單的變數替換功能。變數名稱必須由字母(包括非拉丁字母)、數字和底線組成,第一個字元不能是數字。可以使用命令列 -D
選項(如上所述)或使用下面說明的元指令來設定變數。除了任何由 -D
命令列選項預設的變數之外,還有一些變數是自動預設的,列於表 298中。使用 -D
為這些變數指定的值優先於自動預設值。一旦設定,可以透過寫入 :
variablename
將變數的值插入到 SQL 指令中。當執行多個客戶端會話時,每個會話都有自己的一組變數。pgbench 支援在一個語句中使用最多 255 個變數。
表 298. pgbench 自動變數
變數 | 描述 |
---|---|
client_id |
唯一識別客戶端會話的數字(從零開始) |
default_seed |
預設情況下在雜湊和偽隨機排列函數中使用的種子 |
random_seed |
隨機產生器種子(除非使用 -D 覆寫) |
scale |
目前比例因子 |
腳本檔案元指令以反斜線 (\
) 開頭,通常延伸到行尾,儘管可以透過寫入反斜線-return 將它們延續到其他行。元指令的引數由空白分隔。支援以下元指令
\gset [prefix
]
\aset [prefix
]
#這些指令可用於結束 SQL 查詢,取代終止分號 (;
)。
當使用 \gset
指令時,預期的前一個 SQL 查詢會返回一行,該行的欄位會儲存到以欄位名稱命名的變數中,如果提供了 prefix
,則以其為字首。
當使用 \aset
指令時,所有組合的 SQL 查詢(以 \;
分隔)的欄位都會儲存到以欄位名稱命名的變數中,如果提供了 prefix
,則以其為字首。如果查詢沒有傳回任何行,則不會進行任何指定,並且可以測試變數是否存在以偵測到這一點。如果查詢傳回多於一行,則保留最後一個值。
\gset
和 \aset
不能在管線模式中使用,因為當指令需要它們時,查詢結果尚未可用。
以下範例將第一個查詢的最終帳戶餘額放入變數 abalance
,並使用第三個查詢中的整數填入變數 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
#這組命令實現可巢狀的條件區塊,類似於 psql
的 \if
expression
。條件表達式與 \set
的表達式相同,非零值被解釋為 true。
\set varname
expression
#將變數 varname
設定為從 expression
計算出的值。表達式可以包含 NULL
常數、布林常數 TRUE
和 FALSE
、整數常數(例如 5432
)、雙精度浮點數常數(例如 3.14159
)、變數引用 :
variablename
、具有其通常 SQL 優先級和結合性的運算符、函數呼叫、SQL CASE
通用條件表達式以及括號。
如果輸入為 NULL
,函數和大多數運算符將返回 NULL
。
為了條件判斷的目的,非零數值被視為 TRUE
,零數值和 NULL
被視為 FALSE
。
過大或過小的整數和雙精度浮點數常數,以及整數算術運算符 (+
、-
、*
和 /
) 在溢位時會引發錯誤。
如果沒有為 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 ]
#使腳本執行暫停指定的持續時間,以微秒 (us
)、毫秒 (ms
) 或秒 (s
) 為單位。如果省略單位,則預設為秒。number
可以是整數常數,也可以是對具有整數值的變數的 :
variablename
引用。
範例
\sleep 10 ms
\setshell varname
command
[ argument
... ]
#將變數 varname
設定為具有給定 argument
的 shell 命令 command
的結果。該命令必須透過其標準輸出返回一個整數值。
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
\startpipeline
\syncpipeline
\endpipeline
#這組命令實現 SQL 語句的流水線處理。流水線必須以 \startpipeline
開始,以 \endpipeline
結束。在這之間可以有任意數量的 \syncpipeline
命令,這些命令會發送 同步消息,而不會結束正在進行的流水線並刷新發送緩衝區。在流水線模式下,語句會被發送到伺服器,而無需等待先前語句的結果。 有關更多詳細信息,請參閱 第 32.5 節。流水線模式需要使用擴展查詢協議。
表 299 中列出的算術、位元、比較和邏輯運算符已內建到 pgbench 中,並可以用於 \set
中出現的表達式。這些運算符按優先級遞增的順序列出。 除非另有說明,否則採用兩個數值輸入的運算符,如果任一輸入為雙精度浮點數,則將產生雙精度浮點數值,否則它們將產生整數結果。
表 299. pgbench 運算符
運算符 描述 範例 |
---|
邏輯 OR
|
邏輯 AND
|
邏輯 NOT
|
布林值測試
|
空值測試
|
等於
|
不等於
|
不等於
|
小於
|
小於或等於
|
大於
|
大於或等於
|
位元 OR
|
位元 XOR
|
位元 AND
|
位元 NOT
|
位元左移
|
位元右移
|
加法
|
減法
|
乘法
|
除法 (如果兩個輸入都是整數,則將結果截斷為零)
|
模數 (餘數)
|
負數
|
在表 300中列出的函式是內建於 pgbench 的函式,並可在出現在\set
中的運算式中使用。
表 300. pgbench 函式
函式 描述 範例 |
---|
絕對值
|
將引數列印到 stderr,並傳回該引數。
|
轉換為 double。
|
指數 (
|
選取引數中最大的值。
|
這是
|
計算 FNV-1a 雜湊。
|
計算 MurmurHash2 雜湊。
|
轉換為整數。
|
選取引數中最小的值。
|
自然對數
|
模數 (餘數)
|
|
π 的近似值
|
|
計算
|
計算
|
計算
|
計算
|
平方根
|
random
函數使用均勻分佈生成值,也就是所有值都以相等的機率在指定範圍內繪製。random_exponential
、random_gaussian
和 random_zipfian
函數需要一個額外的 double 參數,該參數決定分佈的精確形狀。
對於指數分佈,parameter
通過在 parameter
處截斷快速遞減的指數分佈來控制分佈,然後將其投影到邊界之間的整數上。 準確地說,如果
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,存取分佈就越平坦(更均勻)。 分佈的一個粗略近似是,範圍中最頻繁的 1% 值(接近 min
)在 parameter
% 的時間內繪製。 parameter
值必須嚴格為正數。
對於高斯分佈,該區間會映射到一個標準常態分佈(經典的鐘形高斯曲線),在左側截斷為 -parameter
,在右側截斷為 +parameter
。 區間中間的值更有可能被繪製。 準確地說,如果 PHI(x)
是標準常態分佈的累積分配函數,平均值 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
越大,越頻繁地存取接近區間中間的值,而越不頻繁地存取接近 min
和 max
邊界的值。 大約 67% 的值是從中間 1.0 / parameter
繪製的,也就是相對於平均值 0.5 / parameter
,而 95% 的值是從中間 2.0 / parameter
繪製的,也就是相對於平均值 1.0 / parameter
; 例如,如果 parameter
為 4.0,則 67% 的值是從區間的中間四分之一 (1.0 / 4.0) 繪製的(也就是從 3.0 / 8.0
到 5.0 / 8.0
),95% 的值是從區間的中間一半 (2.0 / 4.0
) 繪製的(第二個和第三個四分位數)。 允許的最小 parameter
值為 2.0。
random_zipfian
產生一個有界的齊夫分佈。 parameter
定義了分佈的偏斜程度。 parameter
越大,越頻繁地存取接近區間開始的值。 分佈是這樣的,假設範圍從 1 開始,則繪製 k
與繪製 k+1
的機率之比為 ((
。 例如,k
+1)/k
)**parameter
random_zipfian(1, ..., 2.5)
產生數值 1
的頻率約為產生數值 2
的 (2/1)**2.5 = 5.66
倍,而產生數值 2
的頻率本身比產生數值 3
的頻率高 (3/2)**2.5 = 2.76
倍,依此類推。
pgbench 的實作基於 "Non-Uniform Random Variate Generation",Luc Devroye,第 550-551 頁,Springer 1986。 由於該演算法的限制,parameter
值被限制在 [1.001, 1000] 範圍內。
在設計以非均勻方式選擇列的基準時,請注意選擇的列可能與其他資料相關,例如序列中的 ID 或實體列排序,這可能會扭曲效能測量。
為了避免這種情況,您可能希望使用 permute
函式,或採取其他具有類似效果的額外步驟,來洗牌所選的列,並消除這種關聯性。
雜湊函式 hash
、hash_murmur2
和 hash_fnv1a
接受一個輸入值和一個可選的種子參數。如果沒有提供種子,則會使用 :default_seed
的值,該值會隨機初始化,除非通過命令行 -D
選項進行設定。
permute
接受一個輸入值、一個大小,和一個可選的種子參數。它會產生範圍在 [0, size)
內整數的偽隨機排列,並傳回輸入值在排列值中的索引。所選的排列由種子參數化,如果未指定,則預設為 :default_seed
。與雜湊函式不同,permute
確保輸出值中沒有衝突或間隙。區間外的輸入值會以大小進行模運算。如果大小不是正數,則該函式會引發錯誤。permute
可用於分散非均勻隨機函式(例如 random_zipfian
或 random_exponential
)的分佈,以便更常繪製的值不會簡單地相關聯。例如,以下 pgbench 腳本模擬了一個可能的真實世界工作負載,該工作負載對於一些產生過多負載的社交媒體和部落格平台來說是很典型的
\set size 1000000 \set r random_zipfian(1, :size, 1.07) \set k 1 + permute(:r, :size)
在某些情況下,需要幾個不相互關聯的不同的分佈,這時可選的種子參數就派上用場了
\set k1 1 + permute(:r, :size, :default_seed + 123) \set k2 1 + permute(:r, :size, :default_seed + 321)
也可以使用 hash
來近似類似的行為
\set size 1000000 \set r random_zipfian(1, 100 * :size, 1.07) \set k 1 + abs(hash(:r)) % :size
但是,由於 hash
會產生衝突,因此某些值將無法到達,而其他值會比原始分佈預期的更頻繁。
舉例來說,內建類似 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
識別用於交易的腳本檔案(當使用 -f
或 -b
指定多個腳本時很有用)
time_epoch
交易的完成時間,作為 Unix epoch 時間戳
time_us
交易完成時間的小數秒部分,以微秒為單位
schedule_lag
交易啟動延遲,即交易的計劃啟動時間與實際啟動時間之間的差異,以微秒為單位(僅在指定 --rate
時出現)
retries
交易期間序列化或死鎖錯誤後的重試次數(僅當 --max-tries
不等於 1 時出現)
當同時使用 --rate
和 --latency-limit
時,跳過的交易的 time
將報告為 skipped
。如果交易以失敗告終,則其 time
將報告為 failed
。如果您使用 --failures-detailed
選項,則失敗交易的 time
將報告為 serialization
或 deadlock
,具體取決於失敗類型(有關更多資訊,請參閱 Failures and Serialization/Deadlock Retries)。
這是單個用戶端執行中產生的日誌檔案的程式碼片段
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 毫秒) 超過 5 毫秒的限制。接下來的兩個交易被跳過,因為它們在開始之前就已經遲到了。
以下範例顯示了具有失敗和重試的日誌檔案的程式碼片段,最大嘗試次數設定為 10(請注意額外的 retries
欄位)
3 0 47423 0 1499414498 34501 3 3 1 8333 0 1499414498 42848 0 3 2 8358 0 1499414498 51219 0 4 0 72345 0 1499414498 59433 6 1 3 41718 0 1499414498 67879 4 1 4 8416 0 1499414498 76311 0 3 3 33235 0 1499414498 84469 3 0 0 failed 0 1499414498 84905 9 2 0 failed 0 1499414498 86248 9 3 4 8307 0 1499414498 92788 0
如果使用 --failures-detailed
選項,則失敗類型將在 time
中報告,如下所示
3 0 47423 0 1499414498 34501 3 3 1 8333 0 1499414498 42848 0 3 2 8358 0 1499414498 51219 0 4 0 72345 0 1499414498 59433 6 1 3 41718 0 1499414498 67879 4 1 4 8416 0 1499414498 76311 0 3 3 33235 0 1499414498 84469 3 0 0 serialization 0 1499414498 84905 9 2 0 serialization 0 1499414498 86248 9 3 4 8307 0 1499414498 92788 0
在可以處理大量交易的硬體上執行長時間測試時,日誌檔案可能會變得非常大。--sampling-rate
選項可用於僅記錄交易的隨機樣本。
使用 --aggregate-interval
選項時,日誌檔案會使用不同的格式。每個日誌行描述一個彙總間隔。它包含以下以空格分隔的欄位
interval_start
間隔的開始時間,作為 Unix epoch 時間戳
num_transactions
間隔內的交易數量
sum_latency
交易延遲的總和
sum_latency_2
交易延遲的平方和
min_latency
最小交易延遲
max_latency
最大交易延遲
sum_lag
交易開始延遲的總和(除非指定 --rate
,否則為零)
sum_lag_2
交易開始延遲的平方和(除非指定 --rate
,否則為零)
min_lag
最小交易開始延遲(除非指定 --rate
,否則為零)
max_lag
最大交易開始延遲(除非指定 --rate
,否則為零)
skipped
因開始時間過晚而被跳過的交易數量(除非指定 --rate
和 --latency-limit
,否則為零)
retried
重試的交易數量(除非 --max-tries
不等於 1,否則為零)
retries
序列化或死鎖錯誤後的重試次數(除非 --max-tries
不等於 1,否則為零)
serialization_failures
發生序列化錯誤且之後未重試的交易數量(除非指定 --failures-detailed
,否則為零)
deadlock_failures
發生死鎖錯誤且之後未重試的交易數量(除非指定 --failures-detailed
,否則為零)
以下是使用此選項產生的一些範例輸出
pgbench --aggregate-interval=10 --time=20 --client=10 --log --rate=1000 --latency-limit=10 --failures-detailed --max-tries=10 test
1650260552 5178 26171317 177284491527 1136 44462 2647617 7321113867 0 9866 64 7564 28340 4148 0
1650260562 4808 25573984 220121792172 1171 62083 3037380 9666800914 0 9998 598 7392 26621 4527 0
請注意,雖然普通(未彙總)日誌格式顯示了每個交易使用的腳本,但彙總格式則沒有。因此,如果您需要每個腳本的資料,則需要自行彙總資料。
使用 -r
選項,pgbench 會收集每個陳述式的以下統計資料
latency
- 每個陳述式的經過交易時間。pgbench 報告陳述式所有成功執行的平均值。
此陳述式中失敗的次數。更多資訊請參閱失敗和序列化/死鎖重試。
此陳述式在發生序列化或死鎖錯誤後重試的次數。更多資訊請參閱失敗和序列化/死鎖重試。
只有當 --max-tries
選項不等於 1 時,報告才會顯示重試統計資訊。
所有數值都是針對每個客戶端執行的每個陳述式計算的,並在基準測試完成後報告。
對於預設腳本,輸出將類似於以下內容
starting vacuum...end. transaction type: <builtin: TPC-B (sort of)> scaling factor: 1 query mode: simple number of clients: 10 number of threads: 1 maximum number of tries: 1 number of transactions per client: 1000 number of transactions actually processed: 10000/10000 number of failed transactions: 0 (0.000%) number of transactions above the 50.0 ms latency limit: 1311/10000 (13.110 %) latency average = 28.488 ms latency stddev = 21.009 ms initial connection time = 69.068 ms tps = 346.224794 (without initial connection time) statement latencies in milliseconds and failures: 0.012 0 \set aid random(1, 100000 * :scale) 0.002 0 \set bid random(1, 1 * :scale) 0.002 0 \set tid random(1, 10 * :scale) 0.002 0 \set delta random(-5000, 5000) 0.319 0 BEGIN; 0.834 0 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; 0.641 0 SELECT abalance FROM pgbench_accounts WHERE aid = :aid; 11.126 0 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; 12.961 0 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; 0.634 0 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); 1.957 0 END;
另一個使用可序列化預設交易隔離等級的預設腳本的輸出範例 (PGOPTIONS='-c default_transaction_isolation=serializable' pgbench ...
)
starting vacuum...end. transaction type: <builtin: TPC-B (sort of)> scaling factor: 1 query mode: simple number of clients: 10 number of threads: 1 maximum number of tries: 10 number of transactions per client: 1000 number of transactions actually processed: 6317/10000 number of failed transactions: 3683 (36.830%) number of transactions retried: 7667 (76.670%) total number of retries: 45339 number of transactions above the 50.0 ms latency limit: 106/6317 (1.678 %) latency average = 17.016 ms latency stddev = 13.283 ms initial connection time = 45.017 ms tps = 186.792667 (without initial connection time) statement latencies in milliseconds, failures and retries: 0.006 0 0 \set aid random(1, 100000 * :scale) 0.001 0 0 \set bid random(1, 1 * :scale) 0.001 0 0 \set tid random(1, 10 * :scale) 0.001 0 0 \set delta random(-5000, 5000) 0.385 0 0 BEGIN; 0.773 0 1 UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid; 0.624 0 0 SELECT abalance FROM pgbench_accounts WHERE aid = :aid; 1.098 320 3762 UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid; 0.582 3363 41576 UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid; 0.465 0 0 INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP); 1.933 0 0 END;
如果指定了多個腳本檔案,則所有統計資訊都會針對每個腳本檔案分別報告。
請注意,收集每個陳述式延遲計算所需的額外計時資訊會增加一些額外負荷。這會降低平均執行速度並降低計算出的 TPS。減速的程度因平台和硬體而異。比較啟用和停用延遲報告的平均 TPS 值,是衡量計時額外負荷是否顯著的好方法。
在執行 pgbench 時,主要有三種錯誤類型
主程式的錯誤。它們是最嚴重的,並且總是導致 pgbench 立即退出並顯示相應的錯誤訊息。它們包括
pgbench 開始時的錯誤(例如,無效的選項值);
初始化模式下的錯誤(例如,用於建立內建腳本表格的查詢失敗);
在啟動執行緒之前的錯誤(例如,無法連線到資料庫伺服器,Meta 指令中存在語法錯誤,執行緒建立失敗);
內部 pgbench 錯誤(按理說永遠不應該發生...)。
執行緒管理其客戶端時的錯誤(例如,客戶端無法啟動與資料庫伺服器的連線 / 用於將客戶端連線到資料庫伺服器的 Socket 已失效)。在這種情況下,此執行緒的所有客戶端都會停止工作,而其他執行緒繼續工作。但是,如果指定了 --exit-on-abort
,則在這種情況下,所有執行緒都會立即停止。
直接的客戶端錯誤。在發生內部 pgbench 錯誤(按理說永遠不應該發生...)或指定了 --exit-on-abort
的情況下,它們會導致 pgbench 立即退出並顯示相應的錯誤訊息。否則,在最壞的情況下,它們只會導致失敗的客戶端中止,而其他客戶端繼續執行(但有些客戶端錯誤會被處理而不會中止客戶端並單獨報告,請參閱下文)。在本節的後續內容中,假設討論的錯誤僅是直接的客戶端錯誤,而不是內部 pgbench 錯誤。
如果發生嚴重錯誤,則客戶端的執行會被中止;例如,與資料庫伺服器的連線遺失,或在未完成最後一個交易的情況下到達腳本結尾。此外,如果 SQL 或 Meta 指令的執行失敗,原因不是序列化或死鎖錯誤,則客戶端會被中止。否則,如果 SQL 指令因序列化或死鎖錯誤而失敗,則客戶端不會被中止。在這種情況下,目前的交易會回滾,這也包括將客戶端變數設定為執行此交易之前的狀態(假設一個交易腳本僅包含一個交易;有關更多資訊,請參閱在 pgbench 中實際執行的「交易」是什麼?)。具有序列化或死鎖錯誤的交易會在回滾後重複,直到它們成功完成或達到最大重試次數(由 --max-tries
選項指定)/ 最大重試時間(由 --latency-limit
選項指定)/ 基準測試結束(由 --time
選項指定)。如果最後一次嘗試執行失敗,則此交易將被報告為失敗,但客戶端不會被中止並繼續工作。
如果不指定 --max-tries
選項,則在發生序列化或死鎖錯誤後,交易永遠不會重試,因為其預設值為 1。使用無限次數的嘗試 (--max-tries=0
) 和 --latency-limit
選項來僅限制最大嘗試時間。您也可以使用 --time
選項在無限次數的嘗試下限制基準測試的持續時間。
重複包含多個交易的腳本時要小心:腳本總是會完全重試,因此成功的交易可能會執行多次。
重複包含 Shell 指令的交易時要小心。與 SQL 指令的結果不同,Shell 指令的結果不會回滾,但 \setshell
指令的變數值除外。
成功交易的延遲包括帶有回滾和重試的整個交易執行時間。延遲僅針對成功的交易和指令進行測量,而不針對失敗的交易或指令進行測量。
主要報告包含失敗交易的數量。如果 --max-tries
選項不等於 1,則主要報告還包含與重試相關的統計資訊:重試交易的總數和重試的總數。每個腳本報告從主要報告繼承所有這些欄位。只有當 --max-tries
選項不等於 1 時,每個陳述式報告才會顯示重試統計資訊。
如果您想在每個交易和聚合日誌以及主要和每個腳本報告中按基本類型對失敗進行分組,請使用 --failures-detailed
選項。如果您還想區分所有錯誤和失敗(不重試的錯誤)的類型,包括超過哪個重試限制以及序列化/死鎖失敗超過了多少,請使用 --verbose-errors
選項。
您可以為 pgbench 表格指定表格存取方法。環境變數 PGOPTIONS
指定透過命令列傳遞給 PostgreSQL 的資料庫組態選項 (請參閱Section 19.1.4)。例如,可以使用以下方式指定一個假設的 pgbench 建立的表格的預設表格存取方法,名稱為 wuzza
。
PGOPTIONS='-c default_table_access_method=wuzza'
很容易使用 pgbench 產生完全沒有意義的數字。以下是一些指南,可幫助您獲得有用的結果。
首先,絕對不要相信任何只執行幾秒鐘的測試。使用 -t
或 -T
選項來讓測試至少持續幾分鐘,以便平均掉雜訊。在某些情況下,您可能需要數小時才能獲得可重現的數字。最好嘗試多次執行測試,以確定您的數字是否可重現。
對於預設的類似 TPC-B 的測試情境,初始化比例因子 (-s
) 應至少與您打算測試的最大客戶端數量 (-c
) 一樣大;否則您主要會測量更新爭用。在 pgbench_branches
表中只有 -s
列,並且每個事務都想要更新其中一列,因此超過 -s
的 -c
值無疑會導致大量事務被阻止,等待其他事務完成。
預設測試情境對於表初始化後的時長也非常敏感:表中累積的無效列和無效空間會改變結果。要理解結果,您必須追蹤更新總數以及何時執行 vacuum。如果啟用了 autovacuum,可能會導致測量效能出現不可預測的變化。
pgbench 的一個限制是,在嘗試測試大量客戶端連線時,它本身可能會成為瓶頸。可以通過在與資料庫伺服器不同的機器上執行 pgbench 來緩解這個問題,儘管低網路延遲至關重要。甚至可能有用的是在多個客戶端機器上同時執行多個 pgbench 實例,針對同一個資料庫伺服器。
如果不受信任的使用者可以存取未採用安全結構描述使用模式的資料庫,請不要在該資料庫中執行 pgbench。pgbench 使用非限定名稱,並且不操作搜尋路徑。
如果您在文件中發現任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的內容,請使用此表單來報告文件問題。