Tiago Scolari

bits for fun

Postgres Sequential Scan Alert With Gorm (Golang)

2024-02-18

As part of one side-project I’m currently playing with, I decided to add some tests against table scan to it. It felt like something that could live externally, and why not open to people trying to achieve the same.

This is how I came up with gormalert.

As the name says, this only works with gorm, and the concept is really simple: It creates a plugin that watches for the query types you define, and ran an EXPLAIN version of that query after the query is executed. It then use a very basic string matching to see if that result contains any sequential scan, and if yes, calls a callback function you can define.

For example:

gormalert.RegisterScanAlert(db, gormalert.DefaultAlertOptions(), func(query, explain string) {
    // Tell someone about a sequential scan!
    fmt.Printf("The query %q just did a sequential scan!\n", query)
})

This structure is flexible, and allow different uses for it. But the main motivation for me was to “Fail any tests that execute a table scan”. There’s a easy helper in the package just for that:

gormalert.ExpectDBWithoutSequentialScan(t, db)

When it comes to options, there is a few things that can be set:

type AlertOptions struct {
	Name        string
	Async       bool
	QueryType   []QueryType
	ErrorLogger func(string)
}
  • Name is mostly internal to gorm, a way to identify different plugins.
  • Although for tests we want this to execute synchronously, some other use cases might use Async to run the check and callback in background.
  • QueryType allows narrowing down to which of the gorm’s functions to watch for (Create, Update, Select, Raw, Delete…).
  • ErrorLogger is just a function that allows internal errors of the plugin to be logged out.