mirror of
https://github.com/binwiederhier/ntfy.git
synced 2026-11-10 22:50:59 +08:00
The replay query of v2.31.0 only read whole topics in the plan Postgres makes without the parameter values, which it switches to after a prepared statement has run five times (pgx prepares statements); with the values, it had found a cheaper plan. The plan tests now check that generic plan. They found the same problem in the tail read (id > cursor OR id = ANY(holes)): its generic plan scans the whole message table through the primary key, 700 ms on 3.3M rows in the lab, on the primary every second. SQLite, which always plans without the values, scanned the whole table for it too. Both are now two parts joined with UNION ALL.
43 lines
1.7 KiB
Go
43 lines
1.7 KiB
Go
package message
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// See TestPostgresQueries_GenericPlansUseOnlyIndexConditions
|
|
func TestSQLiteQueries_SinceIDAndTailUseOnlyIndexConditions(t *testing.T) {
|
|
// SQLite plans without the parameter values, so this is the plan it always uses
|
|
c, err := NewSQLiteStore(filepath.Join(t.TempDir(), "cache.db"), "", 0, 0, 0, false)
|
|
require.Nil(t, err)
|
|
defer c.Close()
|
|
for name, q := range map[string]struct {
|
|
query string
|
|
args []any
|
|
}{
|
|
"since id": {sqliteQueries.selectMessagesSinceID, []any{"mytopic", 1000, 1792160000}},
|
|
"since id, include scheduled": {sqliteQueries.selectMessagesSinceIDScheduled, []any{"mytopic", 1000, 1792160000}},
|
|
"tail": {sqliteQueries.selectMessagesAfterRowID, []any{1000, "[998, 999]", 1000}},
|
|
} {
|
|
rows, err := c.db.Primary().Query("EXPLAIN QUERY PLAN "+q.query, q.args...)
|
|
require.Nil(t, err)
|
|
plan := make([]string, 0)
|
|
for rows.Next() {
|
|
var id, parent, notUsed int
|
|
var detail string
|
|
require.Nil(t, rows.Scan(&id, &parent, ¬Used, &detail))
|
|
plan = append(plan, detail)
|
|
}
|
|
require.Nil(t, rows.Close())
|
|
for _, step := range plan {
|
|
// "(topic=?)" alone reads every row of the topic, and "rowid<?" every row written before the marker
|
|
require.False(t, strings.HasPrefix(step, "SCAN messages"), "%s: full table scan:\n%s", name, strings.Join(plan, "\n"))
|
|
require.False(t, strings.HasSuffix(step, "(topic=?)"), "%s: reads the whole topic:\n%s", name, strings.Join(plan, "\n"))
|
|
require.False(t, strings.HasSuffix(step, "(topic=? AND rowid<?)"), "%s: reads the topic's history:\n%s", name, strings.Join(plan, "\n"))
|
|
}
|
|
}
|
|
}
|