@query-doctor/core 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +126 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +126 -119
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -1926,120 +1926,120 @@ var Statistics = class Statistics {
|
|
|
1926
1926
|
const processedTables = /* @__PURE__ */ new Set();
|
|
1927
1927
|
let columnStatsUpdatePromise;
|
|
1928
1928
|
const columnStatsValues = [];
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
columnStatsValues.push({
|
|
1936
|
-
schema_name: table.schemaName,
|
|
1937
|
-
table_name: table.tableName,
|
|
1938
|
-
column_name: column.columnName,
|
|
1939
|
-
stainherit: false,
|
|
1940
|
-
stanullfrac: .1,
|
|
1941
|
-
stawidth: 20,
|
|
1942
|
-
stadistinct: .1,
|
|
1943
|
-
stakind1: 0,
|
|
1944
|
-
stakind2: 0,
|
|
1945
|
-
stakind3: 0,
|
|
1946
|
-
stakind4: 0,
|
|
1947
|
-
stakind5: 0,
|
|
1948
|
-
stacoll1: "",
|
|
1949
|
-
stacoll2: "",
|
|
1950
|
-
stacoll3: "",
|
|
1951
|
-
stacoll4: "",
|
|
1952
|
-
stacoll5: "",
|
|
1953
|
-
staop1: "",
|
|
1954
|
-
staop2: "",
|
|
1955
|
-
staop3: "",
|
|
1956
|
-
staop4: "",
|
|
1957
|
-
staop5: "",
|
|
1958
|
-
stanumbers1: null,
|
|
1959
|
-
stanumbers2: null,
|
|
1960
|
-
stanumbers3: null,
|
|
1961
|
-
stanumbers4: null,
|
|
1962
|
-
stanumbers5: null,
|
|
1963
|
-
stavalues1: null,
|
|
1964
|
-
stavalues2: null,
|
|
1965
|
-
stavalues3: null,
|
|
1966
|
-
stavalues4: null,
|
|
1967
|
-
stavalues5: null,
|
|
1968
|
-
_value_type1: "real",
|
|
1969
|
-
_value_type2: "real",
|
|
1970
|
-
_value_type3: "real",
|
|
1971
|
-
_value_type4: "real",
|
|
1972
|
-
_value_type5: "real"
|
|
1973
|
-
});
|
|
1974
|
-
continue;
|
|
1975
|
-
}
|
|
1929
|
+
for (const table of this.ownMetadata) {
|
|
1930
|
+
const target = (this.exportedMetadata?.find((m) => m.tableName === table.tableName && m.schemaName === table.schemaName))?.columns ?? table.columns;
|
|
1931
|
+
if (!target) continue;
|
|
1932
|
+
for (const column of target) {
|
|
1933
|
+
const { stats } = column;
|
|
1934
|
+
if (!stats || this.mode.kind === "fromAssumption") {
|
|
1976
1935
|
columnStatsValues.push({
|
|
1977
1936
|
schema_name: table.schemaName,
|
|
1978
1937
|
table_name: table.tableName,
|
|
1979
1938
|
column_name: column.columnName,
|
|
1980
|
-
stainherit:
|
|
1981
|
-
stanullfrac:
|
|
1982
|
-
stawidth: stats
|
|
1983
|
-
stadistinct:
|
|
1984
|
-
stakind1:
|
|
1985
|
-
stakind2:
|
|
1986
|
-
stakind3:
|
|
1987
|
-
stakind4:
|
|
1988
|
-
stakind5:
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
stanumbers1:
|
|
2000
|
-
stanumbers2:
|
|
2001
|
-
stanumbers3:
|
|
2002
|
-
stanumbers4:
|
|
2003
|
-
stanumbers5:
|
|
2004
|
-
stavalues1:
|
|
2005
|
-
stavalues2:
|
|
2006
|
-
stavalues3:
|
|
2007
|
-
stavalues4:
|
|
2008
|
-
stavalues5:
|
|
2009
|
-
_value_type1:
|
|
2010
|
-
_value_type2:
|
|
2011
|
-
_value_type3:
|
|
2012
|
-
_value_type4:
|
|
2013
|
-
_value_type5:
|
|
1939
|
+
stainherit: false,
|
|
1940
|
+
stanullfrac: .04,
|
|
1941
|
+
stawidth: stats?.stawidth ?? 32,
|
|
1942
|
+
stadistinct: -.9,
|
|
1943
|
+
stakind1: 0,
|
|
1944
|
+
stakind2: 0,
|
|
1945
|
+
stakind3: 3,
|
|
1946
|
+
stakind4: 0,
|
|
1947
|
+
stakind5: 0,
|
|
1948
|
+
stacoll1: "0",
|
|
1949
|
+
stacoll2: "0",
|
|
1950
|
+
stacoll3: "0",
|
|
1951
|
+
stacoll4: "0",
|
|
1952
|
+
stacoll5: "0",
|
|
1953
|
+
staop1: "0",
|
|
1954
|
+
staop2: "0",
|
|
1955
|
+
staop3: "0",
|
|
1956
|
+
staop4: "0",
|
|
1957
|
+
staop5: "0",
|
|
1958
|
+
stanumbers1: null,
|
|
1959
|
+
stanumbers2: null,
|
|
1960
|
+
stanumbers3: [.9],
|
|
1961
|
+
stanumbers4: null,
|
|
1962
|
+
stanumbers5: null,
|
|
1963
|
+
stavalues1: null,
|
|
1964
|
+
stavalues2: null,
|
|
1965
|
+
stavalues3: null,
|
|
1966
|
+
stavalues4: null,
|
|
1967
|
+
stavalues5: null,
|
|
1968
|
+
_value_type1: "real",
|
|
1969
|
+
_value_type2: "real",
|
|
1970
|
+
_value_type3: "real",
|
|
1971
|
+
_value_type4: "real",
|
|
1972
|
+
_value_type5: "real"
|
|
2014
1973
|
});
|
|
1974
|
+
continue;
|
|
2015
1975
|
}
|
|
1976
|
+
columnStatsValues.push({
|
|
1977
|
+
schema_name: table.schemaName,
|
|
1978
|
+
table_name: table.tableName,
|
|
1979
|
+
column_name: column.columnName,
|
|
1980
|
+
stainherit: stats.stainherit ?? false,
|
|
1981
|
+
stanullfrac: stats.stanullfrac,
|
|
1982
|
+
stawidth: stats.stawidth,
|
|
1983
|
+
stadistinct: stats.stadistinct,
|
|
1984
|
+
stakind1: stats.stakind1,
|
|
1985
|
+
stakind2: stats.stakind2,
|
|
1986
|
+
stakind3: stats.stakind3,
|
|
1987
|
+
stakind4: stats.stakind4,
|
|
1988
|
+
stakind5: stats.stakind5,
|
|
1989
|
+
staop1: stats.staop1,
|
|
1990
|
+
staop2: stats.staop2,
|
|
1991
|
+
staop3: stats.staop3,
|
|
1992
|
+
staop4: stats.staop4,
|
|
1993
|
+
staop5: stats.staop5,
|
|
1994
|
+
stacoll1: stats.stacoll1,
|
|
1995
|
+
stacoll2: stats.stacoll2,
|
|
1996
|
+
stacoll3: stats.stacoll3,
|
|
1997
|
+
stacoll4: stats.stacoll4,
|
|
1998
|
+
stacoll5: stats.stacoll5,
|
|
1999
|
+
stanumbers1: stats.stanumbers1,
|
|
2000
|
+
stanumbers2: stats.stanumbers2,
|
|
2001
|
+
stanumbers3: stats.stanumbers3,
|
|
2002
|
+
stanumbers4: stats.stanumbers4,
|
|
2003
|
+
stanumbers5: stats.stanumbers5,
|
|
2004
|
+
stavalues1: Statistics.safeStavalues(stats.stavalues1),
|
|
2005
|
+
stavalues2: Statistics.safeStavalues(stats.stavalues2),
|
|
2006
|
+
stavalues3: Statistics.safeStavalues(stats.stavalues3),
|
|
2007
|
+
stavalues4: Statistics.safeStavalues(stats.stavalues4),
|
|
2008
|
+
stavalues5: Statistics.safeStavalues(stats.stavalues5),
|
|
2009
|
+
_value_type1: this.stavalueKind(Statistics.safeStavalues(stats.stavalues1)),
|
|
2010
|
+
_value_type2: this.stavalueKind(Statistics.safeStavalues(stats.stavalues2)),
|
|
2011
|
+
_value_type3: this.stavalueKind(Statistics.safeStavalues(stats.stavalues3)),
|
|
2012
|
+
_value_type4: this.stavalueKind(Statistics.safeStavalues(stats.stavalues4)),
|
|
2013
|
+
_value_type5: this.stavalueKind(Statistics.safeStavalues(stats.stavalues5))
|
|
2014
|
+
});
|
|
2016
2015
|
}
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2016
|
+
}
|
|
2017
|
+
/**
|
|
2018
|
+
* Postgres has 5 different slots for storing statistics per column and a potentially unlimited
|
|
2019
|
+
* number of statistic types to choose from. Each code in `stakindN` can mean different things.
|
|
2020
|
+
* Some statistics are just numerical values such as `n_distinct` and `correlation`, meaning
|
|
2021
|
+
* they're only derived from `stanumbersN` and the value of `stanumbersN` is never read.
|
|
2022
|
+
* Others take advantage of the `stavaluesN` columns which use `anyarray` type to store
|
|
2023
|
+
* concrete values internally for things like histogram bounds.
|
|
2024
|
+
* Unfortunately we cannot change anyarrays without a C extension.
|
|
2025
|
+
*
|
|
2026
|
+
* (1) = most common values
|
|
2027
|
+
* (2) = scalar histogram
|
|
2028
|
+
* (3) = correlation <- can change
|
|
2029
|
+
* (4) = most common elements
|
|
2030
|
+
* (5) = distinct elem count histogram <- can change
|
|
2031
|
+
* (6) = length histogram (?) These don't appear in pg_stats
|
|
2032
|
+
* (7) = bounds histogram (?) These don't appear in pg_stats
|
|
2033
|
+
* (N) = potentially many more kinds of statistics. But postgres <=18 only uses these 7.
|
|
2034
|
+
*
|
|
2035
|
+
* What we're doing here is setting ANY statistic we cannot directly control
|
|
2036
|
+
* (anything that relies on stavaluesN) to 0 to make sure the planner isn't influenced by what
|
|
2037
|
+
* what the db collected from the test data.
|
|
2038
|
+
* Because we do our tests with `generic_plan` it seems it's already unlikely that the planner will be
|
|
2039
|
+
* using things like common values or histogram bounds to make the planning decisions we care about.
|
|
2040
|
+
* This is a just in case.
|
|
2041
|
+
*/
|
|
2042
|
+
const sql = dedent.default`
|
|
2043
2043
|
WITH input AS (
|
|
2044
2044
|
SELECT
|
|
2045
2045
|
c.oid AS starelid,
|
|
@@ -2222,30 +2222,29 @@ var Statistics = class Statistics {
|
|
|
2222
2222
|
returning starelid, staattnum, stainherit, stakind1, stakind2, stakind3, stakind4, stakind5
|
|
2223
2223
|
)
|
|
2224
2224
|
select * from updated union all (select * from inserted); -- @qd_introspection`;
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
}
|
|
2225
|
+
columnStatsUpdatePromise = tx.exec(sql, [columnStatsValues]).catch((err) => {
|
|
2226
|
+
console.error("Something wrong wrong updating column stats");
|
|
2227
|
+
console.error(err);
|
|
2228
|
+
throw err;
|
|
2229
|
+
});
|
|
2231
2230
|
const reltuplesValues = [];
|
|
2232
2231
|
for (const table of this.ownMetadata) {
|
|
2233
|
-
if (!table.columns) continue;
|
|
2234
2232
|
processedTables.add(`${table.schemaName}.${table.tableName}`);
|
|
2235
2233
|
let targetTable;
|
|
2236
2234
|
if (this.exportedMetadata) targetTable = this.exportedMetadata.find((m) => m.tableName === table.tableName && m.schemaName === table.schemaName);
|
|
2235
|
+
else targetTable = table;
|
|
2237
2236
|
let reltuples;
|
|
2238
2237
|
let relpages;
|
|
2239
2238
|
let relallvisible = 0;
|
|
2240
2239
|
let relallfrozen;
|
|
2241
|
-
if (
|
|
2240
|
+
if (this.mode.kind === "fromAssumption") {
|
|
2241
|
+
reltuples = this.mode.reltuples;
|
|
2242
|
+
relpages = this.mode.relpages;
|
|
2243
|
+
} else if (targetTable) {
|
|
2242
2244
|
reltuples = targetTable.reltuples;
|
|
2243
2245
|
relpages = targetTable.relpages;
|
|
2244
2246
|
relallvisible = targetTable.relallvisible;
|
|
2245
2247
|
relallfrozen = targetTable.relallfrozen;
|
|
2246
|
-
} else if (this.mode.kind === "fromAssumption") {
|
|
2247
|
-
reltuples = this.mode.reltuples;
|
|
2248
|
-
relpages = this.mode.relpages;
|
|
2249
2248
|
} else {
|
|
2250
2249
|
warnings.tablesNotInExports.push(`${table.schemaName}.${table.tableName}`);
|
|
2251
2250
|
reltuples = DEFAULT_RELTUPLES;
|
|
@@ -2259,7 +2258,15 @@ var Statistics = class Statistics {
|
|
|
2259
2258
|
relallfrozen,
|
|
2260
2259
|
relallvisible
|
|
2261
2260
|
});
|
|
2262
|
-
if (
|
|
2261
|
+
if (this.mode.kind === "fromAssumption") for (const index of table.indexes) reltuplesValues.push({
|
|
2262
|
+
relname: index.indexName,
|
|
2263
|
+
schema_name: table.schemaName,
|
|
2264
|
+
reltuples: this.mode.reltuples,
|
|
2265
|
+
relpages: Math.ceil(this.mode.relpages * .2),
|
|
2266
|
+
relallfrozen: 0,
|
|
2267
|
+
relallvisible: this.mode.relpages
|
|
2268
|
+
});
|
|
2269
|
+
if (targetTable) for (const index of targetTable.indexes) reltuplesValues.push({
|
|
2263
2270
|
relname: index.indexName,
|
|
2264
2271
|
schema_name: targetTable.schemaName,
|
|
2265
2272
|
reltuples: index.reltuples,
|