grafana / xk6-sql

k6 extension to load test RDBMSs (PostgreSQL, MySQL, MS SQL and SQLite3)
Apache License 2.0
107 stars 57 forks source link

tags on sql.query command #22

Open lharriespipe opened 2 years ago

lharriespipe commented 2 years ago

for http requests we can add paramaters to our requests.

A parameter that we use often are tags to aid creating threshold for various items

response = http.get(data.helloWorld,
    {tags:{name:'helloWorld'}
  });

however for xk6-sql this doesn't appear to be supported meaning it is difficult to put thresholds on different queries being loaded together

imiric commented 2 years ago

Hi there! Thanks for opening this issue.

For this to work, xk6-sql would first have to emit k6 metrics on which tags and thresholds could be applied. Currently the extension doesn't do that, but I can see how it could be useful.

Could you explain your desired use case? I.e. which specific metrics would you like to see?

I imagine basic things like query duration / response time would be useful. It's likely that anything beyond that would be RDBMS-dependent, but we're tied to whatever Golang's database/sql package exposes. Would something from sql.DBStats be interesting?

lharriespipe commented 2 years ago

My main use case would be to apply name tags to different queries to allow for different queries to have different thresholds on query durations. Things like blocking time and connections etc we can get from other tools however I can see those being a useful addition in here too.

imiric commented 2 years ago

I see. If it's only for tracking query durations and applying thresholds, you can sort of implement this yourself already using custom metrics.

Here's an example using Postgres:

import sql from 'k6/x/sql';
import { Trend } from 'k6/metrics';

const db = sql.open('postgres', 'postgres://user:pass@127.0.0.1/postgres?sslmode=disable');

const queryDuration = new Trend('query_duration');

export const options = {
  thresholds: {
    'query_duration{name:my_query}': ['p(95)<200'],
  },
};

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

function timeQuery(query, ...args) {
  const t0 = Date.now();
  const results = sql.query(db, query, ...args)
  const t1 = Date.now();
  return [results, t1-t0];
}

export default function () {
  const [results, elapsed] = timeQuery("SELECT pg_sleep(1);");
  console.log(`query took ${elapsed}ms`);
  queryDuration.add(elapsed, { name: 'my_query' });
}

It's not ideal since tracking time with JS's Date.now() is very imprecise and you'll only get millisecond precision, plus there's some JS<->Go overhead, but it might be sufficient for your use case.

Though, ideally, this kind of basic metric emission should be done by the extension, so I'll create a separate issue for that (see #23). No ETA promises since we currently have very little bandwidth in the team to get this done, but PRs are welcome.