Skip to content

Commit

Permalink
sql/stats: fix inject/restore of partial stats not creating merged stats
Browse files Browse the repository at this point in the history
Previously, JSON statistics would not include the statistic ID. This
meant that restoring statement bundles would recreate stats with new
IDs, breaking the statisticID/fullStatisticID relationship between full
& partial stats and fail to recreate merged stats as a result. This
commit adds the statistic ID to JSONStatistic and recreates stats with
the same ID if present when injected. Allows for merged stats to be
correctly recreated following inject/restore of full and partial stats.

Fixes: cockroachdb#94101

See also: cockroachdb#125950

Release note (bug fix): Fixed a bug that prevented merged stats from
being created after injecting stats or recreating statement bundles.
This would occur when the injected stats/statement bundle contained
related full and partial statistics.
  • Loading branch information
Uzair5162 committed Jul 16, 2024
1 parent 1d7cc7f commit 4ece712
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 89 deletions.
71 changes: 53 additions & 18 deletions pkg/sql/alter_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -1587,11 +1587,45 @@ func insertJSONStatistic(
fullStatisticIDValue = s.FullStatisticID
}

_ /* rows */, err := txn.Exec(
ctx,
"insert-stats",
txn.KV(),
`INSERT INTO system.table_statistics (
if s.ID != 0 {
_ /* rows */, err := txn.Exec(
ctx,
"insert-stats",
txn.KV(),
`INSERT INTO system.table_statistics (
"statisticID",
"tableID",
"name",
"columnIDs",
"createdAt",
"rowCount",
"distinctCount",
"nullCount",
"avgSize",
histogram,
"partialPredicate",
"fullStatisticID"
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`,
s.ID,
tableID,
name,
columnIDs,
s.CreatedAt,
s.RowCount,
s.DistinctCount,
s.NullCount,
s.AvgSize,
histogram,
predicateValue,
fullStatisticIDValue,
)
return err
} else {
_ /* rows */, err := txn.Exec(
ctx,
"insert-stats",
txn.KV(),
`INSERT INTO system.table_statistics (
"tableID",
"name",
"columnIDs",
Expand All @@ -1604,19 +1638,20 @@ func insertJSONStatistic(
"partialPredicate",
"fullStatisticID"
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`,
tableID,
name,
columnIDs,
s.CreatedAt,
s.RowCount,
s.DistinctCount,
s.NullCount,
s.AvgSize,
histogram,
predicateValue,
fullStatisticIDValue,
)
return err
tableID,
name,
columnIDs,
s.CreatedAt,
s.RowCount,
s.DistinctCount,
s.NullCount,
s.AvgSize,
histogram,
predicateValue,
fullStatisticIDValue,
)
return err
}
}

// validateConstraintNameIsNotUsed checks that the name of the constraint we're
Expand Down
47 changes: 42 additions & 5 deletions pkg/sql/logictest/testdata/logic_test/distsql_stats
Original file line number Diff line number Diff line change
Expand Up @@ -1631,7 +1631,9 @@ statement ok
CREATE STATISTICS s FROM all_null

query T
SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
SELECT jsonb_pretty(
regexp_replace(COALESCE(json_agg(stat), '[]')::STRING, '"id": [0-9]+', '"id": 0', 'g')::JSONB
)
FROM (
SELECT json_array_elements(statistics) - 'created_at' AS stat
FROM [SHOW STATISTICS USING JSON FOR TABLE all_null]
Expand All @@ -1654,6 +1656,7 @@ FROM [SHOW STATISTICS USING JSON FOR TABLE all_null]
],
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"name": "s",
"null_count": 0,
"row_count": 1
Expand All @@ -1666,6 +1669,7 @@ FROM [SHOW STATISTICS USING JSON FOR TABLE all_null]
"distinct_count": 1,
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"name": "s",
"null_count": 1,
"row_count": 1
Expand All @@ -1689,7 +1693,9 @@ statement ok
CREATE STATISTICS s FROM greeting_stats

query T
SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
SELECT jsonb_pretty(
regexp_replace(COALESCE(json_agg(stat), '[]')::STRING, '"id": [0-9]+', '"id": 0', 'g')::JSONB
)
FROM (
SELECT json_array_elements(statistics) - 'created_at' AS stat
FROM [SHOW STATISTICS USING JSON FOR TABLE greeting_stats]
Expand All @@ -1712,6 +1718,7 @@ FROM [SHOW STATISTICS USING JSON FOR TABLE greeting_stats]
],
"histo_col_type": "test.public.greeting",
"histo_version": 3,
"id": 0,
"name": "s",
"null_count": 0,
"row_count": 1
Expand Down Expand Up @@ -1877,7 +1884,9 @@ SHOW HISTOGRAM $hist_id_1
upper_bound range_rows distinct_range_rows equal_rows

query T
SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
SELECT jsonb_pretty(
regexp_replace(COALESCE(json_agg(stat), '[]')::STRING, '"id": [0-9]+', '"id": 0', 'g')::JSONB
)
FROM (SELECT json_array_elements(statistics) - 'created_at' AS stat
FROM [SHOW STATISTICS USING JSON FOR TABLE tabula])
----
Expand All @@ -1890,6 +1899,7 @@ SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
"distinct_count": 0,
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"name": "aristotle",
"null_count": 0,
"row_count": 0
Expand All @@ -1902,6 +1912,7 @@ SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
"distinct_count": 0,
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"name": "aristotle",
"null_count": 0,
"row_count": 0
Expand All @@ -1914,6 +1925,7 @@ SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
],
"distinct_count": 0,
"histo_col_type": "",
"id": 0,
"name": "aristotle",
"null_count": 0,
"row_count": 0
Expand All @@ -1926,6 +1938,7 @@ SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
"distinct_count": 0,
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"name": "aristotle",
"null_count": 0,
"row_count": 0
Expand Down Expand Up @@ -1973,7 +1986,9 @@ SHOW HISTOGRAM $hist_id_1
upper_bound range_rows distinct_range_rows equal_rows

query T
SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
SELECT jsonb_pretty(
regexp_replace(COALESCE(json_agg(stat), '[]')::STRING, '"id": [0-9]+', '"id": 0', 'g')::JSONB
)
FROM (SELECT json_array_elements(statistics) - 'created_at' - 'avg_size' AS stat
FROM [SHOW STATISTICS USING JSON FOR TABLE tabula])
----
Expand All @@ -1993,6 +2008,7 @@ SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
],
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"name": "locke",
"null_count": 0,
"row_count": 1
Expand All @@ -2012,6 +2028,7 @@ SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
],
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"name": "locke",
"null_count": 0,
"row_count": 1
Expand All @@ -2023,6 +2040,7 @@ SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
],
"distinct_count": 1,
"histo_col_type": "",
"id": 0,
"name": "locke",
"null_count": 0,
"row_count": 1
Expand All @@ -2034,6 +2052,7 @@ SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
"distinct_count": 1,
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"name": "locke",
"null_count": 1,
"row_count": 1
Expand Down Expand Up @@ -2081,7 +2100,9 @@ NULL {rowid} 0 0 0 true
t1_ab {a,b} 0 0 0 false

query T
SELECT jsonb_pretty(COALESCE(json_agg(stat), '[]'))
SELECT jsonb_pretty(
regexp_replace(COALESCE(json_agg(stat), '[]')::STRING, '"id": [0-9]+', '"id": 0', 'g')::JSONB
)
FROM (
SELECT json_array_elements(statistics) - 'created_at' AS stat
FROM [SHOW STATISTICS USING JSON FOR TABLE t1]
Expand All @@ -2096,6 +2117,7 @@ FROM [SHOW STATISTICS USING JSON FOR TABLE t1]
"distinct_count": 0,
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"null_count": 0,
"row_count": 0
},
Expand All @@ -2107,6 +2129,7 @@ FROM [SHOW STATISTICS USING JSON FOR TABLE t1]
"distinct_count": 0,
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"null_count": 0,
"row_count": 0
},
Expand All @@ -2118,6 +2141,7 @@ FROM [SHOW STATISTICS USING JSON FOR TABLE t1]
"distinct_count": 0,
"histo_col_type": "INT8",
"histo_version": 3,
"id": 0,
"null_count": 0,
"row_count": 0
},
Expand All @@ -2129,6 +2153,7 @@ FROM [SHOW STATISTICS USING JSON FOR TABLE t1]
],
"distinct_count": 0,
"histo_col_type": "",
"id": 0,
"name": "t1_ab",
"null_count": 0,
"row_count": 0
Expand Down Expand Up @@ -2363,6 +2388,18 @@ statistics_name partial_predicate row_count n
xy_x_partial (x IS NULL) OR ((x < 0:::INT8) OR (x > 3:::INT8)) 4 0
xy_x_partial_2 (x IS NULL) OR ((x < 0:::INT8) OR (x > 3:::INT8)) 4 0

query T
SELECT jsonb_pretty(stat->'name')
FROM (
SELECT jsonb_array_elements(statistics) AS stat
FROM [SHOW STATISTICS USING JSON FOR TABLE xy]
)
WHERE stat->>'full_statistic_id' = '$statistics_id'
ORDER BY stat->>'name';
----
"xy_x_partial"
"xy_x_partial_2"

# Test null values.
statement ok
CREATE TABLE a_null (a INT, INDEX (a));
Expand Down
Loading

0 comments on commit 4ece712

Please sign in to comment.