Como testar a performance de queries em banco de dados usando K6.

Published: (February 1, 2026 at 12:57 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

Pré‑requisitos 📑

Conhecendo o módulo xk6-sql 🧠

O xk6-sql é uma extensão oficial do k6 que permite executar consultas SQL diretamente em testes de performance. Com ele, é possível conectar‑se a diferentes bancos de dados relacionais (MySQL, PostgreSQL, SQL Server, SQLite, entre outros) e realizar operações como:

  • Criação de tabelas
  • Inserção de dados
  • Consultas durante os ciclos de teste de performance

Para utilizá‑lo, é necessário importar o módulo k6/x/sql junto com o driver correspondente ao banco de dados escolhido, por exemplo: xk6-sql-driver-postgres. Após a importação, você pode:

  1. Abrir uma conexão com o banco de dados;
  2. Executar comandos SQL na fase de configuração (setup);
  3. Manipular dados das entidades na fase de execução;
  4. Fechar a conexão na fase de desmontagem (teardown).

Aplicação utilizada 🛝

Padrinho – uma aplicação de discovery de vagas que possui rotas públicas onde os usuários acessam detalhes de cada oportunidade diretamente pelo frontend. Mesmo com cache ativado nessas rotas, a consulta de detalhes envolve junções entre várias entidades e representa cerca de 60 % a 65 % de todas as requisições processadas pela aplicação.

Detalhes da aplicação Padrinho

Além de garantir a consistência das informações retornadas, também precisávamos lidar com a disponibilidade da nossa única instância de PostgreSQL no Supabase, especialmente durante períodos de maior tráfego (first visit), quando uma vaga é consultada pela primeira vez e ainda não existe no cache.

Configurando nosso script 👷🏻‍♀️

Imports

import sql from "k6/x/sql";
import postgres from "k6/x/sql/driver/postgres";
import { SharedArray } from "k6/data";
import { check } from "k6";
import { QUERY_DETALHE_VAGA } from "./query.js";

Nota: A partir da versão 1.2.1 do k6, foi introduzida a feature Automatic extension resolution. Não é mais necessário criar um binário customizado para módulos xk6 ou módulos que não façam parte do core do k6, bastando que a flag K6_ENABLE_COMMUNITY_EXTENSIONS esteja configurada como true. Exemplo de log:

INFO[0000] Automatic extension resolution is enabled. The current k6 binary doesn't satisfy all dependencies, it's required to provision a custom binary.  deps="k6/x/faker*"
INFO[0000] A new k6 binary has been provisioned with version(s): k6:v1.4.2 k6/x/faker:v0.4.4

Opções do teste

export const options = {
    vus: 10,
    iterations: 100,
    duration: "5s",
};

Estamos definindo que 100 iterações serão realizadas em máximo 5 s, utilizando 10 VUs.

Adicionando threshold

export const options = {
    vus: 5,
    iterations: 100,
    duration: "5s",
    thresholds: {
        iteration_duration: [
            "p(90) **Importante:** Nunca defina valores sensíveis diretamente no código."
        ]
    }
};

Conexão com o banco (setup)

export function setup() {
    if (!host || !port || !dbname || !user || !password) {
        throw new Error(
            "Variáveis DB_HOST, DB_PORT, DB_NAME, DB_USER e DB_PASSWORD são obrigatórias."
        );
    }

    const connectionString = `postgres://${user}:${password}@${host}:${port}/${dbname}?sslmode=${ssl}`;
    const db = sql.open(postgres, connectionString);

    return db;
}

Etapa 2 – Definindo as massas de consulta

Na segunda etapa, será definido as massas que serão utilizadas para consulta na nossa base de dados. Utilizaremos alguns IDs de consultas, definidos em um arquivo .json, sendo necessário sua leitura em uma estrutura de SharedArray:

const nanoIds = new SharedArray("nano_ids", () => {
  return JSON.parse(open("./nanoids.json"));
});

Etapa 3 – Execução da consulta

Com as massas definidas e a conexão com o banco de dados aberta, podemos definir nossa consulta na fase de execução. O propósito é distribuir os IDs carregados no SharedArray entre todas as VUs planejadas durante o tempo de execução, realizar uma consulta ao banco e confirmar que foram retornados dados da consulta. Como não definiremos um atraso nas configurações, as VUs vão realizar quantas requisições conseguirem no intervalo de tempo configurado.

export default function (db) {
  const nanoId = nanoIds[Math.floor(Math.random() * nanoIds.length)];

  const result = db.query(QUERY_DETALHE_VAGA, nanoId);

  check(result, {
    "consulta executada": (rows) => rows.length >= 0,
  });
}

Etapa 4 – Desmontagem

Pós‑execução, na fase de desmontagem, finalizaremos fechando nossa conexão com o banco de dados:

export function teardown(db) {
  db.close();
}

Resultados do script 🧑‍🔬

No resultado de saída pós‑execução, teremos os principais indicadores das iterações, incluindo avg, min, med, max e os percentis p(90) e p(95).

█ THRESHOLDS
  iteration_duration
  ✗ 'p(90) *Nosso experimento foi conduzido em execução única utilizando um banco de dados gratuito da ferramenta **Supabase**.*

Conclusão ❤️

A performance de queries no banco de dados é um fator crítico que impacta diretamente a experiência do usuário e a escalabilidade das aplicações.

Como demonstrado neste artigo, com o uso do xk6-sql foi possível identificar gargalos de performance em consultas SQL de forma isolada, estabelecer baselines claros e monitorar a degradação ao longo do tempo.

Integrar testes de performance de banco de dados ao seu ciclo de desenvolvimento não apenas previne problemas em produção, mas também fornece métricas objetivas para priorizar otimizações e validar melhorias antes que impactem os usuários finais.

Gostou do conteúdo e quer saber mais sobre testes de performance com K6?
Confira meu curso na Udemy:

Teste de performance com K6

Back to Blog

Related posts

Read more »