pgbench#

pgbench

pgbench

pgbench — запустить тест производительности на Tantor BE

Синтаксис

pgbench -i [option...] [dbname]

pgbench [option...] [dbname]

Описание

pgbench - это простая программа для запуска тестов производительности на Tantor BE. Она выполняет одну и ту же последовательность 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)

Первые семь строк отчета содержат некоторые из наиболее важных настроек параметров. Шестая строка отчета содержит максимальное количество попыток для транзакций с ошибками сериализации или блокировки (см. Failures and Serialization/Deadlock Retries для получения дополнительной информации). Восьмая строка отчета содержит количество завершенных и запланированных транзакций (последнее является просто произведением количества клиентов и количества транзакций на клиента); они будут равными, если выполнение завершилось успешно или если не было выполнено ни одной SQL-команды. (В режиме -T выводится только фактическое количество транзакций). Следующая строка отчета содержит количество неудачных транзакций из-за ошибок сериализации или блокировки (см. Failures and Serialization/Deadlock Retries для получения дополнительной информации). Последняя строка отчета содержит количество транзакций в секунду.

Для выполнения теста транзакций TPC-B по умолчанию необходимо предварительно настроить определенные таблицы. pgbench должен быть вызван с опцией -i (initialize), чтобы создать и заполнить эти таблицы. (Если вы тестируете собственный скрипт, вам не понадобится этот шаг, но вместо этого вам потребуется выполнить все необходимые настройки для вашего теста). Процесс инициализации выглядит следующим образом:

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 (fillfactor) также можно использовать в этом случае.

После выполнения необходимой настройки вы можете запустить свой бенчмарк с помощью команды, которая не включает -i, то есть

pgbench [ options ] dbname

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

Опции

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

Опции инициализации

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

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 or G (Generate data, client-side or server-side) #

Сгенерируйте данные и загрузите их в стандартные таблицы, заменив любые уже существующие данные.

С использованием g (генерация данных на стороне клиента), данные генерируются в клиенте pgbench и затем отправляются на сервер. Это интенсивно использует пропускную способность клиента/сервера через COPY. pgbench использует опцию FREEZE с версии 14 или более поздней PostgreSQL для ускорения последующего VACUUM, если включены разделы. Использование g приводит к печати одного сообщения каждые 100 000 строк при генерации данных для таблицы pgbench_accounts.

С использованием 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 с заданным fillfactor. По умолчанию равен 100.

-n
--no-vacuum #

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

-q
--quiet #

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

Эта настройка не имеет эффекта, если G указано в -I.

-s scale_factor
--scale=scale_factor #

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

--foreign-keys #

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

--index-tablespace=index_tablespace #

Создавайте индексы в указанном табличном пространстве, а не в табличном пространстве по умолчанию.

--partition-method=NAME #

Создайте секционированную таблицу pgbench_accounts с методом NAME. Ожидаемые значения: 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
--debug #

Вывод отладочной информации.

-D varname=value
--define=varname=value #

Определите переменную для использования в пользовательском скрипте (см. ниже). Разрешается использование нескольких параметров -D.

-f filename[@weight]
--file=filename[@weight] #

Добавьте транзакционный скрипт, прочитанный из filename, в список скриптов, которые будут выполнены.

При желании, после @ можно указать целочисленный вес, чтобы настроить вероятность выбора этого сценария по сравнению с другими. По умолчанию вес равен 1. (Чтобы использовать имя файла сценария, которое содержит символ @, добавьте вес, чтобы исключить неоднозначность, например filen@me@1). Подробности см. ниже.

-j threads
--jobs=threads #

Количество рабочих потоков внутри pgbench. Использование более одного потока может быть полезным на многоядерных машинах. Клиенты распределяются как можно равномерно между доступными потоками. По умолчанию установлено значение 1.

-l
--log #

Запишите информацию о каждой транзакции в файл журнала. См. ниже для получения более подробной информации.

-L limit
--latency-limit=limit #

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

Когда используется ограничение скорости (--rate=...), транзакции, отставающие от графика более чем на limit мс и, следовательно, не имеющие никаких шансов соответствовать ограничению задержки, вообще не отправляются на сервер. Они подсчитываются и отдельно отображаются как прне указанные.

Когда используется опция --max-tries, транзакция, которая не удалась из-за сериализационной аномалии или из-за блокировки, не будет повторно попытаться, если общее время всех попыток превышает limit мс. Чтобы ограничить только время попыток, а не их количество, используйте --max-tries=0. По умолчанию опция --max-tries установлена на 1, и транзакции с ошибками сериализации/блокировки не повторяются. См. Failures and Serialization/Deadlock Retries для получения дополнительной информации о повторных попытках таких транзакций.

-M querymode
--protocol=querymode #

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

  • simple: использовать простой протокол запросов.

  • extended: использовать расширенный протокол запросов.

  • prepared: использовать расширенный протокол запросов с подготовленными операторами.

В режиме запроса prepared , pgbench повторно использует результат анализа разбора, начиная со второй итерации запроса, поэтому pgbench работает быстрее, чем в других режимах.

Сохраняется протокол простого запроса по умолчанию. (См. Глава 52 для получения дополнительной информации).

-n
--no-vacuum #

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

-N
--skip-some-updates #

Запустите встроенный сценарий простого обновления. Сокращенная форма для -b simple-update.

-P sec
--progress=sec #

Показывать отчет о ходе выполнения каждые sec секунд. Отчет включает время с начала выполнения, TPS с момента последнего отчета, среднюю задержку транзакции, стандартное отклонение и количество неудачных транзакций с момента последнего отчета. При ограничении (-R) задержка вычисляется относительно запланированного времени начала транзакции, а не фактического времени начала, поэтому она также включает среднее время задержки планирования. Когда используется --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 #

Выполните встроенный сценарий только для выборки. Сокращение для -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. С этой опцией журнал содержит сводные данные по интервалам, описанные ниже.

--failures-detailed #

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

  • сбои сериализации;

  • сбои взаимоблокировки;

См. Failures and Serialization/Deadlock Retries для получения дополнительной информации.

--log-prefix=prefix #

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

--max-tries=number_of_tries #

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

--progress-timestamp #

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

--random-seed=seed #

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

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

--sampling-rate=rate #

Частота выборки, используемая при записи данных в журнал, для сокращения объема генерируемого журнала. Если задан этот параметр, в журнал будут записываться только указанная доля транзакций. Значение 1.0 означает, что все транзакции будут записаны в журнал, а значение 0.05 означает, что в журнал будут записаны только 5% транзакций.

Не забудьте учитывать частоту выборки при обработке файла журнала. Например, при вычислении значений TPS необходимо умножать числа соответствующим образом (например, при частоте выборки 0,01 вы получите только 1/100 от фактического значения TPS).

--show-script=scriptname #

Показать фактический код встроенного сценария scriptname на stderr и немедленно завершить выполнение.

--verbose-errors #

Печатать сообщения обо всех ошибках и сбоях (ошибки без повторных попыток) включая, какой лимит для повторных попыток был превышен и насколько он был превышен для сбоев сериализации/взаимоблокировки. (Обратите внимание, что в этом случае вывод может быть значительно увеличен.) См. Failures and Serialization/Deadlock Retries для получения дополнительной информации.

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

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

-h hostname
--host=hostname #

Имя хоста сервера базы данных

-p port
--port=port #

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

-U login
--username=login #

Имя пользователя для подключения

-V
--version #

Вывести версию pgbench и завершить работу.

-?
--help #

Показать справку о командной строке для приложения pgbench и выйти.

Статус выхода

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

Окружение

PGDATABASE
PGHOST
PGPORT
PGUSER #

Параметры подключения по умолчанию.

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

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

Примечания

Что на самом деле выполняется в pgbench в транзакции?

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

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

Примечание

До PostgreSQL 9.6 SQL-команды в файлах скриптов завершались переводами строк, поэтому их нельзя было продолжать на следующей строке. Теперь точка с запятой обязательна для разделения последовательных SQL-команд (хотя SQL-команда не требует точки с запятой, если за ней следует метакоманда). Если вам нужно создать файл скрипта, который будет работать как с старыми, так и с новыми версиями pgbench, убедитесь, что каждая SQL-команда записана на одной строке и заканчивается точкой с запятой.

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

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

Таблица 292. 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's \if expression. Условные выражения идентичны тем, что используются с \set, где ненулевые значения интерпретируются как true.

\set varname expression #

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

Все функции и большинство операторов возвращают NULL при вводе NULL.

Для условных целей, ненулевые числовые значения являются TRUE, нулевые числовые значения и NULL являются FALSE.

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

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

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
\endpipeline #

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

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

Все арифметические, побитовые, сравнительные и логические операторы, перечисленные в Таблица 293, встроены в pgbench и могут использоваться в выражениях, появляющихся в \set. Операторы перечислены в порядке возрастания приоритета. За исключением указанных случаев, операторы, принимающие два числовых входа, будут производить значение типа double, если хотя бы один из входов является double, в противном случае они будут производить целочисленный результат.

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

Оператор

Описание

Пример(ы)

boolean OR booleanboolean

Логическое ИЛИ

5 или 0TRUE

boolean AND booleanboolean

Логическое И

3 и 0FALSE

NOT booleanboolean

Логическое НЕ

not falseTRUE

boolean IS [NOT] (NULL|TRUE|FALSE)boolean

Тесты логических значений

1 is nullFALSE

value ISNULL|NOTNULLboolean

Тесты на нулевое значение

1 notnullTRUE

number = numberboolean

Равно

5 = 4FALSE

number <> numberboolean

Не равно

5 <> 4TRUE

number != numberboolean

Не равно

5 != 5FALSE

number < numberboolean

Меньше чем

5 < 4FALSE

number <= numberboolean

Меньше или равно

5 <= 4FALSE

number > numberboolean

Больше чем

5 > 4TRUE

number >= numberboolean

Больше или равно

5 >= 4TRUE

integer | integerinteger

Побитовое ИЛИ

1 | 23

integer # integerinteger

Побитовое исключающее ИЛИ

1 # 32

integer & integerinteger

Побитовое И

1 & 31

~ integerinteger

Побитовое НЕ

~ 1-2

integer << integerinteger

Побитовый сдвиг влево

1 << 24

integer >> integerinteger

Побитовый сдвиг вправо

8 >> 22

number + numbernumber

Дополнение

5 + 49

number - numbernumber

Вычитание

3 - 2.01.0

number * numbernumber

Умножение

5 * 420

number / numbernumber

Division (обрезает результат к нулю, если оба входных значения являются целыми числами)

5 / 31

integer % integerinteger

Модуло (остаток)

3 % 21

- numbernumber

Отрицание

- 2.0-2.0


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

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

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

Функция

Описание

Пример(ы)

abs ( number ) → UNION | INTERSECT | EXCEPT

Абсолютное значение

abs(-17)17

debug ( number ) → UNION | INTERSECT | EXCEPT

Печатает аргумент в stderr и возвращает аргумент.

debug(5432.1)5432.1

double ( number ) → double

Сasts to double.

double(5432)5432.0

exp ( number ) → double

Экспонента (e, возведенная в заданную степень)

exp(1.0)2.718281828459045

greatest ( number [, ... ] ) → double if any argument is double, else integer

Выбирает наибольшее значение среди аргументов.

greatest(5, 4, 3, 2)5

hash ( value [, seed ] ) → integer

Это псевдоним для hash_murmur2.

hash(10, 5432)-5817877081768721676

hash_fnv1a ( value [, seed ] ) → integer

Вычисляет хеш FNV-1a FNV-1a hash..

hash_fnv1a(10, 5432)-7793829335365542153

hash_murmur2 ( value [, seed ] ) → integer

Вычисляет хеш MurmurHash2 MurmurHash2 hash.

hash_murmur2(10, 5432)-5817877081768721676

int ( number ) → integer

Приведение к целому числу.

int(5.4 + 3.8)9

least ( number [, ... ] ) → double if any argument is double, else integer

Выбирает наименьшее значение из аргументов.

least(5, 4, 3, 2.1)2.1

ln ( number ) → double

Натуральный логарифм

ln(2.718281828459045)1.0

mod ( integer, integer ) → integer

Модуло (остаток)

mod(54, 32)22

permute ( i, size [, seed ] ) → integer

Переставленное значение i, в диапазоне [0, size). Это новая позиция i (по модулю size) в псевдослучайной перестановке целых чисел 0...size-1, параметризованной seed, см. ниже.

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)an integer between 1 and 10

random_exponential ( lb, ub, parameter ) → integer

Вычисляет случайное целое число, распределенное экспоненциально в интервале [lb, ub], см. ниже.

random_exponential(1, 10, 3.0)an integer between 1 and 10

random_gaussian ( lb, ub, parameter ) → integer

Вычисляет целое число, распределенное по Гауссу в интервале [lb, ub], см. ниже.

random_gaussian(1, 10, 2.5)an integer between 1 and 10

random_zipfian ( lb, ub, parameter ) → integer

Вычисляет случайное целое число, распределенное по закону Ципфа в интервале [lb, ub], см. ниже.

random_zipfian(1, 10, 1.5)an integer between 1 and 10

sqrt ( number ) → double

Квадратный корень

sqrt(2.0)1.414213562


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

  • Для экспоненциального распределения параметр parameter контролирует распределение, обрезая быстро убывающее экспоненциальное распределение на parameter, а затем проецируя на целые числа между границами. Чтобы быть точным, с

    f(x) = exp(-parameter * (x - min) / (max - min + 1)) / (1 - exp(-parameter))

    Затем значение i между min и max включительно выбирается с вероятностью: f(i) - f(i + 1).

    Intuitively, the larger the parameter, the more frequently values close to min are accessed, and the less frequently values close to max are accessed. The closer to 0 parameter is, the flatter (more uniform) the access distribution. A crude approximation of the distribution is that the most frequent 1% values in the range, close to min, are drawn parameter% of the time. The parameter value must be strictly positive.

  • Для гауссового распределения интервал отображается на стандартное нормальное распределение (классическая колоколообразная гауссова кривая), обрезанное слева на -parameter и справа на +parameter. Значения в середине интервала более вероятно будут выбраны. А именно, если PHI(x) является накопленной функцией распределения стандартизированного нормального распределения, среднее значение mu определяется как (max + min) / 2.0, с

    f(x) = PHI(2.0 * параметр * (x - среднее) / (максимальное - минимальное + 1)) /
           (2.0 * PHI(параметр) - 1)

    Затем значение i между min и max включительно выбирается с вероятностью: 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/1)**2.5 = 5.66 раз чаще, чем 2, который сам производится (3/2)**2.5 = 2.76 раз чаще, чем 3, и так далее.

    Реализация pgbench основана на "Генерации неоднородных случайных величин", Люк Деврой, стр. 550-551, Springer 1986. Из-за ограничений этого алгоритма, значение parameter ограничено диапазоном [1.001, 1000].

Примечание

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

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

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

permute принимает входное значение, размер и необязательный параметр seed. Он генерирует псевдослучайную перестановку целых чисел в диапазоне [0, size) и возвращает индекс входного значения в переставленных значениях. Перестановка выбирается с помощью seed, который по умолчанию равен :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)

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

\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 - это PID процесса pgbench. Префикс можно изменить с помощью опции --log-prefix. Если опция -j равна 2 или больше, то есть есть несколько рабочих потоков, каждый из них будет иметь свой собственный файл журнала. Первый рабочий поток будет использовать то же имя файла журнала, что и в случае стандартного однопоточного режима. Дополнительные файлы журнала для других рабочих процессов будут называться prefix.nnn.mmm, где mmm - это последовательный номер для каждого рабочего процесса, начиная с 1.

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

client_id

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

transaction_no

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

time

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

script_no

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

time_epoch

время завершения транзакции в формате Unix-эпохи

time_us

дробная часть времени завершения транзакции, в микросекундах

schedule_lag

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

retries

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

Когда используются оба параметра --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 не равно одному)

retries

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

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 сообщает среднее значение всех успешных запусков оператора.

  • Количество ошибок в данном операторе. См. Failures and Serialization/Deadlock Retries для получения дополнительной информации.

  • Количество повторных попыток после возникновения ошибки сериализации или блокировки в данном операторе. См. Failures and Serialization/Deadlock Retries для получения дополнительной информации.

Отчет отображает статистику повторных попыток только если опция --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;

Еще один пример вывода для скрипта по умолчанию с использованием уровня изоляции транзакций serializable (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-команда завершается неудачно из-за ошибок сериализации или дедлока, клиент не прерывается. В таких случаях текущая транзакция откатывается, что также включает установку клиентских переменных такими, какими они были до запуска этой транзакции (предполагается, что в одном транзакционном скрипте содержится только одна транзакция; см. What Is the "Transaction" Actually Performed in 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. Переменная окружения PGOPTIONS задает параметры конфигурации базы данных, которые передаются в PostgreSQL через командную строку (См. Раздел 18.1.4). Например, гипотетический метод доступа к таблице по умолчанию для таблиц, которые создает pgbench, называемый wuzza, можно указать с помощью:

PGOPTIONS='-c default_table_access_method=wuzza'

Хорошие практики

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

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

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

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

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

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

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