Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@libpg-query/parser": "^17.6.3",
"@opentelemetry/api": "^1.9.0",
"@pgsql/types": "^17.6.2",
"@query-doctor/core": "^0.7.2",
"@query-doctor/core": "^0.8.0",
"async-sema": "^3.1.1",
"dedent": "^1.7.1",
"fast-csv": "^5.0.5",
Expand Down
41 changes: 22 additions & 19 deletions src/remote/gin-indexes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ test("GIN: basic @> containment recommends GIN with jsonb_path_ops", async () =>
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "data", stats: null },
{ columnName: "id", stats: null, attlen: 8 },
{ columnName: "data", stats: null, attlen: null },
],
indexes: [],
}],
Expand Down Expand Up @@ -171,8 +171,8 @@ test("GIN: key existence (?) recommends GIN with default jsonb_ops", async () =>
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "payload", stats: null },
{ columnName: "id", stats: null, attlen: 8 },
{ columnName: "payload", stats: null, attlen: null },
],
indexes: [],
}],
Expand Down Expand Up @@ -258,8 +258,8 @@ test("GIN: any-key existence (?|) recommends GIN with default jsonb_ops", async
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "payload", stats: null },
{ columnName: "id", stats: null, attlen: 8 },
{ columnName: "payload", stats: null, attlen: null },
],
indexes: [],
}],
Expand Down Expand Up @@ -342,8 +342,8 @@ test("GIN: all-keys existence (?&) recommends GIN with default jsonb_ops", async
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "payload", stats: null },
{ columnName: "id", stats: null, attlen: 8 },
{ columnName: "payload", stats: null, attlen: null },
],
indexes: [],
}],
Expand Down Expand Up @@ -428,9 +428,9 @@ test("GIN: mixed JSONB and regular column produces both GIN and B-tree", async (
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "data", stats: null },
{ columnName: "price", stats: null },
{ columnName: "id", stats: null, attlen: 8 },
{ columnName: "data", stats: null, attlen: null },
{ columnName: "price", stats: null, attlen: 8 },
],
indexes: [],
}],
Expand Down Expand Up @@ -536,8 +536,8 @@ test("GIN: mixed @> and ? on same column escalates to jsonb_ops", async () => {
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "data", stats: null },
{ columnName: "id", stats: null, attlen: 8 },
{ columnName: "data", stats: null, attlen: null },
],
indexes: [],
}],
Expand Down Expand Up @@ -626,8 +626,8 @@ test("GIN: table alias resolves to correct table for GIN recommendation", async
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "data", stats: null },
{ columnName: "id", stats: null, attlen: 8 },
{ columnName: "data", stats: null, attlen: null },
],
indexes: [],
}],
Expand Down Expand Up @@ -710,8 +710,8 @@ test("GIN: non-JSONB query produces B-tree only, no GIN", async () => {
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "name", stats: null },
{ columnName: "id", stats: null, attlen: 8 },
{ columnName: "name", stats: null, attlen: 20 },
],
indexes: [],
}],
Expand Down Expand Up @@ -802,14 +802,17 @@ test("GIN: existing GIN index prevents duplicate recommendation", async () => {
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "data", stats: null },
{ columnName: "id", stats: null, attlen: 8 },
{ columnName: "data", stats: null, attlen: null },
],
indexes: [{
indexName: "idx_products_data",
relpages: 50,
reltuples: 100_000,
relallvisible: 1,
amname: "gin",
columns: [{ attlen: null }],
fillfactor: 0.9
}],
}],
});
Expand Down
48 changes: 33 additions & 15 deletions src/remote/query-optimizer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,22 @@ test("controller syncs correctly", async () => {
columns: [{
columnName: "a",
stats: null,
attlen: null,
}, {
columnName: "b",
stats: null,
attlen: null,
}],
indexes: [{
indexName: "testing_index",
relpages: 2,
reltuples: 10000,
relallvisible: 1,
amname: "btree",
columns: [{
attlen: 8
}],
fillfactor: 0.9,
}],
}],
});
Expand Down Expand Up @@ -157,15 +164,20 @@ test("controller syncs correctly", async () => {
columns: [{
columnName: "a",
stats: null,
attlen: 8,
}, {
columnName: "b",
stats: null,
attlen: 8,
}],
indexes: [{
indexName: "testing_index",
relpages: 2,
reltuples: 10000,
relallvisible: 1,
amname: "btree",
columns: [{ attlen: 8 }],
fillfactor: 0.9,
}],
}],
});
Expand Down Expand Up @@ -223,14 +235,17 @@ test("disabling an index removes it from indexesUsed and recommends it", async (
reltuples: 10_000_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "email", stats: null },
{ columnName: "id", stats: null, attlen: null },
{ columnName: "email", stats: null, attlen: null },
],
indexes: [{
indexName: "users_email_idx",
relpages: 100,
reltuples: 10_000_000,
relallvisible: 1,
amname: "btree",
fillfactor: 0.9,
columns: [{ attlen: null }],
}],
}],
};
Expand Down Expand Up @@ -392,11 +407,11 @@ test("hypertable optimization includes index recommendations", async () => {
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "time", stats: null },
{ columnName: "sensor_id", stats: null },
{ columnName: "aqi", stats: null },
{ columnName: "pm25_ugm3", stats: null },
{ columnName: "pm10_ugm3", stats: null },
{ columnName: "time", stats: null, attlen: null },
{ columnName: "sensor_id", stats: null, attlen: null },
{ columnName: "aqi", stats: null, attlen: null },
{ columnName: "pm25_ugm3", stats: null, attlen: null },
{ columnName: "pm10_ugm3", stats: null, attlen: null },
],
indexes: [],
},
Expand All @@ -407,9 +422,9 @@ test("hypertable optimization includes index recommendations", async () => {
reltuples: 100,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "name", stats: null },
{ columnName: "location_type", stats: null },
{ columnName: "id", stats: null, attlen: null },
{ columnName: "name", stats: null, attlen: null },
{ columnName: "location_type", stats: null, attlen: null },
],
indexes: [],
},
Expand Down Expand Up @@ -490,8 +505,8 @@ test("timed out queries are retried with exponential backoff up to maxRetries",
reltuples: 1_000_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "data", stats: null },
{ columnName: "id", stats: null, attlen: null },
{ columnName: "data", stats: null, attlen: null },
],
indexes: [],
}],
Expand Down Expand Up @@ -577,15 +592,18 @@ test("optimizer does not treat ASC index as duplicate of DESC candidate", async
reltuples: 100_000,
relallvisible: 1,
columns: [
{ columnName: "id", stats: null },
{ columnName: "created_at", stats: null },
{ columnName: "status", stats: null },
{ columnName: "id", stats: null, attlen: null },
{ columnName: "created_at", stats: null, attlen: null },
{ columnName: "status", stats: null, attlen: null },
],
indexes: [{
indexName: "orders_multi_asc",
relpages: 50,
reltuples: 100_000,
relallvisible: 1,
amname: "btree",
fillfactor: 0.9,
columns: [{ attlen: null }, { attlen: null }],
}],
}],
});
Expand Down
1 change: 0 additions & 1 deletion src/remote/query-optimizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export class QueryOptimizer extends EventEmitter<EventMap> {
private static readonly MAX_CONCURRENCY = 1;
private static readonly defaultStatistics: StatisticsMode = {
kind: "fromAssumption",
relpages: 1,
reltuples: 10_000,
};
private readonly queries = new Map<QueryHash, OptimizedQuery>();
Expand Down
2 changes: 1 addition & 1 deletion src/reporters/github/github.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ function makeRecommendation(overrides: {

function makeContext(overrides: Partial<ReportContext> = {}): ReportContext {
return {
statisticsMode: { kind: "fromAssumption", reltuples: 10000, relpages: 1000 },
statisticsMode: { kind: "fromAssumption", reltuples: 10000 },
recommendations: [],
queriesPastThreshold: [],
queryStats: { total: 28, matched: 10, optimized: 2, errored: 0 },
Expand Down
3 changes: 1 addition & 2 deletions src/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { ConnectionManager } from "./sync/connection-manager.ts";
import { RecentQuery } from "./sql/recent-query.ts";
import { QueryHash } from "./sql/recent-query.ts";
import type { OptimizedQuery } from "./sql/recent-query.ts";
import { ExportedStats, StatisticsMode } from "@query-doctor/core";
import { ExportedStats } from "@query-doctor/core";
import { readFile } from "node:fs/promises";

export class Runner {
Expand Down Expand Up @@ -80,7 +80,6 @@ export class Runner {
stats: {
kind: "fromAssumption",
reltuples: 10_000_000,
relpages: 200_000
}
}
}
Expand Down
Loading