pgbench

pgbench — запустить тест оценки производительности QHB


Синтаксис

pgbench -i [параметр...] [имя_бд]

pgbench [параметр...] [имя_бд]

Описание

Утилита pgbench — это простая программа для запуска тестов оценки производительности QHB. Она многократно выполняет одну и ту же последовательность команд 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 [ другие-параметры ] имя_бд

где имя_бд — это имя уже созданной базы данных, в которой будет проводиться тест. (Кроме того, вам может понадобиться добавить параметры -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 [ параметры ] имя_бд

Практически во всех случаях, чтобы получить полезный тест, понадобятся какие-либо параметры. К наиболее важным параметрам относятся -c (число клиентов), -t (число транзакций), -T (ограничение по времени) и -f (указать файл с нестандартным скриптом). Полный список параметров см. ниже.


Параметры

Все параметры разделены на три подраздела. Во время инициализации базы данных и во время тестовых прогонов используются разные параметры, но некоторые параметры полезны в обоих случаях.


Параметры инициализации

Утилита pgbench принимает следующие аргументы командной строки для инициализации:

имя_бд
Задает имя базы данных, в которой должен проходить тест. Если оно не задано, используется значение переменной среды PGDATABASE. Если и она не установлена, используется имя пользователя, под которым проводится подключение.

-i
--initialize
Требуется для вызова режима инициализации.

-I этапы_инициализации
--init-steps=этапы_инициализации
Выполнять только выбранный набор из всех обычных этапов инициализации. В параметре этапы_инициализации указываются этапы, которые должны выполняться (по одному символу на этап). Все этапы вызываются в заданном порядке. Значение по умолчанию — dtgvp. Возможные этапы:

  • d (Drop, удалить)
    Удалить все существующие таблицы pgbench.
  • t (create Tables, создать таблицы)
    Создать таблицы, используемые стандартным сценарием pgbench, а именно: pgbench_accounts, pgbench_branches, pgbench_history и pgbench_tellers.
  • g или G (Generate data, сгенерировать данные на стороне клиента или на стороне сервера)
    Сгенерировать данные и загрузить их в стандартные таблицы, заменив все уже находящиеся там данные.
    С ключом g (генерирование данных на стороне клиента) данные генерируются на клиенте pgbench, а затем передаются на сервер. При этом пропускная способность соединения клиент/сервер интенсивно используется командой COPY. Если не включено партиционирование, pgbench использует параметр FREEZE, чтобы ускорить последующую команду VACUUM. При генерировании с ключом g данных для таблицы pgbench_accounts каждые 100 000 строк выводится сообщение о прогрессе.
    С ключом G (генерирование данных на стороне сервера) клиент pgbench передает только небольшие запросы, а затем уже сами данные генерируются на сервере. В этом варианте высокая пропускная способность не требуется, но возрастет нагрузка на сервер. При генерировании данных с ключом G никаких сообщений о прогрессе не выводится.
    По умолчанию во время инициализации генерирование данных происходит на стороне клиента (равнозначно использованию ключа g).
  • v (Vacuum, очистка)
    Вызывать команду VACUUM для стандартных таблиц.
  • p (create Primary keys, создать первичные ключи)
    Создать индексы первичных ключей в стандартных таблицах.
  • f (create Foreign keys, создать внешние ключи)
    Создать ограничения внешних ключей между стандартными таблицами. (Обратите внимание, что по умолчанию этот этап не выполняется.)

-F фактор_заполнения
--fillfactor=фактор_заполнения
Создать таблицы pgbench_accounts, pgbench_tellers и pgbench_branches с заданным фактором заполнения. Значение по умолчанию — 100.

-n
--no-vacuum
Не выполнять очистку во время инициализации. (Этот параметр подавляет этап инициализации v, даже если тот был указан в -I.)

-q
--quiet
Переключить журналирование в тихий режим, выводя только одно сообщение о прогрессе в 5 секунд. По умолчанию сообщения выдаются через каждые 100 000 строк, из-за чего за секунду часто выводится много строк (особенно на хорошем оборудовании).
Этот параметр не действует, если в -I указан ключ G.

-s коэффициент_масштабирования
--scale=коэффициент_масштабирования
Умножить количество генерируемых строк на заданный коэффициент масштабирования. К примеру, с -s 100 в таблице pgbench_accounts будет сгенерировано 10 000 000 строк. Значение по умолчанию — 1. При коэффициенте, равном 20 000 или выше, столбцы, содержащие идентификаторы счетов (столбцы aid), переключатся на более крупные целые числа (тип bigint), чтобы в них уместился весь диапазон идентификаторов счетов.

--foreign-keys
Создать ограничения внешних ключей между стандартными таблицами. (Этот параметр добавляет к последовательности этапов инициализации этап f, если тот отсутствует.)

--index-tablespace=табличное_пространство_индексов
Создает индексы в заданном табличном пространстве, а не в табличном пространстве по умолчанию.

--partition-method=ИМЯ
Создать партиционированную таблицу pgbench_accounts методом ИМЯ. Ожидаемые значения: range (диапазонный) или hash (хеш). Для этого параметра требуется, чтобы в --partitions было ненулевое значение. Если ничего не задано, метод по умолчанию — range.

--partitions=ЧИСЛО
Создать партиционированную таблицу pgbench_accounts с заданным ЧИСЛОМ партиций примерно одинакового размера для масштабированного количества счетов. Значение по умолчанию — 0, что подразумевает отключение партиционирования.

--tablespace=табличное_пространство
Создать таблицы в заданном табличном пространстве, а не в табличном пространстве по умолчанию.

--unlogged-tables
Создать все таблицы как нежурналируемые, а не как постоянные.


Параметры тестирования производительности

Утилита pgbench принимает следующие аргументы командной строки для тестирования производительности:

-b имя_скрипта[@вес]
--builtin=имя_скрипта[@вес]
Добавить заданный встроенный скрипт в список скриптов, которые будут выполняться. Доступные встроенные скрипты: tpcb-like, simple-update и select-only. Допускается указание однозначных префиксов их имен. Со специальным именем list показать список встроенных скриптов и немедленно завершиться.
Дополнительно можно указать целочисленный вес после @, чтобы скорректировать вероятность выбора этого скрипта относительно других. По умолчанию вес равен 1. Подробную информацию см. ниже.

-c клиенты
--client=клиенты
Число имитируемых клиентов, то есть число параллельных сеансов базы данных. Значение по умолчанию — 1.

-C
--connect
Устанавливать новое подключение для каждой транзакции вместо одного для каждого клиентского сеанса. Это полезно для оценки издержек подключений.

-d
--debug
Выводить отладочные сообщения.

-D имя_переменной=значение
--define=имя_переменной=значение
Определить переменную для использования в пользовательском скрипте (см. ниже). Параметр -D можно указать несколько раз.

-f имя_файла[@вес]
--file=имя_файла[@вес]
Добавить скрипт транзакции, читаемый из файла имя_файла, в список скриптов, которые будут выполняться.
Дополнительно можно указать целочисленный вес после @, чтобы скорректировать вероятность выбора этого скрипта относительно других. По умолчанию вес равен 1. (При указании имени файла скрипта, содержащего символ @, добавьте вес, чтобы избежать неоднозначности, например, filen@me@1.) Подробную информацию см. ниже.

-j потоки
--jobs=потоки
Количество рабочих потоков в pgbench. Использование нескольких потоков может быть полезно на многопроцессорных машинах. Клиенты распределяются по доступным потокам по возможности равномерно. Значение по умолчанию — 1.

-l
--log
Записать информацию о каждой транзакции в файл журнала. Подробную информацию см. ниже.

-L предел
--latency-limit=предел
Транзакции, длящиеся дольше заданного предела (в миллисекундах), подсчитываются и отражаются отдельно, как опаздывающие.
При дросселировании запросов (--rate=...) транзакции, отстающие от графика более чем на заданный предел (в мс) и поэтому никак не укладывающиеся в этот предел задержки, вообще не передаются на сервер. Они подсчитываются и отражаются отдельно, как пропущенные.
При использовании параметра --max-tries транзакция, завершившаяся сбоем из-за аномалии сериализации или взаимоблокировки, не будет повторяться, если общее время всех ее попыток превышает заданный предел (в мс). Чтобы ограничить только время попыток, а не их количество, установите --max-tries=0. По умолчанию в параметре --max-tries установлено значение 1, и транзакции с ошибками сериализации/взаимоблокировки не повторяются. Более подробную информацию о повторении таких транзакций см. в параграфе Сбои и повторы из-за ошибок сериализации/взаимоблокировки.

-M режим_запросов
--protocol=режим_запросов
Протокол, который будет использоваться для передачи запросов на сервер:

  • simple: использовать простой протокол запросов.
  • extended: использовать расширенный протокол запросов.
  • prepared: использовать расширенный протокол запросов с подготовленными операторами. В режиме prepared pgbench повторно использует результат синтаксического анализа, начиная со второй итерации запроса, и поэтому выполняется быстрее, чем в других режимах.
    По умолчанию установлен простой протокол запросов. (Подробную информацию см. в главе Клиент-серверный протокол.)

-n
--no-vacuum
Не выполнять очистку таблиц перед проведением теста. Этот параметр необходим, если вы запускаете собственный сценарий, не включающий стандартные таблицы pgbench_accounts, pgbench_branches, pgbench_history и pgbench_tellers.

-N
--skip-some-updates
Запустить встроенный скрипт simple-update (простое добавление). Краткая запись для -b simple-update.

-P секунды
--progress=секунды
Отображать отчет о прогрессе через указанное число секунд. Отчет включает время, прошедшее с момента запуска, скорость (в TPS) с момента предыдущего отчета, а также среднее время задержки транзакций, стандартной отклонение и количество прервавшихся транзакций с момента последнего отчета. При дросселировании запросов (-R) время задержки вычисляется относительно запланированного времени начала транзакции, а не фактического времени ее начала, поэтому оно также включает среднее время отставания от графика . При использовании параметра --max-tries для включения повторения транзакций после ошибок сериализации/взаимоблокировки в отчет включается количество повторявшихся транзакций и общее число всех повторов.

-r
--report-per-command
Отображать следующую статистику для каждой команды после завершения теста на производительность: среднее время задержки по операторам (время выполнения с точки зрения клиента), число сбоев и число повторений после ошибок сериализации или взаимоблокировки в этой команде. Статистика по повторениям отображается в отчете, только если параметр --max-tries не равен 1.

-R скорость
--rate=скорость
Выполнять транзакции, ориентируясь на указанную скорость, а не с максимально возможной скоростью (поведение по умолчанию). Скорость задается в транзакциях в секунду. Если указанная скорость превышает максимально возможную, это ограничение скорости не повлияет на результаты.
Заданная скорость достигается запуском транзакций по графику, обусловленному распределением Пуассона. Запланированное время запуска сдвигается относительно начала операций клиента, а не завершения предыдущей транзакции. Такой подход означает, что когда транзакции отстанут от исходного запланированного времени завершения, есть возможность, что последующие транзакции снова нагонят график.
При активном дросселировании запросов задержка транзакций, выводимое в конце тестового прогона, вычисляется, исходя из запланированного времени запуска, поэтому она включает в себя время, которое каждая транзакция вынуждена была ждать завершения предыдущей транзакции. Это время ожидания называется временем отставания от графика, и его среднее и максимальное значения тоже выводятся отдельно. Задержку транзакции относительно времени ее фактического запуска, т. е. время, потраченное на выполнение транзакции в базе данных, можно вычислить, вычтя время отставания от графика из зафиксированного времени задержки.
Если вместе с --rate применяется параметр --latency-limit, транзакция может отставать так сильно, что уже превышает предел времени задержки, когда завершается предыдущая транзакция, поскольку время задержки вычисляется относительно запланированного времени запуска. Подобные транзакции не передаются на сервер, а пропускаются и подсчитываются отдельно.
Большое значение отставания от графика является показателем того, что система не может обработать транзакции с заданной скоростью и выбранным количеством клиентов и потоков. Когда среднее время выполнения транзакции превышает запланированный интервал между транзакциями, каждая последующая транзакция будет отставать все больше, и по мере выполнения тестирования время отставания от графика будет неуклонно возрастать. Когда это происходит, следует снизить заданную скорость транзакций.

-s коэффициент_масштабирования
--scale=коэффициент_масштабирования
Отобразить заданный коэффициент масштабирования в выводе pgbench. Для встроенных тестов в этом нет необходимости; правильный коэффициент масштабирования будет определен путем подсчета количества строк в таблице pgbench_branches. Однако при выполнении только пользовательских тестов производительности (параметр -f) без этого параметра коэффициент масштабирования будет выводиться как равный 1.

-S
--select-only
Запустить встроенный скрипт select-only (только выборка). Краткая запись для -b select-only.

-t транзакции
--transactions=транзакции
Количество транзакций, выполняемых каждым клиентом. Значение по умолчанию — 10.

-T секунды
--time=секунды
Выполнять тест в течение заданного числа секунд, а не по фиксированному количеству транзакций на каждого клиента. Параметры -t и -T являются взаимоисключающими.

-v
--vacuum-all
Очищать все четыре стандартные таблицы перед запуском теста. Без параметров -n и -v утилита pgbench будет очищать таблицы pgbench_tellers и pgbench_branches и опустошать таблицу pgbench_history.

--aggregate-interval=секунды
Продолжительность интервала агрегации (в секундах). Можно использовать только с параметром -l. С этим параметром журнал будет содержать сводные данные по интервалам, как описано ниже.

--failures-detailed
Отображать ошибки в журнале по транзакциям и в журнале по агрегированию, а также в основном отчете и отчетах по скриптам, группируя их по следующим типам:

--log-prefix=префикс
Установить префикс для имен файлов журнала, создаваемых с параметром --log. Значение по умолчанию — pgbench_log.

--max-tries=число_попыток
Включить повторения для транзакций с ошибками сериализации/взаимоблокировки и установить максимальное число этих попыток. Этот параметр можно сочетать с параметром --latency-limit, ограничивающим общее время всех попыток для транзакции; более того, не установив параметр --latency-limit или --time, нельзя задать неограниченное число попыток (--max-tries=0). Значение по умолчанию — 1, то есть транзакции с ошибками сериализации/взаимоблокировки не повторяются. Подробную информацию о повторении подобных транзакций см. в параграфе Сбои и повторы из-за ошибок сериализации/взаимоблокировки.

--progress-timestamp
При отображении прогресса (параметр -P) использовать временную метку (в формате эпохи Unix) вместо количества секунд, прошедших с начала запуска. Единицей измерения являются секунды с точностью др миллисекунд (в формате дроби). Это помогает сравнивать журналы, генерируемые различными программными средствами.

--random-seed=затравочное_значение
Установить затравочное значение для генератора случайных чисел. Вводит затравочное значение в системный генератор случайных чисел, который затем выдает последовательность начальных состояний генераторов, по одному для каждого потока. затравочным_значением может быть: time (по умолчанию, затравочное значение основано на текущем времени), rand (использовать надежный источник случайных чисел, выдать ошибку, если такового нет) или беззнаковое десятичное целое число. Генератор случайных чисел вызывается явно из скрипта pgbench (функции random...) или неявно (к примеру, параметр --rate использует его для создания графика выполнения транзакций). Если он устанавливается явно, значение, применяемое для затравки, отображается в терминале. Любое значение, допустимое в качестве затравочного_значения, можно также задать в переменной среды PGBENCH_RANDOM_SEED. Чтобы предоставленное затравочное значение точно действовало во всех возможных случаях использования, поставьте этот параметр первым или воспользуйтесь переменной среды .
Явное указание затравочного значения позволяет точно воспроизвести выполнение pgbench в том, что касается случайных чисел. Поскольку случайное состояние поддерживается в потоке, это означает, что при одинаковых запусках выполнение pgbench будет полностью идентичным, если один поток используется одним клиентом и отсутствуют внешние зависимости или зависимости от данных. С точки зрения статистики точное воспроизведение выполнения — идея неудачная, поскольку это может скрыть изменчивость производительности или чрезмерно завысить показатели производительности, например из-за попадания на те же страницы, что и во время предыдущего выполнения. Тем не менее это может быть и крайне полезно для отладки, к примеру, для повторения каверзного сценария, приводящего к ошибке. Применяйте этот параметр обдуманно.

--sampling-rate=частота
Частота выборки, применяемая при записи данных в журнал, которая позволяет снижать объем генерируемого журнала. Если этот параметр задан, протоколируется только указанная доля транзакций. Значение 1.0 означает, что протоколироваться будут все транзакции, значение 0.05 означает, что протоколироваться будут только 5% транзакций.
Обрабатывая файл журнала, не забудьте учесть частоту выборки. Например, при вычислении значений TPS, вам нужно будет умножить содержащиеся в нем числа соответствующим образом (к примеру, с частотой выборки 0.01 вы получите только 1/100 фактической TPS).

--show-script=имя_скрипта
Отобразить фактический код встроенного скрипта имя_скрипта в stderr и немедленно завершиться.

--verbose-errors
Выводить сообщения обо всех ошибках сериализации/взаимоблокировки и отказах (ошибки без последующего повторения транзакций), включая то, какой предел повторений был превышен и насколько. (Обратите внимание, что в этом случае объем вывода может значительно увеличиться.) Подробную информацию см. в параграфе Сбои и повторы из-за ошибок сериализации/взаимоблокировки.


Общие параметр

Утилита pgbench также принимает в качестве параметров подключения следующие аргументы командной строки:

-h имя_хоста
--host=имя_хоста
Имя хост-компьютера сервера баз данных

-p порт
--port=порт
Номер порта сервера баз данных

-U логин
--username=логин
Имя пользователя, под которым производится подключение

-V
--version
Вывести версию pgbench и завершиться.

-?
--help
Показать справку об аргументах командной строки pgbench и завершиться.


Код завершения

Успешное выполнение завершится с кодом 0. Код завершения 1 указывает на статичные проблемы, такие как недопустимые параметры командной строки или внутренние ошибки, которые не должны происходить. Начальные ошибки, возникающие при запуске теста, например, сбои при подключении, тоже имеют код завершения 1. При ошибках во время выполнения, например, ошибках в базе данных или проблемах в скрипте, будет выдан код завершения 2. В последнем случае pgbench выведет частичные результаты.


Переменные среды

PGDATABASE
PGHOST
PGPORT
PGUSER
Переменные подключения по умолчанию.

Эта утилита, как и большинство других утилит QHB, использует переменные среды, поддерживаемые libpq (см. раздел Переменные среды).

Переменная среды PG_COLOR указывает, использовать ли цвета в диагностических сообщениях. Возможные значения: always (всегда), auto (автоматически) и never (никогда).


Примечание

Какие транзакции фактически выполняются в pgbench?

Утилита pgbench выполняет тестовые скрипты, выбираемые случайным образом из указанного списка. Это могут быть как встроенные скрипты, заданные ключом -b, так и пользовательские скрипты, заданные ключом -f. Для каждого скрипта можно задать относительный вес после символа @, чтобы изменить вероятность его выбора. По умолчанию вес равен 1. Скрипты с весом 0 игнорируются.

Стандартный встроенный скрипт транзакции (также вызываемый с ключом -b tpcb-like) выполняет по семь команд на транзакцию со случайно выбранными aid, tid, bid и delta. Этот сценарий основан на тесте производительности TPC-B, но на самом деле им не является, отсюда и название.

  1. BEGIN;

  2. UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;

  3. SELECT abalance FROM pgbench_accounts WHERE aid = :aid;

  4. UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;

  5. UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;

  6. INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);

  7. END;

При выборе встроенного скрипта simple-update (также вызывается с ключом -N) шаги 4 и 5 в транзакцию не включаются. Это позволит избежать конкуренции при добавлении данных в эти таблицы, но делает тест еще менее похожим на TPC-B.

При выборе встроенного скрипта select-only (также вызывается с ключом -S) выполняется только команда SELECT.


Пользовательские скрипты

Утилита pgbench поддерживает запуск пользовательских сценариев теста производительности путем замещения стандартного скрипта транзакции (описанного выше) скриптом транзакции, считываемым из файла (параметр -f). В этом случае «транзакцией» считается одно выполнение файла скрипта.

Файл скрипта содержит одну или несколько команд SQL, оканчивающихся точкой с запятой. Пустые строки и строки, начинающиеся с --, игнорируются. Также файлы скриптов могут содержать «метакоманды», которые обрабатывает сама pgbench, как описано ниже.

Примечание
Предполагается, что скрипты pgbench не содержат незавершенных блоков транзакций SQL. Если во время выполнения клиент достигает конца скрипта, не завершив последний блок транзакции, его работа будет прервана.

Для файлов скриптов существует простой механизм подстановки переменных. Имена переменных должны состоять из букв (которые могут быть не латинскими), цифр и подчеркиваний, причем цифра не может быть первым символом. Переменные можно установить параметром командной строки -D, описанным выше, или метакомандами, описанными ниже. Кроме переменных, которые можно заранее установить параметрами командной строки -D, существует несколько переменных, заранее устанавливаемых автоматически. Они перечислены в Таблице 1. Значения, указанные для этих переменных с помощью -D, переопределяют автоматические значения. Установленное значение переменной можно добавить в команду SQL, написав :имя_переменной. При запуске нескольких клиентских сеансов каждый сеанс получает собственный набор переменных. Утилита pgbench поддерживает использование до 255 переменных в одном операторе.

Таблицы 1. Автоматические переменные pgbench

ПеременнаяОписание
client_idуникальный номер, идентифицирующий клиентский сеанс (начинается с нуля)
default_seedзатравочное значение, по умолчанию используемое в функциях хеша и псевдослучайных перестановок
random_seedзатравочное значение генератора случайных чисел (если не переписано ключом -D)
scaleтекущий коэффициент масштабирования

Метакоманды в файле скрипта начинаются с обратного слэша (\) и обычно продолжаются до конца строки, хотя их можно переносить на следующую строку, написав символы обратного слэша и возврата каретки. Аргументы метакоманд разделяются пробелами. Поддерживаются следующие метакоманды:

\gset [префикс] \aset [префикс]

Эти команды можно использовать для завершения запросов SQL вместо завершающей точки с запятой (;).

При использовании команды \gset ожидается, что предыдущий запрос SQL возвратит одну строку, столбцы которой сохраняются в переменных, названных по именам этих столбцов, а если предоставлен префикс, он добавляется к этим именам.

При использовании команды \aset столбцы всех совмещенных запросов SQL (разделенных \;) сохраняются в переменных, названных по именам этих столбцов, а если предоставлен префикс, он добавляется к этим именам. Если запрос не возвращает строк, присваивание не производится, и это можно определить, проверив переменные на существование. Если запрос возвращает несколько строк, сохраняется последнее значение.

Команды \gset и \aset нельзя использовать в конвейерном режиме, поскольку результаты запросов еще не будут доступны к тому моменту, когда могут понадобиться командам.

В следующем примере итоговый баланс из первого запроса попадает в переменную abalance, а целочисленные значения из третьего запроса — в переменные p_two и p_three. Результат второго запроса отбрасывается. Результат двух последних совмещенных запросов сохраняется в переменных four и five.

UPDATE pgbench_accounts
  SET abalance = abalance + :delta
  WHERE aid = :aid
  RETURNING abalance \gset
-- объединяет два запроса
SELECT 1 \;
SELECT 2 AS two, 3 AS three \gset p_
SELECT 4 AS four \; SELECT 5 AS five \aset

\if выражение
\elif выражение
\else
\endif

Эта группа команд реализует вкладываемые условные блоки, подобно \if выражение в psql. Условные выражения идентичны таковым в команде \set, причем ненулевые выражения интерпретируются как true.

\set имя_переменной выражение

Устанавливает в переменной имя_переменной значение, вычисленное из выражения. Выражение может содержать константу NULL, логические константы TRUE и FALSE, целочисленные константы, например, 5432, константы двойной точности с плавающей запятой, например, 3.14159, ссылки на переменные :имя_переменной, операторы с обычными для SQL приоритетностью и ассоциативностью, вызовы функций, общие условные выражения CASE SQL и круглые скобки.

Функции и большинство операторов возвращают NULL для входных данных NULL.

В контексте проверки условий ненулевые числовые значения являются TRUE, нулевые числовые значения и NULLFALSE.

Слишком большие или слишком маленькие целочисленные константы или константы двойной точности с плавающей запятой, а также целочисленные арифметические операторы (+, -, * и /) вызывают ошибки переполнения.

Если в конструкции 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 число [ us | ms | s ]

Приостанавливает выполнение скрипта на заданный период в микросекундах (us), миллисекундах (ms) или секундах (s). Если единицы опущены, по умолчанию значение считается заданным в секундах. Задаваемое число может быть целочисленной константой или ссылкой :имя_переменной на переменную с целочисленным значением.

Пример:

\sleep 10 ms

\setshell имя_переменной команда [ аргумент ... ]

Устанавливает в переменной имя_переменной результат команды оболочки команда с заданными аргументами. Эта команда должна возвращать целочисленное значение в свой стандартный вывод.

команда и каждый аргумент могут быть текстовой константой или ссылкой на переменную :имя_переменной. Если вы хотите использовать аргумент, начинающийся с двоеточия, напишите в начале этого аргумента дополнительное двоеточие.

Пример:

\setshell variable_to_be_assigned command literal_argument :variable ::literal_starting_with_colon

\shell команда [ аргумент ... ]

То же, что и \setshell, но результат команды отбрасывается.

Пример:

\shell command literal_argument :variable ::literal_starting_with_colon

\startpipeline
\endpipeline

Эти команды разделяют начало и конец конвейера команд SQL. В конвейерном режиме команды передаются серверу, не дожидаясь результатов предыдущих команд. Подробную информацию см. в разделе Конвейерный режим. Для конвейерного режима нужно использовать расширенный протокол запросов.


Встроенные операторы

Арифметические, битовые и логические операторы, перечисленные в Таблице 2, встроены в pgbench и могут использоваться в выражениях, находящихся в \set. Эти операторы перечислены в порядке возрастания их приоритета. Не считая отмеченных исключений, операторы, принимающие два числовых аргумента, будут выдавать значение двойной точности с плавающей запятой, если какой-либо из аргументов имеет такой тип; в противном случае они выдают целочисленный результат.

Таблица 2. Операторы pgbench

Оператор
Описание
Пример(ы)
логическое_значение OR логическое_значениелогическое_значение
Логическое ИЛИ
5 or 0 → TRUE
логическое_значение AND логическое_значениелогическое_значение
Логическое И
3 and 0 → FALSE
NOT логическое_значениелогическое_значение
Логическое НЕ
not false → TRUE
логическое_значение IS [NOT] (NULL|TRUE|FALSE) → логическое_значение
Проверки логических значений
1 is null → FALSE
значение ISNULL|NOTNULL → логическое_значение
Проверки на NULL
1 notnull → TRUE
число = числологическое_значение
Равно
5 = 4 → FALSE
число <> числологическое_значение
Не равно
5 <> 4 → TRUE
число != числологическое_значение
Не равно
5 != 5 → FALSE
число < числологическое_значение
Меньше
5 < 4 → FALSE
число <= числологическое_значение
Меньше или равно
5 <= 4 → FALSE
число > числологическое_значение
Больше
5 > 4 → TRUE
число >= числологическое_значение
Больше или равно
5 >= 4 → TRUE
целое_число | целое_числоцелое_число
Битовое ИЛИ
1 | 2 → 3
целое_число # целое_числоцелое_число
Битовое исключающее ИЛИ
1 # 3 → 2
целое_число & целое_числоцелое_число
Битовое И
1 & 3 → 1
~ целое_числоцелое_число
Битовое НЕ
~ 1 → -2
целое_число << целое_числоцелое_число
Битовый сдвиг влево
1 << 2 → 4
целое_число >> целое_числоцелое_число
Битовый сдвиг вправо
5 <= 4 → FALSE
число + числочисло
Сложение
5 + 4 → 9
число - числочисло
Вычитание
3 - 2.0 → 1.0
число * числочисло
Умножение
5 * 4 → 20
число / числочисло
Деление (если оба аргумента целочисленные, результат округляется в сторону нуля)
5 / 3 → 1
целое_число % целое_числоцелое_число
Остаток от деления (по модулю)
3 % 2 → 1
- числочисло
Смена знака
- 2.0 → -2.0

Встроенные функции

Функции, перечисленные в Таблице 3, встроены в pgbench и могут использоваться в выражениях, находящихся в \set.

Таблица 3. Функции pgbench

Функция
Описание
Пример(ы)
abs ( число ) → тип аргумента
Абсолютное значение (модуль числа)
abs(-17) → 17
debug ( число ) → тип аргумента
Выводит аргумент в stderr и возвращает этот аргумент.
debug(5432.1) → 5432.1
debug ( число ) → double
Приводит аргумент к значению двойной точности с плавающей запятой.
double(5432) → 5432.0
exp ( число ) → double
Экспонента (e возводится в заданную степень)
exp(1.0) → 2.718281828459045
greatest ( число [, ... ] ) → double, если какой-либо из аргументов double, иначе — integer
Выбирает наибольшее значение среди аргументов.
greatest(5, 4, 3, 2) → 5
hash ( значение [, затравочное_значение ] ) → integer
Это псевдоним для hash_murmur2.
hash(10, 5432) → -5817877081768721676
hash_fnv1a ( значение [, затравочное_значение ] ) → integer
Вычисляет хеш по алгоритму FNV-1a.
hash_fnv1a(10, 5432) → -7793829335365542153
hash_murmur2 ( value [, seed ] ) → integer
Вычисляет хеш по алгоритму MurmurHash2.
hash_murmur2(10, 5432) → -5817877081768721676
int ( число ) → integer
Приводит аргумент к целочисленному значению.
int(5.4 + 3.8) → 9
least ( число [, ... ] ) → double, если какой-либо из аргументов double, иначе — integer
Выбирает наименьшее значение среди аргументов.
least(5, 4, 3, 2.1) → 2.1
ln ( число ) → double
Натуральный логарифм
ln(2.718281828459045) → 1.0
mod ( целое, целое ) → integer
Остаток от деления (по модулю)
mod(54, 32) → 22
permute ( i, размер [, затравочное_значение ] ) → integer
Переставленное значение i в диапазоне [0, размер). Это новая позиция i (по модулю величины) в псевдослучайной перестановке целых чисел 0...размер-1, параметризированной затравочным_значением; см. ниже.
permute(0, 4) → an integer between 0 and 3
pi () → double
Приближенное значение π
pi() → 3.14159265358979323846
pow ( x, y ) → double
power ( x, y ) → double
x возводится в степень y
pow(2.0, 10) → 1024.0
random ( lb, ub ) → integer
Вычисляет случайное целое число с равномерным распределением в диапазоне [lb, ub].
random(1, 10) → целое между 1 и 10
random_exponential ( lb, ub, параметр ) → integer
Вычисляет случайное целое число с экспоненциальным распределением в диапазоне [lb, ub]; см. ниже.
random_exponential(1, 10, 3.0) → целое между 1 и 10
random_gaussian ( lb, ub, параметр ) → integer
Вычисляет случайное целое число с распределением Гаусса в диапазоне [lb, ub]; см. ниже.
random_gaussian(1, 10, 2.5) → целое между 1 и 10
random_zipfian ( lb, ub, parameter ) → integer
Вычисляет случайное целое число с распределением Ципфа в диапазоне [lb, ub]; см. ниже.
random_zipfian(1, 10, 1.5) → целое между 1 и 10
sqrt ( число ) → double
Квадратный корень
sqrt(2.0) → 1.414213562

Функция random генерирует значения, используя равномерное распределение, то есть все значения выдаются из заданного диапазона и с равной вероятностью. Функциям random_exponential, random_gaussian и random_zipfian требуется дополнительный параметр типа double, определяющий точную форму распределения.

  • Для экспоненциального распределения параметр управляет распределением путем усечения быстро снижающегося экспоненциального распределения в точке параметр, а затем проецирования его на целые числа между границами. Точнее говоря, с
    f(x) = exp(-параметр * (x - min) / (max - min + 1)) / (1 - exp(-параметр))
    значение i между min и max (включительно) выдается с вероятностью: f(i) - f(i + 1).
    С точки зрения интуиции чем больше параметр, тем чаще происходит обращение к значениям, близким к min, и тем реже — к значениям, близким к max. Чем параметр ближе к 0, тем более плоским (более равномерным) будет распределение. В грубом приближении при таком распределении наиболее частый 1% значений в диапазоне, близком к min, выдается параметр% времени. Значение параметра должно быть строго положительным.

  • Для распределения Гаусса интервал отображается на стандартное нормальное распределение (классическая кривая Гаусса в форме колокола), обрезанное в точке -параметр слева и +параметр справа. При этом вероятнее всего будут выданы значения в середине интервала. Точнее говоря, если PHI(x) — кумулятивная функция стандартного нормального распределения со средним значением mu, определенным как (max + min) / 2.0, и
    f(x) = PHI(2.0 * параметр * (x - mu) / (max - min + 1)) /
    (2.0 * PHI(параметр) - 1)
    то значение i между min и max (включительно) выдается с вероятностью: f(i + 0.5) - f(i - 0.5). С точки зрения интуиции чем больше параметр, тем чаще выдаются значения ближе к середине интервала, и тем реже — значения ближе к границам min и max. Примерно 67% значений выдаются из среднего интервала 1.0 / параметр, то есть примерно плюс/минус 0.5 / параметр от среднего значения, и 95% из среднего интервала 2.0 / параметр, то есть примерно плюс/минус 1.0 / параметр от среднего значения; к примеру, если параметр равен 4.0, 67% значений выдаются из средней четверти (1.0 / 4.0) интервала (т. е. от 3.0 / 8.0 до 5.0 / 8.0) и 95% — из средней половины (2.0 / 4.0) интервала (из второй и третьей четвертей). Минимально допустимое значение параметра — 2.0.

  • Функция random_zipfian генерирует ограниченное распределение Ципфа. параметр определяет, насколько несимметрично распределение. Чем больше параметр, тем чаще выдаются значения ближе к началу интервала. Это распределение таково, что, исходя из предположения, что диапазон начинается с 1, отношение вероятности получения k к вероятности получения k+1 равно ((k+1)/k)**параметр. К примеру, random_zipfian(1, ..., 2.5) выдает значение 1 примерно в (2/1)**2.5 = 5.66 раза чаще значения 2, которое, в свою очередь, выдается в (3/2)**2.5 = 2.76 раз чаще значения 3, и т. д.
    Реализация этого распределения в pgbench основана на книге "Non-Uniform Random Variate Generation" (Генерирование неравномерно распределенных случайных переменных), Люк Деврой (Luc Devroye), стр. 550-551, Springer 1986. Из-за ограничений этого алгоритма значение параметра ограничено диапазоном [1.001, 1000].

Примечание
При разработке теста оценки производительности, выбирающей строки неравномерно, учтите, что выбираемые строки могут коррелировать с другими данными, например, с идентификаторами из последовательности или с физическим порядком строк, что может искажать показатели производительности.

Чтобы избежать этого, можно использовать функцию permute (или какой-то другой дополнительный шаг со сходным эффектом) для перемешивания выбранных строк и удаления таких корреляций.

Функции хеширования hash, hash_murmur2 и hash_fnv1a принимают на вход значение и необязательный параметр с затравочным значением. В случае, если затравочное значение не предоставляется, используется значение переменной :default_seed, которая инициализируется случайным образом, если не установлена параметром командной строки -D.

Функция permute принимает на вход значение, размер и необязательный параметр затравочного значения. Она генерирует псевдослучайную перестановку целых чисел в диапазоне [0, размер) и возвращает индекс входного значения в переставленных значениях. Выбираемая перестановка параметризируется затравочным значением, которое (если не задано) по умолчанию будет иметь значение :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 записывает информацию о каждой транзакции в файл журнала. Этот файл журнала будет называться префикс.nnn, где префикс по умолчанию — pgbench_log, а nnn — PID процесса pgbench. Префикс можно изменить с помощью параметра --log-prefix. Если параметр -j равен 2 или выше, чтобы было несколько рабочих потоков, каждый из них будет иметь собственный файл журнала. Первый рабочий процесс будет использовать для своего файла журнала то же имя, что и в стандартном случае с одним рабочим процессом. Дополнительные файлы журнала для остальных рабочих процессов будут называться префикс.nnn.mmm, где mmm — порядковый номер отдельного рабочего процесса, начиная с 1.

Каждая строка в файле журнала описывает одну транзакцию. Она содержит следующие поля, разделенные пробелами:

id_клиента
идентифицирует клиентский сеанс, в котором выполнялась транзакция

число_транзакций
считает, сколько транзакций было выполнено в этом сеансе

продолжительность
время, затраченное на выполнение транзакции, в микросекундах

номер_скрипта
идентифицирует файл скрипта, использовавшегося для транзакции (полезно, когда в параметрах -f или -b указано несколько скриптов)

время_эпохи
время завершения транзакции, в виде метки времени эпохи Unix

время_мкс
доли секунды в отметке времени завершения транзакции, в микросекундах

отставание_от_графика
задержка начала транзакции, то есть разница между запланированным временем запуска транзакции и временем фактического запуска, в микросекундах (присутствует, только если задан параметр --rate)

повторения
число повторений после ошибок сериализации или взаимоблокировки во время транзакции (присутствует, только если параметр --max-tries не равен единице)

Когда одновременно используются параметры --rate и --latency-limit в поле продолжительность для пропущенных транзакций будет выводиться skipped. Если транзакция завершается ошибкой, в поле продолжительность будет выводиться failed. Если вы используете параметр --failures-detailed, в поле продолжительность неуспешной транзакции будет выводиться 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 (обратите внимание на дополнительный столбец отставание_от_графика):

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 (обратите внимание на дополнительный столбец повторения):

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, тип ошибки в поле продолжительность выводится следующим образом:

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 для файлов журнала используется другой формат. Каждая строка журнала описывает один интервал агрегации. Она содержит следующие поля, разделенные пробелами:

начало_интервала
начальное время интервала в виде метки времени эпохи Unix

число_транзакций
количество транзакций в этом интервале

сумма_времени_отклика
суммарное время отклика транзакций

сумма_времени_отклика_2
сумма квадратов времени отклика транзакций

мин_время_отклика
минимальное время отклика транзакции

макс_время_отклика
максимальное время отклика транзакции

сумма_задержек
сумма задержек начала транзакций (ноль, если не указан параметр --rate)

сумма_задержек_2
сумма квадратов задержек начала транзакций (ноль, если не указан параметр --rate)

мин_задержка
минимальная задержка начала транзакции (ноль, если не указан параметр --rate)

макс_задержка
максимальная задержка начала транзакции (ноль, если не указан параметр --rate)

пропущеные
количество транзакций, пропущенных из-за того, что они начались бы слишком поздно (ноль, если не указаны параметры --rate и --latency-limit)

повторенные
количество повторенных транзакций (ноль, если параметр --max-tries не равен единице)

повторы
число повторов после ошибок сериализации или взаимоблокировки (ноль, если параметр --max-tries не равен единице)

сбои_сериализации количество транзакций, в которых произошла ошибка сериализации и которые затем не были повторены (ноль, если не указан параметр --failures-detailed)

сбои_взаимоблокировки
количество транзакций, в которых произошла ошибка взаимоблокировки и которые затем не были повторены (ноль, если не указан параметр --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 собирает следующую статистику по каждому оператору:

Отчет отображает статистику повторов, только если параметр --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 (которых теоретически не может быть).
  • Ошибки при манипулировании клиентами в потоке (например, клиент не смог запустить подключение к серверу баз данных, сокет для подключения клиента к серверу баз данных стал недействительным). В таких случаях все клиенты этого потока останавливаются, тогда как другие потоки продолжают работать.

  • Ошибки непосредственно клиента. Они ведут к немедленному завершению pgbench с соответствующим сообщением об ошибке только в случае внутренней ошибки pgbench. В противном случае самое худшее, что может произойти, это прерывание работы клиента с ошибкой, тогда как другие клиенты продолжат работу (однако некоторые клиентские ошибки обрабатываются без прерывания работы клиента, и о них сообщается отдельно, см. ниже). Далее в этом параграфе предполагается, что рассматриваемые ошибки относятся только к ошибкам непосредственно клиента, а не ко внутрениим ошибкам pgbench.

Работа клиента прерывается в случае серьезной ошибки; например, если было потеряно соединение с сервером баз данных или конец скрипта был достигнут до завершения последней транзакции. Кроме того, работа клиента прерывается, если выполнение команды SQL или метакоманды завершается сбоем не по причине ошибки сериализации или взаимоблокировки. Иначе же, если команда SQL завершается ошибкой сериализации или взаимоблокировки, клиент не прерывает работу. В таких случаях текущая транзакция откатывается, при этом клиентским переменным возвращаются те значения, которые были установлены до начала этой транзакции (предполагается, что один скрипт транзакции содержит только одну транзакцию; подробную информацию см. в параграфе Какие транзакции фактически выполняются в pgbench?). Транзакции с ошибками сериализации или взаимоблокировки повторяются после отката, пока не завершаются успехом или не достигают максимального числа попыток (заданного параметром --max-tries) / максимальной продолжительности повторений (заданной параметром --latency-limit) / истечения времени выполнения теста (заданного параметром --time). Если последняя попытка завершается сбоем, эта транзакция отображается как неуспешная, но клиент не прерывается и продолжает работу.

Примечание
Если не указать параметр --max-tries, транзакция никогда не будет повторяться после ошибки сериализации или взаимоблокировки, поскольку его значение по умолчанию равно 1. Чтобы ограничить только максимальную продолжительность попыток, задайте неограниченное число попыток (--max-tries=0) и установите параметр --latency-limit. Кроме того, можно воспользоваться параметром --time, чтобы ограничить продолжительность теста при неограниченном числе попыток.

Будьте осторожны при повторении скриптов, содержащих несколько транзакций: скрипт всегда повторяется полностью, поэтому успешные транзакции могут выполняться несколько раз.

Будьте осторожны при повторении транзакций с командами оболочки. В отличие от результатов команд SQL, результаты команд оболочки не откатываются, за исключением значения переменной команды \setshell.

Время отклика успешной транзакции включает общее время выполнения транзакции с учетом откатов и повторов. Время отклика измеряется только для успешных транзакций и команд, но не для завершившихся сбоем.

Основной отчет содержит количество неуспешных транзакций. Если параметр --max-tries не равен 1, основной отчет также будет содержать статистику, относящуюся к повторам: общее количество повторявшихся транзакций и общее число повторов. Отчет по скриптам наследует все эти поля от основного отчета. Отчет по операторам отображает статистику повторов, только если параметр --max-tries не равен 1.

Если вы хотите сгруппировать сбои по базовым типам в журнале по транзакциям и журнале с агрегированием, а также в основном отчете и отчете по скриптам, воспользуйтесь параметром --failures-detailed. Если вы также хотите отличать все ошибки и сбои (ошибки без последующих повторов) по типу, включая то, какой предел повторов был превышен для сбоев сериализации/взаимоблокировки и насколько, воспользуйтесь параметром --verbose-errors.


Методические рекомендации

Крайне легко получить с помощью pgbench совершенно бессмысленные числа. Приведенные здесь рекомендации помогут вам получить полезные результаты.

Во-первых, никогда не верьте тесту, длящемуся всего несколько секунд. Воспользуйтесь параметром -t или -T, чтобы тест выполнялся по меньшей мере несколько минут, чтобы исключить шум. В некоторых случаях могут понадобиться часы, чтобы получить воспроизводимые числа. Имеет смысл запустить выполнение теста несколько раз, чтобы понять, являются ли полученные числа воспроизводимыми.

Для стандартного тестового сценария по типу TPC-B коэффициент масштабирования инициализации (-s) должен быть как минимум не меньше максимального количества клиентов, с которым вы намерены провести тест (-c); иначе вы будете по большей части измерять время конкурентных изменений. В таблице pgbench_branches содержится всего -s строк, и каждая транзакция желает изменить одну из них, поэтому если значения -c превышают -s, это несомненно приведет к блокировкам многих транзакций, ожидающих завершения других транзакций.

Стандартный сценарий тестирования тоже довольно чувствителен к тому, сколько времени прошло с момента инициализации таблиц: накопление неактуальных строк и неиспользуемого пространства в таблицах меняет результаты. Для понимания результатов следует отслеживать общее число изменений и когда проводилась очистка. Если включена автоочистка, это может привести к непредсказуемым изменениям в измеряемой производительности.

Ограничение утилиты pgbench состоит в том, что она сама может стать сдерживающим фактором при попытке протестировать большое число клиентских сеансов. Этого можно избежать, запуская pgbench на другом компьютере, не на сервере баз данных, хотя при этом ключевым моментом станет низкая скорость сети. Возможно даже, будет полезно запускать для одного сервера баз данных несколько экземпляров pgbench параллельно, на нескольких клиентских компьютерах.


Безопасность

Если к базе данных, которая не приведена в соответствие с шаблоном безопасного использования схем, имеют доступ недоверенные пользователи, не запускайте pgbench в этой базе данных. pgbench использует имена, не дополненные схемой, и не манипулирует путем поиска.