pgbench — executa testes de desempenho no PostgreSQL
pgbench -i [opção...] [nome_do_banco_de_dados]
pgbench [opção...] [nome_do_banco_de_dados]
O utilitário pgbench é um programa simples
para executar testes de desempenho
(benchmark) no
PostgreSQL.
Ele executa a mesma sequência de comandos SQL
repetidamente, possivelmente em várias sessões de banco de dados
concorrentes e, em seguida, calcula a taxa média de transação
(transações por segundo).
Por padrão, o pgbench testa um contexto
vagamente baseado no TPC-B,
envolvendo cinco comandos SELECT,
UPDATE e INSERT por transação.
Entretanto, é fácil testar outros casos escrevendo seus próprios
arquivos de script de transação.
A saída típica do pgbench se parece com:
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)
As sete primeiras linhas descrevem algumas das definições de
parâmetros mais importantes.
A sexta linha relata o número máximo de novas tentativas para
transações com erros de serialização ou impasse (veja
Falhas e novas tentativas de serialização/impasse para obter mais informações).
A oitava linha relata o número de transações concluídas e pretendidas
(este último sendo simplesmente o produto do número de clientes pelo
número de transações por cliente); estes dois números serão iguais,
a menos que a execução falhe antes da conclusão, ou que algum(ns)
comando(s) SQL tenha(m) falhado.
(No modo -T é mostrado apenas o número efetivo de
transações.)
A próxima linha relata o número de transações com falha devido a
erros de serialização ou impasse. (veja
Falhas e novas tentativas de serialização/impasse para obter mais informações).
A última linha relata o número de transações por segundo.
O teste de transação padrão do tipo TPC-B requer
que sejam configuradas antecipadamente tabelas específicas.
O utilitário pgbench deve ser chamado com
a opção -i (inicializar) para criar e preencher
estas tabelas.
(Ao testar um script personalizado, esta etapa não é necessária,
mas será preciso fazer as configurações necessárias para o teste.)
A inicialização se parece com:
pgbench -i [outras_opções]nome_do_banco_de_dados
onde nome_do_banco_de_dados é o nome do
banco de dados já criado para o teste.
(Também podem ser necessárias as opções -h,
-p, e/ou -U, para especificar como
se conectar ao servidor de banco de dados.)
A inicialização pgbench -i cria quatro tabelas:
pgbench_accounts,
pgbench_branches,
pgbench_history e
pgbench_tellers,
removendo antes todas as tabelas existentes com estes nomes.
Deve-se tomar o cuidado de usar outro banco de dados se existirem
tabelas com estes nomes!
No “fator de escala” padrão de 1, as tabelas inicialmente contêm esta quantidade de linhas:
SELECT n.nspname AS esquema,
c.relname AS tabela,
c.reltuples AS linhas
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND n.nspname NOT IN ('information_schema','pg_catalog')
AND c.relname LIKE 'pgbench%'
ORDER BY c.relname;
esquema | tabela | linhas ---------+------------------+-------- public | pgbench_accounts | 100000 public | pgbench_branches | 1 public | pgbench_history | 0 public | pgbench_tellers | 10 (4 linhas)
Pode-se (e, para a maioria das finalidades, provavelmente deve-se)
aumentar o número de linhas usando a opção -s
(fator de escala).
A opção -F (fator de preenchimento) também pode ser
usada neste ponto.
Após fazer a configuração necessária, pode-se executar o teste de
desempenho com um comando que não inclua -i, ou seja:
pgbench [opções]nome_do_banco_de_dados
Em quase todos os casos, serão necessárias algumas opções para fazer
um teste útil.
As opções mais importantes são -c (número de clientes),
-t (número de transações), -T
(limite de tempo), e -f
(especifica um arquivo de script personalizado).
Veja abaixo a lista completa.
O que segue está dividido em três subseções. São usadas opções diferentes durante a inicialização do banco de dados e durante a execução dos testes de desempenho, mas algumas opções são úteis nos dois casos.
O utilitário pgbench aceita os seguintes argumentos de inicialização na linha de comando:
[-d] nome_do_banco_de_dados[--dbname=]nome_do_banco_de_dados #
Especifica o nome do banco de dados para realizar os testes.
Se não for especificado, será usada a variável de ambiente
PGDATABASE.
Se esta variável não estiver definida, será usado o nome de
usuário especificado para a conexão.
-i--initialize #Necessário para chamar o modo de inicialização.
-I passos_iniciais--init-steps=passos_iniciais #
Executa apenas o conjunto selecionado de etapas normais de
inicialização.
O valor de init_steps especifica as
etapas de inicialização a serem executadas, usando um dos
caracteres por etapa.
Cada etapa é executada na ordem especificada.
O valor padrão é dtgvp.
As etapas disponíveis são:
d (Remove tabelas) #Remove quaisquer tabelas do pgbench existentes.
t (Cria tabelas) #
Cria as tabelas utilizadas pelo cenário padrão do
pgbench, isto é:
pgbench_accounts,
pgbench_branches,
pgbench_history e
pgbench_tellers.
g ou G (Gera os dados, no lado cliente ou no lado servidor) #Gera os dados e os carrega nas tabelas padrão, substituindo quaisquer dados existentes.
Com a opção g (geração dos dados no lado
cliente), os dados são gerados pelo pgbench
no lado cliente e, em seguida, enviados para o servidor.
Isto usa extensivamente a largura de banda cliente/servidor
por meio de um comando COPY.
No PostgreSQL versão 14 ou
posterior, o pgbench usa a opção
FREEZE para carregar dados em tabelas
comuns (não particionadas) para acelerar a operação
VACUUM subsequente.
O uso da opção g faz com que seja mostrada
uma mensagem a cada 100.000 linhas enquanto são gerados os
dados para todas as tabelas.
Com a opção G (geração dos dados no lado
servidor), são enviadas apenas pequenas consultas pelo
cliente pgbench e os dados são
gerados no servidor.
Não é necessária nenhuma largura de banda significativa para
esta variante, mas o servidor terá mais trabalho.
O uso da opção G impede que sejam
mostradas mensagens de progresso durante a geração dos dados.
O comportamento de inicialização padrão usa a geração dos
dados no lado cliente (equivalente a g).
v (Vacuum/Limpeza) #
Chama o comando VACUUM para as tabelas
padrão.
p (Cria chaves primárias) #Cria índices de chave primária nas tabelas padrão.
f (Cria chaves estrangeiras) #Cria restrições de chave estrangeira entre as tabelas padrão. (Note que esta etapa não é executada por padrão.)
-F fator_de_preenchimento--fillfactor=fator_de_preenchimento #
Cria as tabelas pgbench_accounts,
pgbench_tellers e
pgbench_branches com o fator de
preenchimento especificado.
O valor padrão é 100.
-n--no-vacuum #
Não efetua a limpeza durante a inicialização.
(Esta opção suprime a etapa de inicialização v,
mesmo que tenha sido especificada em -I.)
-q--quiet #Muda o registro para o modo silencioso, produzindo apenas uma mensagem de progresso a cada 5 segundos. O registro padrão mostra uma mensagem a cada 100.000 linhas, que geralmente gera muitas linhas por segundo (especialmente em um hardware potente).
Esta opção não terá efeito se for especificado
G na opção -I.
-s fator_de_escala--scale=fator_de_escala #
Multiplica o número de linhas geradas pelo fator de escala.
Por exemplo, -s 100 irá criar 10.000.000
linhas na tabela pgbench_accounts.
O valor padrão é 1.
Quando o fator de escala for de 20.000, ou maior, as colunas
usadas para conter identificadores de conta
(colunas aid), passarão a usar
números inteiros grandes (bigint), para serem
grandes o suficiente para manter o intervalo de identificadores
de conta.
--foreign-keys #
Cria restrições de chave estrangeira entre as tabelas padrão.
(Esta opção irá adicionar a etapa f à sequência
de etapas de inicialização, se ainda não estiver presente.)
--index-tablespace=espaço_de_tabelas_do_índice #Cria os índices no espaço de tabela especificado, em vez de no espaço de tabela padrão.
--partition-method=NOME #
Crie a tabela pgbench_accounts particionada
com o método NOME.
Os valores esperados são range ou
hash.
Esta opção requer que a opção --partitions seja
definida com um valor diferente de zero.
Se não for especificado, o valor padrão é range.
--partitions=NUM #
Cria a tabela pgbench_accounts particionada
com NUM partições de tamanho quase
igual para o número especificado de contas.
O valor padrão é 0, significando nenhum
particionamento.
--tablespace=espaço_de_tabelas #Cria as tabelas no espaço de tabelas especificado, em vez de no espaço de tabelas padrão.
--unlogged-tables #Cria todas as tabelas como tabelas sem registro de transações (unlogged/temporárias), em vez de tabelas permanentes.
O utilitário pgbench aceita os seguintes argumentos na linha de comando para permitir testes de desempenho em diferentes cenários (benchmarking):
-b nome_do_script[@peso]--builtin=nome_do_script[@peso] #
Adiciona o script integrado especificado à lista de scripts
a serem executados.
Os scripts integrados disponíveis são: tpcb-like
[185],
simple-update e select-only.
São aceitos prefixos sem ambiguidade dos nomes de script integrado.
Com o nome especial list, mostra a lista de
scripts integrados, e termina imediatamente.
Opcionalmente, pode-se escrever um peso inteiro após o
@ para ajustar a probabilidade de selecionar
este script em relação a outros.
O peso padrão é 1.
Veja os detalhes abaixo.
-c clientes--client=clientes #Número de clientes simulados, ou seja, número de sessões de banco de dados concorrentes. O valor padrão é 1.
-C--connect #Estabelece uma nova conexão para cada transação, em vez de apenas uma vez por sessão do cliente. Serve para medir a sobrecarga da conexão.
-D nome_da_variável=valor--define=nome_da_variável=valor #
Define uma variável para uso por um script personalizado
(veja abaixo).
É permitido haver várias opções -D.
-f nome_do_arquivo[@peso]--file=nome_do_arquivo[@peso] #
Adiciona o script de transação
nome_do_arquivo à lista de scripts
a serem executados.
Opcionalmente, pode-se escrever um peso inteiro após o
@ para ajustar a probabilidade de selecionar
este script em relação a outros.
O peso padrão é 1.
(Para usar um nome de arquivo de script que inclua o caractere
@, deve-se anexar um peso para não haver
ambiguidade, por exemplo, filen@me@1.)
Veja os detalhes abaixo.
-j threads--jobs=threads #Número de threads trabalhadoras (processos trabalhadores) no pgbench. O uso de mais de uma thread pode ser útil em máquinas com várias CPUs. Os clientes são distribuídos o mais uniformemente possível entre as threads disponíveis. O valor padrão é 1.
-l--log #Escreve informações sobre cada transação em um arquivo de registro. Veja os detalhes abaixo.
-L limite--latency-limit=limite #
As transações que demoram mais de limite
milissegundos são contadas e relatadas separadamente como
late (atrasada).
Quando é especificada uma taxa (--rate=...),
as transações que ficam atrasadas mais de
limite ms e, portanto, não têm
esperança de atingir o limite de latência, não são enviadas
para o servidor.
Elas são contadas e relatadas separadamente como
skipped.
Quando é usada a opção --max-trys, uma transação
que falha devido a uma anomalia de serialização ou a um impasse
(deadlock) não será tentada
novamente se o tempo total de todas as suas tentativas for
maior que limite ms.
Para limitar apenas o tempo das tentativas e não o seu número,
deve ser usado --max-tries=0.
Por padrão, a opção --max-tries é definida
como 1 e as transações com erros de serialização/impasse não
são repetidas
Veja Falhas e novas tentativas de serialização/impasse para obter mais
informações sobre como tentar novamente estas transações.
-M modo_da_consulta--protocol=modo_da_consulta #Protocolo a ser usado para enviar as consultas ao servidor:
simple:
usa o protocolo de consulta simples.
extended:
usa o protocolo de consulta estendido.
prepared:
usa o protocolo de consulta estendido com instruções
preparadas.
No modo prepared, o utilitário
pgbench reutiliza o resultado
da análise a partir da segunda iteração da consulta,
de modo que o utilitário pgbench
é executado mais rapidamente do que nos outros modos.
O padrão é o protocolo de consulta simples. (Veja Protocolo cliente/servidor para obter mais informações.)
-n--no-vacuum #
Não efetua nenhuma limpeza antes de executar o teste.
Esta opção é necessária se estiver sendo
executado um contexto de teste personalizado que não inclua as
tabelas padrão pgbench_accounts,
pgbench_branches,
pgbench_history e
pgbench_tellers.
-N--skip-some-updates #
Executa o script integrado de atualização simples.
Atalho para -b simple-update.
-P sec--progress=sec #
Mostra o relatório de progresso a cada
sec segundos.
O relatório inclui o tempo decorrido desde o início da execução,
o TPS desde o último relatório, a latência
média da transação, o desvio padrão e o número de transações
com falha desde o último relatório.
Com a limitação de taxa (-R), a latência é
calculada em relação ao horário de início agendado da transação,
e não ao horário real de início da transação; portanto,
ela também inclui o tempo médio de atraso do agendamento.
Quando é usada a opção --max-tries para ativar
novas tentativas de transação após erros de serialização/impasse,
o relatório inclui o número de transações repetidas e a soma de
todas as novas tentativas.
-r--report-per-command #
Relata as seguintes estatísticas para cada comando após a
conclusão do teste de desempenho:
a latência média por instrução
(tempo de execução da perspectiva do cliente),
o número de falhas e o número de novas tentativas após erros
de serialização ou de impasse neste comando.
O relatório irá mostrar estatísticas de novas tentativas somente
se a opção --max-trys for diferente de 1.
-R razão--rate=razão #Executa as transações visando a taxa especificada, em vez de executar o mais rápido possível (o padrão). A taxa é dada em transações por segundo. Se a taxa especificada estiver acima da taxa máxima possível, o limite imposto pela taxa não afetará os resultados.
A taxa é definida iniciando as transações ao longo de uma linha do tempo escalonada segundo uma distribuição de Poisson. A programação de hora de início esperada avança com base em quando o cliente foi iniciado pela primeira vez, e não em quando a transação anterior foi encerrada. Esta abordagem significa que, se uma transação exceder sua hora de término programada, ainda será possível recuperar o atraso nas próximas transações.
Quando a taxa está ativa, a latência da transação informada no final da execução é calculada a partir das horas de início programadas, ou seja, inclui o tempo que cada transação teve que esperar até que a transação anterior fosse concluída. O tempo de espera é chamado de tempo de atraso do agendamento, e seus valores médio e máximo também são informados separadamente. A latência da transação em relação à hora real de início da transação, ou seja, o tempo gasto na execução da transação no banco de dados, pode ser calculada subtraindo o tempo de atraso do agendamento da latência informada.
Se a opção --latency-limit for usada com a opção
--rate, uma transação pode ficar tão atrasada
que já estaria acima do limite de latência quando a transação
anterior terminar, porque a latência é calculada a partir da
hora de início agendada.
Estas transações não são enviadas ao servidor, sendo totalmente
ignoradas e contadas separadamente.
Um tempo de atraso alto em relação ao agendado, é uma indicação de que o sistema não pode processar transações na taxa especificada, com o número escolhido de clientes e de processos. Quando o tempo médio de execução da transação for maior do que o intervalo esperado entre cada transação, cada transação sucessiva ficará mais para trás, e o tempo de atraso da programação continuará aumentando quanto mais longa for a execução do teste. Quando isto acontecer, será necessário reduzir a taxa de transação especificada.
-s fator_de_escala--scale=fator_de_escala #
Relata o fator de escala especificado na saída do utilitário
pgbench.
Com os testes integrados, isto não é necessário;
o fator de escala correto será detectado contando o número
de linhas na tabela pgbench_branches.
Entretanto, ao realizar apenas testes personalizados
(opção -f), o fator de escala será relatado
como 1, a menos que esta opção seja usada.
-S--select-only #
Executa somente o script de seleção integrado.
Atalho para -b select-only.
-t transações--transactions=transações #Número de transações que cada cliente executa. O valor padrão é 10.
-T segundos--time=segundos #
Executa o teste por esta quantidade de segundos, em vez de pelo
número fixado de transações por cliente.
As opções -t e
-T são mutuamente exclusivas.
-v--vacuum-all #
Limpa todas as quatro tabelas padrão antes de executar o teste.
Sem -n nem -v, o utilitário
pgbench irá limpar as tabelas
pgbench_tellers e
pgbench_branches,
e irá truncar a tabela pgbench_history.
--aggregate-interval=segundos #
Duração do intervalo de agregação (em segundos).
Pode ser usado apenas com a opção -l.
Com esta opção, o registro (log)
conterá dados resumidos por intervalo, conforme descrito abaixo.
--exit-on-abort #
Sair imediatamente quando qualquer cliente for encerrado devido
a algum erro.
Sem esta opção, mesmo quando um cliente é encerrado, outros
clientes poderiam continuar sua execução conforme especificado
pela opção -t ou -T e,
neste caso, pgbench iria mostrar
resultados incompletos.
Note que falhas de serialização ou impasses não interrompem o cliente, portanto, não são afetados por esta opção. Veja Falhas e novas tentativas de serialização/impasse para obter mais informações.
--failures-detailed #Relata falhas nos registros por transação e agregação, bem como nos relatórios principais e por script, agrupadas pelos seguintes tipos:
falhas de serialização;
falhas de impasse;
Veja Falhas e novas tentativas de serialização/impasse para obter mais informações.
--log-prefix=prefix #
Define o prefixo do nome de arquivo para os arquivos de registro
criados pela opção --log.
O valor padrão é pgbench_log.
--max-tries=número_de_tentativas #
Ativa novas tentativas para transações com erros de
serialização/impasse e define o número máximo dessas tentativas.
Esta opção pode ser combinada com a opção
--latency-limit que limita o tempo total
de todas as tentativas de transação;
além disso, não se pode usar um número ilimitado de tentativas
(--max-tries=0) sem
--latency-limit ou --time.
O valor padrão é 1 e as transações com erros de
serialização/impasse não são repetidas.
Veja Falhas e novas tentativas de serialização/impasse para obter mais
informações sobre como tentar repetir novamente estas transações.
--progress-timestamp #
Ao mostrar o progresso (opção -P), usa um
carimbo de data/hora
(Unix time),
em vez do número de segundos desde o início da execução.
A unidade é em segundos, com precisão de milissegundos após o ponto.
Isto ajuda a comparar registros gerados por várias ferramentas.
--random-seed=semente #
Define a semente que inicia o gerador de números aleatórios
do sistema, que produzirá uma sequência de estados geradores
iniciais, um para cada processo (thread).
Os valores para a semente podem ser:
time (o padrão, a semente é baseada na hora
corrente), rand (usa uma fonte fortemente
aleatória, falhando se nenhuma estiver disponível),
ou um valor inteiro decimal sem sinal.
O gerador aleatório é chamado explicitamente de um script
pgbench (funções random...),
ou implicitamente (por exemplo, a opção --rate
usa para agendar transações).
Quando é definido explicitamente, o valor usado para semente
é mostrado no terminal.
Qualquer valor permitido para semente
também pode ser fornecido por meio da variável de ambiente
PGBENCH_RANDOM_SEED.
Para garantir que a semente fornecida impacte todos os usos
possíveis, deve-se colocar esta opção primeiro, ou usar a
variável de ambiente.
Definir a semente explicitamente permite reproduzir uma execução
do utilitário pgbench exatamente idêntica,
no que diz respeito a números aleatórios.
Como o estado do gerador de números aleatórios é gerenciado por
processo (thread), o
pgbench será executado de forma idêntica,
se houver um cliente por processo, e não houver dependências
externas ou de dados.
Do ponto de vista estatístico, a reprodução exata das execuções
é uma má ideia, porque pode mascarar a variabilidade do desempenho,
ou melhorar o desempenho indevidamente, por exemplo, acessando
as mesmas páginas de uma execução anterior.
Entretanto, também pode ser de grande ajuda para depuração,
por exemplo, reexecutando um caso complicado que leva a um erro.
Deve ser usado com sabedoria.
--sampling-rate=razão #Taxa de amostragem, usada ao escrever dados no registro (log), para reduzir a quantidade de registro gerada. Se esta opção for fornecida, apenas a fração especificada de transações será registrada. 1.0 significa que todas as transações serão registradas, 0.05 significa que apenas 5% das transações serão registradas.
Deve-se lembrar levar em consideração a taxa de amostragem ao processar o arquivo de registro. Por exemplo, ao calcular valores de TPS, é necessário multiplicar os números de acordo (por exemplo, com uma taxa de amostragem de 0.01, será obtido apenas 1/100 do TPS real).
--show-script=nome_do_script #
Escreve o código real do script integrado
nome_do_script na saída de erro
padrão (stderr), e termina imediatamente.
--verbose-errors #Mostra mensagens sobre todos os erros e falhas (erros sem novas tentativas), incluindo qual limite de novas tentativas foi excedido e em que medida este limite foi excedido para as falhas de serialização/impasse. (Note que, neste caso, a saída poderá ser significativamente aumentada.) Veja Falhas e novas tentativas de serialização/impasse para obter mais informações.
O utilitário pgbench também aceita os seguintes argumentos de linha de comando comuns para parâmetros de conexão:
--debug #Mostra saída de depuração.
-h nome_do_hospedeiro--host=nome_do_hospedeiro #O nome do hospedeiro do servidor de banco de dados
-p porta--port=porta #O número da porta do servidor de banco de dados
-U usuário--username=usuário #O nome de usuário para se conectar como
-V--version #Mostra a versão do utilitário pgbench, e termina.
-?--help #Mostra a ajuda sobre os argumentos da linha de comando do pgbench, e termina.
Uma execução bem-sucedida resultará no código de saída 0.
O código de saída 1 indica problemas estáticos, como opções de
linha de comando inválidas ou erros internos que não deveriam ocorrer.
Erros iniciais que ocorrem ao iniciar o teste de desempenho, como
falhas de conexão iniciais, também são encerrados com o código 1.
Erros durante a execução, como erros de banco de dados ou problemas
no script, resultarão no código de saída 2. Neste último caso,
o pgbench irá relatar resultados parciais
se não for especificada a opção --exit-on-abort.
PGDATABASEPGHOSTPGPORTPGUSERParâmetros de conexão padrão.
Este utilitário, como a maioria dos outros utilitários do PostgreSQL, também usa as variáveis de ambiente com suporte pela libpq (veja Variáveis de ambiente).
A variável de ambiente PG_COLOR
especifica se devem ser usadas cores nas mensagens de diagnóstico.
Os valores possíveis são always,
auto e never.
O utilitário pgbench executa scripts de
teste escolhidos aleatoriamente de uma lista especificada.
Os scripts podem incluir scripts integrados especificados com
a opção -b, e scripts fornecidos pelo usuário
especificados coma opção -f.
Cada script pode receber um peso relativo especificado após o
@ para alterar sua probabilidade de seleção.
O peso padrão é 1.
Os scripts com peso 0 são ignorados.
O script de transação integrado padrão
(também chamados com a opção -b tpcb-like)
executa sete comandos por transação escolhidos aleatoriamente entre
aid, tid,
bid, e delta.
O contexto é inspirado no teste de desempenho TPC-B,
mas como, na verdade, não é o TPC-B,
daí vem seu nome.
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;
Se for selecionado o script integrado simple-update
(também a opção -N), as etapas 4 e 5 não serão
incluídas na transação.
Isto evita a contenção de atualização nessas tabelas, mas torna o
caso de teste ainda menos parecido com o TPC-B.
Se for selecionado o script integrado select-only
(também a opção -S), será executado apenas o
SELECT.
O utilitário pgbench oferece suporte para
a execução de contexto de testes de desempenho personalizados,
substituindo o script de transação padrão (descrito acima) por um
script de transação lido de um arquivo (opção -f).
Neste caso, uma “transação” conta como a execução de um
arquivo de script.
O arquivo de script contém um ou mais comandos SQL
terminados por ponto e vírgula.
As linhas vazias, e as linhas começando com --,
são ignoradas.
Arquivos de script também podem conter “metacomandos”,
interpretados pelo próprio utilitário
pgbench, conforme descrito abaixo.
Antes do PostgreSQL 9.6, os comandos SQL em arquivos de script eram finalizados pelo caractere de nova-linha e, portanto, não podiam ser continuados entre as linhas. Agora é necessário o ponto e vírgula para separar comandos SQL consecutivos (embora o comando SQL não precise dele, se for seguido por um metacomando). Se for necessário criar um arquivo de script que funcione com as versões antiga e nova do utilitário pgbench, certifique-se de escrever cada comando SQL em uma única linha terminando com ponto e vírgula.
É assumido que os scripts do pgbench não contêm blocos incompletos de transações SQL. Se, durante a execução, o cliente chegar ao final do script sem concluir o último bloco de transação, a operação será cancelada.
Existe um recurso simples de substituição de variável para arquivos
de script.
Os nomes das variáveis devem consistir em letras (incluindo letras
não latinas), dígitos e sublinhados, com o primeiro caractere não
sendo um dígito.
As variáveis podem ser definidas pela opção -D da
linha de comando, explicada acima, ou pelos metacomandos explicados
abaixo.
Além de quaisquer variáveis predefinidas pelas opções de linha de
comando -D, existem algumas variáveis
predefinidas automaticamente, listadas na
Tabela 301.
Um valor especificado para estas variáveis usando a opção
-D tem precedência sobre as predefinições automáticas.
Uma vez definido, o valor de uma variável pode ser inserido em um
comando SQL escrevendo
:nome_da_variável.
Ao executar mais de uma sessão cliente, cada sessão possui seu
próprio conjunto de variáveis.
O utilitário pgbench oferece suporte
a até 255 usos de variáveis em uma instrução.
Tabela 301. Variáveis automáticas do pgbench
| Variável | Descrição |
|---|---|
client_id | número único que identifica a sessão do cliente (começa em zero) |
default_seed | semente usada por padrão em funções de permutação hash e pseudo-aleatória |
random_seed | semente do gerador de números aleatórios (a menos que
seja sobreposto pela opção -D) |
scale | fator de escala corrente |
Os metacomandos do arquivo de script começam com uma contrabarra
(\), e normalmente se estendem até o final da
linha, embora possam ser continuados em linhas adicionais
escrevendo contrabarra-retorno.
Os argumentos para o metacomando são separados por espaços em branco.
Os seguintes metacomandos têm suporte:
\gset [prefix]
\aset [prefix]
#
Estes comandos podem ser usados para finalizar instruções
SQL, substituindo o ponto e vírgula
(;) final.
Quando é usado o metacomando \gset, espera-se
que a instrução SQL anterior retorne uma linha,
cujas colunas serão armazenadas nas variáveis indicadas após os
nomes das colunas, e prefixadas com o
prefixo, se fornecido.
Quando é usado o metacomando \aset, todas as
instruções SQL combinadas
(separadas por \;) têm suas colunas armazenadas
nas variáveis indicadas após os nomes das colunas, e prefixadas
com o prefixo, se fornecido.
Se a instrução não retornar nenhuma linha, nenhuma atribuição
será feita, e a variável poderá ser testada quanto à existência
para detectar isto.
Se a instrução retornar mais de uma linha, será mantido o último
valor.
Os metacomandos \gset e \aset
não podem ser usados no modo encadeado (|), porque
os resultados da instrução ainda não estarão disponíveis no momento
em que os comandos vão precisar deles.
O exemplo a seguir coloca o saldo final da conta da primeira
instrução na variável abalance,
e preenche as variáveis p_two e
p_three com valores inteiros da
terceira instrução.
O resultado da segunda instrução é descartado.
O resultado combinado das duas últimas instruções são armazenados
nas variáveis four e
five.
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid RETURNING abalance \gset -- composto de duas consultas SELECT 1 \; SELECT 2 AS two, 3 AS three \gset p_ SELECT 4 AS four \; SELECT 5 AS five \aset
\if expressão\elif expressão\else\endif #
Este grupo de comandos implementa blocos condicionais aninhados,
similares ao \if expressão do
psql.
As expressões condicionais são idênticas àquelas com
\set, com valores diferentes de zero
interpretados como verdade.
\set nome_da_variável expressão
#
Define a variável nome_da_variável para
o valor calculado a partir de expressão.
A expressão pode conter a constante NULL,
constantes booleanas TRUE e FALSE,
constantes inteiras como 5432,
constantes de precisão dupla como 3.14159,
referências a variáveis
:nome_da_variável,
operadores
com sua precedência e associatividade SQL usuais,
chamadas de função,
expressões condicionais genéricas SQL
CASE, e parênteses.
As funções, e a maioria dos operadores, retornam
NULL na entrada NULL.
Para fins de condição, os valores numéricos diferentes de zero são
TRUE, os valores numéricos zero e
NULL são FALSE.
Constantes inteiras e de dupla precisão muito grandes ou muito
pequenas, bem como operadores aritméticos inteiros
(+, -, *
e /), geram erros de estouro
(overflow).
Quando não é fornecida nenhuma cláusula final ELSE
para o CASE, o valor padrão é NULL.
Exemplos:
\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 número [ us | ms | s ]
#
Faz com que a execução do script seja suspensa pela duração
especificada em microssegundos (us),
milissegundos (ms),
ou segundos (s).
Se for omitida a unidade, por padrão será segundos.
O número pode ser uma constante inteira,
ou uma referência
:nome_da_variável
a uma variável com um valor inteiro.
Exemplo:
\sleep 10 ms
\setshell nome_da_variável comando [ argumento ... ]
#
Define a variável nome_da_variável como
o resultado do comando do interpretador
de comandos, com o(s) argumento(s)
fornecido(s).
O comando deve retornar um valor inteiro por meio da saída padrão.
O comando e cada
argumento pode ser uma constante de
texto, ou uma referência
:nome_da_variável
a uma variável.
Se for desejado usar um argumento
começando com dois pontos, deve-se escrever dois pontos
adicionais no início do argumento.
Exemplo:
\setshell variável_a_ser_atribuída comando argumento_literal :variável ↵
::literal_começando_com_dois_pontos
\shell comando [ argumento ... ]
#
O mesmo que \setshell, mas o resultado do
comando é descartado.
Exemplo:
\shell comando argumento_literal :variável ::literal_começando_com_dois_pontos
\startpipeline\syncpipeline\endpipeline #
Este grupo de comandos implementa um fluxo
(pipeline) de instruções
SQL.
O fluxo deve começar com \startpipeline
e terminar com \endpipeline.
Entre elas pode haver qualquer número de comandos
\syncpipeline que enviam uma
mensagem de sincronização
sem encerrar o fluxo de dados em andamento e descarregando
o buffer de envio.
No modo de fluxo, as instruções são enviadas ao servidor
sem esperar pelos resultados das instruções anteriores.
Veja Pipeline Mode para obter mais
informações.
O modo fluxo requer o uso de um protocolo de consulta estendido.
Os operadores aritméticos, bit a bit, de comparação, e lógicos,
listados na Tabela 302, são integrados ao
utilitário pgbench, podendo ser usados
nas expressões que aparecem em
\set
.
Os operadores são listados na ordem crescente de precedência.
Exceto onde indicado, os operadores que usam duas entradas
numéricas produzirão um resultado de precisão dupla se uma das
entradas for de precisão dupla, caso contrário, produzirão um
resultado inteiro.
nome_da_variável expressão
Tabela 302. Operadores do pgbench
Operador Descrição Exemplo(s) |
|---|
OU lógico
|
E lógico
|
NÃO lógico
|
Testes de valor booleano
|
Testes de valor nulo
|
Igual
|
Não igual
|
Não igual
|
Menor que
|
Menor que, ou igual a
|
Maior que
|
Maior que, ou igual a
|
OU bit a bit
|
OU exclusivo (XOR) bit a bit
|
E bit a bit
|
NÃO bit a bit
|
Deslocamento bit a bit para a esquerda
|
Deslocamento bit a bit para a direita
|
Adição
|
Subtração
|
Multiplicação
|
Divisão (trunca o resultado em direção a zero se as duas entradas forem números inteiros)
|
Módulo (resto)
|
Negação
|
As funções listadas na Tabela 303
são integradas ao pgbench, podendo ser usadas
em expressões que aparecem em
\set
.
nome_da_variável expressão
Tabela 303. Funções de pgbench
Função Descrição Exemplo(s) |
|---|
Valor absoluto
|
Escreve o argumento na saída de erro padrão (stderr), e retorna o argumento.
|
Converte para precisão dupla
|
Exponencial (
|
Seleciona o maior valor entre os argumentos.
|
Esta função é um alias para a função
|
Computa FNV-1a hash.
|
Computa MurmurHash2 hash.
|
Converte em inteiro.
|
Seleciona o menor valor entre os argumentos.
|
Logaritmo natural
|
Módulo (resto)
|
Valor permutado de
|
Valor aproximado de π;
|
|
Computa um número inteiro aleatório uniformemente distribuído
no intervalo
|
Computa um número inteiro aleatório distribuído exponencialmente
no intervalo
|
Computa um número inteiro aleatório numa distribuição Gaussiana
no intervalo
|
Calcula um número inteiro aleatório distribuído segundo a
Lei de Zipf
no intervalo
|
Raiz quadrada
|
A função random gera valores usando uma
distribuição uniforme, ou seja, todos os valores são distribuídos
dentro do intervalo especificado com igual probabilidade.
As funções random_exponential,
random_gaussian e random_zipfian
requerem um parâmetro adicional de precisão dupla, que determina
a forma precisa da distribuição.
Para uma distribuição exponencial, o
parâmetro controla a distribuição,
truncando uma distribuição exponencial decrescente rapidamente
no parâmetro e, em seguida, fazendo a
projeção dos resultados em números inteiros entre os limites.
Para ser preciso, usando
f(x) = exp(-parâmetro * (x - min) / (max - min + 1)) / (1 - exp(-parâmetro))
Então o valor i, entre
min e max
inclusive, é recuperado com a probabilidade:
f(i) - f(i + 1).
Intuitivamente, quanto maior for o parâmetro,
serão acessados com maior frequência os valores próximos a
min, e serão acessados menor
frequência os valores próximos a max.
Quanto mais próximo de zero estiver o parâmetro,
mais plana (mais uniforme) será a distribuição de acesso.
Uma aproximação grosseira da distribuição é que 1% dos valores
mais frequentes no intervalo, próximos a min,
são selecionados parâmetro% das vezes.
O valor do parâmetro deve ser
estritamente positivo.
Para uma distribuição Gaussiana, o intervalo corresponde a uma
distribuição normal padrão (a curva Gaussiana clássica em forma
de sino), truncada em -parâmetro à esquerda,
e +parâmetro à direita.
Valores no meio do intervalo têm maior probabilidade de serem
selecionados.
Para ser preciso, se PHI(x) for a função de
distribuição cumulativa da distribuição normal padrão, com a média
mu definida como
(max + min) / 2,0, com
f(x) = PHI(2.0 * parâmetro * (x - mu) / (max - min + 1)) /
(2.0 * PHI(parâmetro) - 1)
então o valor i, entre
min e max
inclusive, é selecionado com probabilidade:
f(i + 0.5) - f(i - 0.5).
Intuitivamente, quanto maior for o parâmetro,
mais frequentemente serão selecionados valores próximos ao meio do
intervalo, e menos frequentemente os valores próximos aos limites
min e max.
Cerca de 67% dos valores serão selecionados a partir do centro
1.0 / parâmetro, ou seja,
0,5 / parâmetro em torno da média,
e 95% no centro 2.0 / parâmetro, ou
1.0 / parâmetro em torno da média;
por exemplo, se parâmetro for 4.0,
67% dos valores serão selecionados do quarto do meio (1,0 / 4,0)
do intervalo (ou seja, de 3.0 / 8.0 a
5.0 / 8.0), e 95% da metade intermediária
(2.0 / 4.0) do intervalo
(segundo e terceiro quartis).
O valor mínimo permitido para o parâmetro
é 2.0.
A função random_zipfian gera uma distribuição
com limites segundo a lei de Zipf.
O parâmetro define o quão distorcida
é a distribuição.
Quanto maior for o parâmetro, mais
frequentemente serão escolhidos os valores mais próximos do
início do intervalo
A distribuição é tal que, assumindo que o intervalo comece em 1,
a razão da probabilidade de selecionar k
contra selecionar k+1 é
((.
Por exemplo, k+1)/k)**parâmetrorandom_zipfian(1, ..., 2.5)
produz o valor 1 cerca de
(2/1)**2.5 = 5.66 vezes mais frequentemente
do que 2, que é produzido
(3/2)**2.5 = 2.76 vezes mais frequentemente
do que 3, e assim por diante.
A implementação do pgbench é baseada em
“Non-Uniform Random Variate Generation”,
Luc Devroye, p. 550-551, Springer 1986.
Devido às limitações desse algoritmo, o valor do
parâmetro está restrito ao intervalo
[1.001, 1000].
Ao projetar um teste de desempenho que seleciona linhas de maneira não uniforme, deve-se estar ciente de que as linhas selecionadas podem estar correlacionadas com outros dados, como identificadores de sequência, ou a ordem física da linha, o que pode distorcer as medições de desempenho.
Para evitar esta situação, pode-se desejar usar a função
permute, ou alguma outra etapa adicional
com efeito semelhante, para embaralhar as linhas selecionadas,
e remover estas correlações.
As funções de hash:
hash, hash_murmur2 e
hash_fnv1a, aceitam um valor de entrada e um
parâmetro de semente opcional.
Caso a semente não seja fornecida, é usado o valor de
:default_seed, que é inicializado aleatoriamente,
a menos que seja definido pela opção -D da
linha de comando.
A função permute aceita um valor de entrada,
um tamanho e um parâmetro de semente opcional.
Ela gera uma permutação pseudo-aleatória de inteiros no intervalo
[0, tamanho), e retorna o índice do valor de
entrada nos valores permutados.
A permutação escolhida é parametrizada pela semente, cujo valor
padrão é :default_seed, se não for especificado.
Ao contrário das funções de hash,
a função permute garante que não haja colisões
ou buracos nos valores de saída.
Valores de entrada fora do intervalo são interpretados módulo
o tamanho.
A função gera um erro se o tamanho não for positivo.
A função permute pode ser usada para dispersar
a distribuição de funções aleatórias não uniformes, como
random_zipfian ou random_exponential,
para que os valores selecionados com mais frequência não estejam
trivialmente correlacionados.
Por exemplo, o script para o pgbench
a seguir simula uma possível carga de trabalho do mundo real,
típica para mídias sociais e plataformas de blog, onde algumas
contas geram carga excessiva:
\set size 1000000 \set r random_zipfian(1, :size, 1.07) \set k 1 + permute(:r, :size)
Em alguns casos, são necessárias várias distribuições distintas que não se correlacionam entre si, e é aí que o parâmetro semente opcional é útil:
\set k1 1 + permute(:r, :size, :default_seed + 123) \set k2 1 + permute(:r, :size, :default_seed + 321)
Um comportamento semelhante também pode ser aproximado com a função
hash:
\set size 1000000 \set r random_zipfian(1, 100 * :size, 1.07) \set k 1 + abs(hash(:r)) % :size
Entretanto, como a função hash gera colisões,
alguns valores não serão alcançáveis, e outros serão mais
frequentes do que o esperado na distribuição original.
Como exemplo, a definição completa da transação integrada do tipo 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;
Este script permite que cada iteração da transação faça referência a diferentes linhas escolhidas aleatoriamente. (Este exemplo também mostra por que é importante que cada sessão cliente tenha suas próprias variáveis — caso contrário, elas não estariam tocando linhas diferentes de forma independente.)
Com a opção -l (mas sem a opção
--aggregate-interval), o utilitário
pgbench escreve informações sobre cada
transação em um arquivo de registro (log).
O arquivo de registro terá o nome
,
onde prefixo.nnnprefixo, por padrão, é
pgbench_log, e nnn é o
PID do processo pgbench.
O prefixo pode ser alterado usando a opção --log-prefix.
Se a opção -j for igual a 2, ou superior, de modo
que haja vários processos trabalhadores
(threads), cada um terá seu próprio
arquivo de registro.
O primeiro processo trabalhador usará o mesmo nome para seu arquivo
de registro, como no processo único padrão.
Os arquivos de registro adicionais para os demais processos
trabalhadores terão os nomes
,
onde prefixo.nnn.mmmmmm é um número sequencial para cada
processo trabalhador começando com 1.
Cada linha em um arquivo de registro descreve uma transação. Ela contém os seguintes campos separados por espaços:
client_ididentifica a sessão do cliente que executou a transação
transaction_noconta quantas transações foram executadas por esta sessão
timetempo decorrido da transação, em microssegundos
script_no
identifica o arquivo de script usado para a transação
(útil quando vários scripts são especificados com
-f ou -b)
time_epochtempo de conclusão da transação, em formato de carimbo de data e hora Unix-epoch
time_usfração de segundo do tempo de conclusão da transação, em microssegundos
schedule_lag
o atraso no início da transação, que é a diferença entre a hora
de início da transação programada e a hora em que ela realmente
começou, em microssegundos
(presente somente se for especificado --rate)
retries
contagem de novas tentativas após erros de serialização ou de
impasse durante a transação
(presente apenas se --max-trys for diferente de um.)
Quando são usadas as duas opções --rate e
--latency-limit,
o tempo para uma transação ignorada será
relatado como skipped.
Se a transação terminar com falha, seu tempo
será relatado como failed.
Se for usada a opção --failures-detailed,
o tempo da transação que falhou será relatado
como serialization ou deadlock
dependendo do tipo de falha
(veja Falhas e novas tentativas de serialização/impasse para obter mais informações).
A seguir está um trecho de um arquivo de registro gerado em uma execução de um único cliente:
0 199 2241 0 1175850568 995598 0 200 2465 0 1175850568 998079 0 201 2513 0 1175850569 608 0 202 2038 0 1175850569 2663
Outro exemplo com --rate=100
e --latency-limit=5
(note a coluna adicional 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
Neste exemplo, a transação 82 estava atrasada, porque sua latência (6,173 ms) estava acima do limite de 5 ms. As duas transações seguintes foram ignoradas, porque já estavam atrasadas antes mesmo de serem iniciadas.
O exemplo a seguir mostra um trecho de um arquivo de registro com
falhas e novas tentativas, com o número máximo de novas tentativas
definido como 10.
(note a coluna adicional 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
Se for usada a opção --failures-detailed, o tipo de
falha será relatado no time desta forma:
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
Ao executar um teste longo em hardware
capaz de lidar com muitas transações, os arquivos de registro podem
ficar muito grandes.
Pode ser usada a opção --sampling-rate para
registrar apenas uma amostra aleatória de transações.
Com a opção --aggregate-interval, é usado um
formato diferente para os arquivos de registro.
Cada linha do registro descreve um intervalo de agregação.
O registro contém os seguintes campos separados por espaços:
interval_starthora de início do intervalo, no formato de carimbo de data e hora Unix-epoch
num_transactionsnúmero de transações dentro do intervalo
sum_latencysoma das latências de transação
sum_latency_2soma dos quadrados das latências de transação
min_latencylatência mínima de transação
max_latencylatência máxima de transação
sum_lag
soma dos atrasos de início das transações
(zero, a menos que seja especificado --rate)
sum_lag_2
soma dos quadrados dos atrasos de início das transações
(zero, a menos que seja especificado --rate)
min_lag
atraso mínimo de início de transação
(zero, a menos que seja especificado --rate)
max_lag
atraso máximo de início de transação
(zero, a menos que seja especificado --rate)
skipped
número de transações ignoradas, porque teriam começado muito tarde.
(zero, a menos que seja especificado --rate
e --latency-limit)
retried
número de transações tentadas novamente
(zero, a menos que --max-tries não seja igual a 1)
retries
número de novas tentativas após erros de serialização ou impasse
(zero, a menos que --max-tries não seja igual a 1)
serialization_failures
número de transações que apresentaram erro de serialização
e não foram tentadas novamente posteriormente
(zero, a menos que seja especificados --failures-detailed)
deadlock_failures
número de transações que apresentaram erro de impasse
e não foram tentadas novamente posteriormente
(zero, a menos que seja especificados --failures-detailed)
A seguir está um exemplo de saída gerada com esta opção:
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
Note que, enquanto o formato de registro simples (não agregado) mostra qual script foi usado para cada transação, o formato agregado não o faz. Portanto, se houver necessidade de obter dados por script, será necessário agregar os dados por conta própria.
Com a opção -r, o pgbench
coleta as seguintes estatísticas para cada instrução:
latency — tempo decorrido da transação
para cada instrução.
o pgbench relata o valor médio de
todas as execuções bem-sucedidas da instrução.
O número de falhas nesta instrução. Veja Falhas e novas tentativas de serialização/impasse para obter mais informações.
O número de novas tentativas após um erro de serialização ou de impasse nesta instrução. Veja Falhas e novas tentativas de serialização/impasse para obter mais informações.
O relatório irá mostrar as estatísticas de novas tentativas somente
se a opção --max-trys for diferente de 1.
Todos os valores são calculados para cada instrução executada por cada cliente e são relatados após a conclusão do teste de desempenho.
Para o script padrão, a saída será semelhante a esta:
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;
Outro exemplo de saída para o script padrão usando o nível de
isolamento de transação padrão serializável (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;
Se forem especificados vários arquivos de script, todas as estatísticas serão relatadas separadamente para cada arquivo de script.
Note que a coleta das informações adicionais de tempo necessárias para o cálculo da latência por instrução adiciona alguma sobrecarga. Isto reduzirá a velocidade média de execução e diminuirá o TPS calculado. O grau de lentidão varia significativamente dependendo da plataforma e do hardware. Comparar os valores médios de TPS com e sem o relatório de latência ativado é uma boa maneira de medir se a sobrecarga de tempo é significativa.
Ao executar o utilitário pgbench existem três tipos principais de erros:
Erros do programa principal. Estes são os mais graves e sempre resultam em uma saída imediata do pgbench com a mensagem de erro correspondente. Estão incluídos:
erros no início de pgbench (por exemplo, um valor de opção inválido);
erros no modo de inicialização (por exemplo, a consulta para criar tabelas nos scripts integrados falha);
erros antes de iniciar os processos (por exemplo, não foi possível conectar ao servidor de banco de dados, erro de sintaxe no comando meta, falha na criação de processo);
erros internos do pgbench (que supostamente nunca deveriam ocorrer...).
Erros ocorrem quando o processo gerencia seus clientes.
(por exemplo, o cliente não conseguiu iniciar uma conexão com
o servidor de banco de dados / o soquete para conectar o
cliente ao servidor de banco de dados tornou-se inválido).
Nesses casos, todos os clientes desse processo param de
funcionar, enquanto os outros processos continuam a operar.
Entretanto, se for especificada a opção
--exit-on-abort, todos os processos serão
interrompidos imediatamente neste caso.
Erros diretos do cliente.
Estes erros levam à saída imediata do utilitário
pgbech com a mensagem de erro
correspondente no caso de um erro interno do
pgbench
(que supostamente nunca deveriam ocorrer...) ou quando é
especificado --exit-on-abort.
Caso contrário, na pior das hipóteses, levam apenas à
interrupção do cliente que falhou, enquanto os outros clientes
continuam sua execução.
(mas alguns erros do cliente são tratados sem a interrupção
do cliente e relatados separadamente, veja abaixo.).
Mais adiante nesta seção, assume-se que os erros discutidos são
apenas erros diretos do cliente e não erros internos do
pgbench.
A execução de um cliente é interrompida em caso de erro grave;
por exemplo, a conexão com o servidor de banco de dados foi perdida
ou o script chegou ao fim sem que a última transação fosse concluída.
Além disso, se a execução de um comando SQL ou
meta comando falhar por motivos que não sejam erros de serialização
ou impasse, o cliente será encerrado.
Caso contrário, se um comando SQL falhar com erros
de serialização ou impasse, o cliente não será interrompido.
Nesses casos, a transação corrente é desfeita, o que também inclui
redefinir as variáveis do cliente para seus valores anteriores
à execução dessa transação
(se presume que um script de transação contenha apenas uma transação;
veja Qual é a "transação" realmente executada no pgbench? para obter mais
informações).
As transações com erros de serialização ou impasse são tentadas
novamente após serem desfeitas, até serem concluídas com sucesso ou
atingirem o número máximo de novas tentativas (especificado pela
opção --max-tries) / o tempo máximo de novas
tentativas (especificado pela opção --latency-limit)
/ o fim do tempo (especificado pela opção --time).
Se a última tentativa falhar, esta transação será relatada como
falhada, mas o cliente não será encerrado e continuará funcionando.
Se não for especificada a opção --max-tries,
uma transação nunca será tentada novamente após um erro de
serialização ou de impasse, porque seu valor padrão é 1.
Deve ser usado um número ilimitado de tentativas
(--max-tries=0) juntamente com a opção
--latency-limit para limitar apenas o tempo
máximo de tentativas.
Também pode ser usada a opção --time para limitar a
duração do teste de desempenho sob um número ilimitado de tentativas.
Tenha cuidado ao repetir scripts que contenham várias transações: o script é sempre tentado novamente integralmente, fazendo com que transações bem-sucedidas sejam executadas diversas vezes.
Tenha cuidado ao repetir transações com comandos do interpretador
de comandos (shell).
Ao contrário dos resultados dos comandos SQL,
os resultados dos comandos do interpretador de comandos não são
revertidos, exceto pelo valor da variável do comando
\setshell.
A latência de uma transação bem-sucedida inclui todo o tempo de execução da transação, incluindo reversões e novas tentativas. A latência é medida apenas para transações e comandos bem-sucedidos, e não para transações ou comandos com falha.
O relatório principal contém o número de transações com falha.
Se a opção --max-tries não for igual a 1,
o relatório principal também conterá estatísticas relacionadas
a novas tentativas: o número total de transações tentadas novamente
e o número total de novas tentativas.
O relatório por script herda estes campos do relatório principal.
O relatório por instrução irá mostrar estatísticas de novas tentativas
somente se a opção --max-trys for diferente de 1.
Se for desejado agrupar as falhas por tipos básicos em registros por
transação e agregação, bem como nos relatórios principais e por script,
deve ser usada a opção --failures-detailed.
Se também for desejado distinguir todos os erros e falhas
(erros sem nova tentativa) por tipo, incluindo qual limite de novas
tentativas foi excedido e em quanto foi excedido para as falhas de
serialização/impasse, deve ser usada a opção
--verbose-errors.
Pode ser especificado o
Método de acesso à tabela para as
tabelas do pgbench.
A variável de ambiente PGOPTIONS especifica as opções
de configuração do banco de dados passadas para o
PostgreSQL através da linha de comando.
(Veja Interação com parâmetros via linha de comando).
Por exemplo, um hipotético método de acesso à tabela padrão para as
tabelas que o pgbench cria, chamado
wuzza, pode ser especificado usando:
PGOPTIONS='-c default_table_access_method=wuzza'
É muito fácil usar o utilitário pgbench para produzir números inteiramente sem sentido. Aqui estão algumas diretrizes para auxiliar na obtenção de resultados úteis.
Em primeiro lugar, nunca se deve acreditar em
qualquer teste que dure apenas alguns segundos.
Deve ser usada a opção -t ou -T para
fazer a execução durar pelo menos alguns minutos, de modo a reduzir
o ruído.
Em alguns casos, podem ser necessárias horas para obter números
reproduzíveis.
É uma boa ideia fazer o teste algumas vezes, para descobrir se os
números são reprodutíveis ou não.
Para o cenário de teste padrão do tipo TPC-B,
o fator de escala de inicialização (-s) deve ser
pelo menos tão grande quanto o número máximo de clientes que se
pretende testar (-c); caso contrário, se estará
medindo principalmente a contenção induzida por atualizações.
Como existem apenas -s linhas na tabela
pgbench_branches, e cada transação deseja
atualizar uma dessas linhas, então se o valor de -c
for maior que o valor de -s certamente resultará
em muitas transações bloqueadas aguardando a conclusão de outras
transações.
O contexto de teste padrão também é bastante sensível a quanto tempo se passou desde que as tabelas foram inicializadas: o acúmulo de linhas mortas e espaço morto nas tabelas altera os resultados. Para entender os resultados, deve-se acompanhar o número total de atualizações e quando ocorre a limpeza. Se o autovacuum estiver ativado, pode resultar em alterações imprevisíveis no desempenho medido.
Uma limitação do pgbench é que ele pode se tornar um gargalo ao tentar testar muitas sessões clientes. Isto pode ser aliviado executando pgbench em uma máquina diferente do servidor de banco de dados, embora uma baixa latência de rede seja essencial. Pode até ser útil executar várias instâncias do pgbench concorrentemente em várias máquinas cliente, no mesmo servidor de banco de dados.
Se usuários não confiáveis tiverem acesso a um banco de dados que não adotou um padrão de uso de esquema seguro, não se deve executar o pgbench neste banco de dados. O utilitário pgbench usa nomes não qualificados, e não trata o caminho de procura.