如何使用 K6 测试数据库查询的性能

发布: (2026年2月2日 GMT+8 01:57)
6 分钟阅读
原文: Dev.to

抱歉,我需要您提供要翻译的具体文本内容(除 > Source: … 之外的部分),才能为您完成简体中文翻译。请把文章的正文粘贴过来,我会保持原有的 Markdown 格式、代码块和链接不变,只翻译文字部分。

先决条件 📑

了解 xk6-sql 模块 🧠

xk6-sql 是 k6 的官方扩展,允许在性能测试中直接执行 SQL 查询。使用它,可以连接到不同的关系型数据库(MySQL、PostgreSQL、SQL Server、SQLite 等),并执行以下操作:

  • 创建表
  • 插入数据
  • 在性能测试周期中执行查询

要使用它,需要导入 k6/x/sql 模块以及对应数据库的驱动,例如:xk6-sql-driver-postgres。导入后,你可以:

  1. 打开与数据库的连接;
  2. 在配置阶段(setup)执行 SQL 命令;
  3. 在执行阶段处理实体数据;
  4. 在拆卸阶段(teardown)关闭连接。

使用的应用 🛝

Padrinho – 一个职位发现应用,拥有公共路由,用户可以直接通过前端访问每个机会的详细信息。即使在这些路由上启用了缓存,详细查询仍涉及多个实体的连接,约占应用处理的所有请求的 60 % 到 65 %

Padrinho 应用详情

除了确保返回信息的一致性外,我们还需要处理 Supabase 上唯一的 PostgreSQL 实例的可用性,尤其是在流量高峰期(首次访问)时,当职位被首次查询且缓存中尚不存在时。

配置我们的脚本 👷🏻‍♀️

导入

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: 从 k6 1.2.1 版本开始,引入了 Automatic extension resolution 功能。不再需要为 xk6 模块或不属于 k6 核心的模块创建自定义二进制,只需将标志 K6_ENABLE_COMMUNITY_EXTENSIONS 设置为 true。日志示例:

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

测试选项

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

我们定义 100 次迭代将在 最多 5 秒内完成,使用 10 个 VUs

添加阈值

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

与数据库的连接(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;
}

第2步 – 定义查询批次

在第二步中,将定义用于查询我们数据库的批次。我们将使用一些在 .json 文件中定义的查询 ID,需要将其读取到 SharedArray 结构中:

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

第三步 – 执行查询

在已定义好数据集并打开数据库连接后,我们可以在执行阶段定义查询。其目的是将加载到 SharedArray 中的 ID 分配给所有计划在运行期间使用的 VU,向数据库发起查询,并确认查询返回了数据。由于我们在配置中没有设置延迟,VUs 将在配置的时间间隔内尽可能多地发送请求。

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,
  });
}

第四阶段 – 拆卸

后执行阶段,在拆卸阶段,我们将关闭与数据库的连接:

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

脚本结果 🧑‍🔬

在后执行的输出结果中,我们将获得迭代的主要指标,包括 avgminmedmax 以及百分位 p(90)p(95)

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

结论 ❤️

数据库查询的性能是一个关键因素,直接影响用户体验和应用的可扩展性。

正如本文所示,使用 xk6-sql 能够在单独的 SQL 查询中识别性能瓶颈,建立明确的基准线,并随时间监控性能下降。

将数据库性能测试集成到开发周期中,不仅可以防止生产环境的问题,还能提供客观的指标,以便在影响最终用户之前优先进行优化并验证改进。

喜欢本内容并想了解更多关于 K6 性能测试的内容吗?
查看我在 Udemy 的课程:

Teste de performance com K6

Back to Blog

相关文章

阅读更多 »