pgbench — 對 PostgreSQL 執行基準測試
pgbench
-i
[選項
...] [資料庫名
]
pgbench
[選項
...] [資料庫名
]
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
其中 資料庫名
是要測試的已建立資料庫的名稱。(您可能還需要 -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=]資料庫名
#指定要測試的資料庫的名稱。如果未指定,則使用環境變數 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
使用 FREEZE
選項將資料載入到 PostgreSQL 14 或更高版本中的普通(非分割槽)表中,以加快後續 VACUUM
的速度。使用 g
會導致日誌列印每 100,000 行一條訊息,同時為所有表生成資料。
使用 G
(伺服器端生成資料)時,只有少量查詢從 pgbench
客戶端傳送,然後資料實際上是在伺服器中生成的。此變體不需要大量頻寬,但伺服器會執行更多工作。使用 G
會導致日誌在生成資料時不列印任何進度訊息。
預設的初始化行為使用客戶端生成資料(等同於 g
)。
v
(Vacuum - 清理) #對標準表呼叫 VACUUM
。
p
(create Primary keys - 建立主鍵) #在標準表上建立主鍵索引。
f
(create Foreign keys - 建立外部索引鍵) #在標準表之間建立外部索引鍵約束。(注意,此步驟預設不執行。)
-F
fillfactor
--fillfactor=
fillfactor
#使用給定的填充因子建立 pgbench_accounts
、pgbench_tellers
和 pgbench_branches
表。預設值為 100。
-n
--no-vacuum
#初始化期間不執行清理。(此選項會抑制 v
初始化步驟,即使它在 -I
中指定了。)
-q
--quiet
#將日誌記錄切換到靜默模式,每 5 秒只輸出一條進度訊息。預設日誌記錄每 100,000 行輸出一條訊息,這通常每秒會輸出很多行(尤其是在效能良好的硬體上)。
如果 -I
中指定了 G
,則此設定無效。
-s
scale_factor
--scale=
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
#使用 NUM
個分割槽建立分割槽表 pgbench_accounts
,這些分割槽的尺寸幾乎相等,以適應縮放後的賬戶數量。預設值為 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
毫秒的事務會被單獨計數和報告,稱為延遲。
使用限制(--rate=...
)時,與計劃開始時間相比滯後超過 limit
毫秒的事務,因此沒有希望滿足延遲限制,根本不會發送到伺服器。它們會被單獨計數和報告為跳過。
當使用 --max-tries
選項啟用事務重試以應對序列化或死鎖錯誤時,如果該事務所有重試的總時間超過 limit
毫秒,則不會重試。要僅限制重試次數而不限制其總時間,請使用 --max-tries=0
。預設情況下,--max-tries
選項設定為 1,並且不會重試具有序列化/死鎖錯誤的事務。有關重試此類事務的更多資訊,請參閱 失敗和序列化/死鎖重試。
-M
querymode
--protocol=
querymode
#用於向伺服器提交查詢的協議:
simple
:使用簡單查詢協議。
extended
:使用擴充套件查詢協議。
prepared
:使用帶預備語句的擴充套件查詢協議。
在 prepared
模式下,pgbench 從第二次查詢迭代開始重用解析分析結果,因此 pgbench 的執行速度比其他模式快。
預設使用簡單查詢協議。(有關更多資訊,請參閱 第 54 章。)
-n
--no-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
#以指定的速率執行事務,而不是儘可能快地執行(預設)。速率以每秒事務數給出。如果目標速率高於最大可能速率,速率限制將不會影響結果。
該速率透過在泊松分佈的時間線上啟動事務來達到。預期的開始時間計劃會根據客戶端首次啟動的時間向前推進,而不是根據上一個事務結束的時間。這種方法意味著,當事務超過其原始計劃的結束時間時,後面的事務有可能再次趕上。
當限速啟用時,執行結束時報告的事務延遲是從計劃的開始時間計算的,因此它包括每個事務必須等待上一個事務完成的時間。等待時間稱為計劃滯後時間,其平均值和最大值也會單獨報告。相對於實際事務開始時間的事務延遲,即在資料庫中執行事務所花費的時間,可以透過從報告的延遲中減去計劃滯後時間來計算。
如果 --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
#在執行測試之前清理所有四個標準表。如果既不使用 -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 紀元)而不是自執行開始以來的秒數。單位是秒,小數點後有毫秒精度。這有助於比較由各種工具生成的日誌。
--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
命令列選項預設的任何變數外,還有一些變數是自動預設的,列在 表 301 中。使用 -D
為這些變數指定的值將覆蓋自動預設值。一旦設定,變數的值可以透過寫入 :
variablename
來插入到 SQL 命令中。當執行多個客戶端會話時,每個會話都有自己的變數集。pgbench 支援在一個語句中最多使用 255 個變數。
表 301. pgbench 自動變數
變數 | 描述 |
---|---|
client_id |
標識客戶端會話的唯一編號(從零開始)。 |
default_seed |
預設情況下,在雜湊和偽隨機置換函式中使用的種子。 |
random_seed |
隨機生成器種子(除非用 -D 覆蓋)。 |
scale |
當前比例因子。 |
指令碼檔案元命令以反斜槓(\
)開頭,通常延伸到行尾,儘管可以透過寫反斜槓-回車來將它們延續到其他行。元命令的引數由空格分隔。支援以下元命令:
\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
設定為 shell 命令 command
及其給定 argument
(s) 的結果。命令必須透過其標準輸出來返回一個整數值。
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
命令,它會發送一個 sync 訊息,而不會結束正在進行的管道並刷新發送緩衝區。在管道模式下,語句會發送到伺服器,而無需等待前一個語句的結果。有關更多詳細資訊,請參閱 第 32.5 節。管道模式需要使用擴充套件查詢協議。
pgbench 內建了 表 302 中列出的算術、位、比較和邏輯運算子,可以在 \set
中出現的表示式中使用。運算子按優先順序升序排列。除非另有說明,否則接受兩個數值輸入的運算子在任一輸入為雙精度時產生雙精度值,否則產生整數結果。
表 302. pgbench 運算子
運算子 描述 示例 |
---|
邏輯 OR。
|
邏輯 AND。
|
邏輯 NOT。
|
布林值測試。
|
空值測試。
|
等於。
|
不等於。
|
不等於。
|
小於。
|
小於等於。
|
大於。
|
大於等於。
|
位 OR。
|
位 XOR。
|
位 AND。
|
按位非
|
位左移。
|
位右移。
|
加法。
|
減法。
|
乘法。
|
除法(如果兩個輸入都是整數,則結果向零截斷)。
|
模(餘數)。
|
負數。
|
pgbench 內建了 表 303 中列出的函式,可以在 \set
中出現的表示式中使用。
表 303. pgbench 函式
函式 描述 示例 |
---|
絕對值。
|
將引數列印到 stderr,並返回該引數。
|
轉換為雙精度。
|
指數函式(e 的 given power 次方)。
|
選擇引數中的最大值。
|
這是
|
計算 FNV-1a 雜湊。
|
計算 MurmurHash2 雜湊。
|
轉換為整數。
|
選擇引數中的最小值。
|
自然對數。
|
模(餘數)。
|
|
π 的近似值。
|
|
計算
|
計算
|
計算
|
計算
|
平方根。
|
random
函式生成的值使用均勻分佈,也就是說,所有值都在指定範圍內以相等的機率抽取。random_exponential
、random_gaussian
和 random_zipfian
函式需要一個額外的雙精度引數,該引數決定了分佈的精確形狀。
對於指數分佈,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
生成一個有界的 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
(有關更多資訊,請參閱 故障和序列化/死鎖重試)。
以下是單客戶端執行生成的日誌檔案片段。
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 開始時的錯誤(例如,無效的選項值);
初始化模式中的錯誤(例如,用於建立內建指令碼表的查詢失敗);
啟動執行緒之前的錯誤(例如,無法連線到資料庫伺服器,元命令中的語法錯誤,執行緒建立失敗);
內部 pgbench 錯誤(這種情況不應發生……)。
執行緒管理其客戶端時的錯誤(例如,客戶端無法啟動到資料庫伺服器的連線/客戶端與資料庫伺服器之間的套接字無效)。在這種情況下,該執行緒的所有客戶端都會停止,而其他執行緒繼續工作。但是,如果指定了 --exit-on-abort
,在這種情況下所有執行緒都會立即停止。
直接客戶端錯誤。在內部 pgbench 錯誤(這種情況不應發生……)或指定 --exit-on-abort
的情況下,它們會導致 pgbench 立即退出並顯示相應的錯誤訊息。否則,在最壞的情況下,它們只會導致失敗的客戶端中止,而其他客戶端繼續執行(但某些客戶端錯誤會得到處理而不會中止客戶端,並在下面單獨報告)。稍後在本節中,假定討論的錯誤僅是直接客戶端錯誤,而不是內部 pgbench 錯誤。
在發生嚴重錯誤時,客戶端的執行將被中止;例如,與資料庫伺服器的連線丟失或指令碼結束但最後一個事務未完成。此外,如果 SQL 或元命令的執行因序列化或死鎖錯誤以外的原因而失敗,則客戶端將被中止。否則,如果 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 的資料庫配置選項(請參閱 第 19.1.4 節)。例如,可以使用以下方式為 pgbench 建立的表指定一個假設的預設表訪問方法,名為 wuzza
:
PGOPTIONS='-c default_table_access_method=wuzza'
使用 pgbench 產生完全無意義的數字非常容易。以下是一些指南,可幫助您獲得有用的結果。
首先,切勿相信僅執行幾秒鐘的測試。使用 -t
或 -T
選項使執行持續至少幾分鐘,以平均掉噪聲。在某些情況下,您可能需要幾個小時才能獲得可重現的數字。最好嘗試執行幾次測試,以找出您的數字是否可重現。
對於預設的 TPC-B 類測試場景,初始化比例因子(-s
)應至少與您打算測試的最大客戶端數量(-c
)一樣大;否則,您將主要測量更新爭用。 pgbench_branches
表只有 -s
行,並且每個事務都想更新其中一行,因此超過 -s
的 -c
值無疑會導致大量事務被阻塞,等待其他事務。
預設測試場景還對錶自初始化以來的時間非常敏感:累積的死行和死空間會改變結果。要理解結果,您必須跟蹤更新的總數以及何時發生 vacuuming。如果啟用了 autovacuum,它可能導致測得的效能發生不可預測的變化。
pgbench 的一個限制是,在測試大量客戶端會話時,它本身可能成為瓶頸。這可以透過在與資料庫伺服器不同的機器上執行 pgbench 來緩解,儘管低網路延遲是必不可少的。甚至可能有用的是在多個客戶端機器上同時執行多個 pgbench 例項,針對同一個資料庫伺服器。
如果不受信任的使用者可以訪問尚未採用 安全模式使用模式 的資料庫,請勿在該資料庫中執行 pgbench。pgbench 使用非限定名稱,並且不操縱搜尋路徑。
如果您在文件中發現任何不正確之處,與您對特定功能的體驗不符,或者需要進一步說明,請使用 此表單 報告文件問題。