Skip to content

Commit 4ab26a2

Browse files
committed
catalog: add mz_object_hydration_history
Adds the durable table that hydration episodes are recorded into. Nothing writes it yet, the collector arrives separately. The table is in `mz_internal` because its contents are best effort and its `status` column will gain values as more hydration events become observable. An episode is identified by `(object_id, replica_id, installed_at)`, using the replica-stamped installation time because it is stable across an environmentd restart. That identity is not declared as a key on the relation: the collector's anti-join is what keeps it unique, and telling the optimizer a best-effort sampler's output is unique would turn any duplicate into a silently wrong query result. None of the comparable history tables declare one either. No index. An arrangement on the catalog server would hold the whole table, which grows with objects times replicas times re-hydrations, and nothing queries this table by key yet. NOTE: Adding one later is not only an index. `make_mz_indexes` inlines the builtin index set as VALUES, so a new index changes the `mz_indexes` fingerprint and needs a `MigrationStep::replacement` for it pinned to the then-current dev version. A step at a stale version is skipped and the fingerprint check panics at catalog open. Contents are exempt from the bootstrap reset and from forced schema migrations, since a sampled history cannot be rebuilt from anything else once it is gone. Durability is best effort in both directions, and the assert added here is a tripwire so that clearing the table is chosen rather than stumbled into. Ref: SQL-644
1 parent 87ffaa7 commit 4ab26a2

14 files changed

Lines changed: 193 additions & 31 deletions

File tree

doc/user/content/reference/system-catalog/mz_internal.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,28 @@ The `mz_object_history` view enriches the [`mz_catalog.mz_objects`](/reference/s
688688
| `created_at` | [`timestamp with time zone`] | Wall-clock timestamp of when the object was created. `NULL` for built in system objects. |
689689
| `dropped_at` | [`timestamp with time zone`] | Wall-clock timestamp of when the object was dropped. `NULL` for built in system objects or if the object hasn't been dropped. |
690690

691+
## `mz_object_hydration_history`
692+
693+
The `mz_object_hydration_history` table records completed hydration of indexes and
694+
materialized views, with one row for each time an object hydrated on a replica. Rows
695+
are retained for 30 days, and `object_id`, `cluster_id`, and `replica_id` may name
696+
objects that no longer exist.
697+
698+
Recording is best effort. Only successful hydration is recorded, an episode can be
699+
missed if the object or its replica goes away before the episode is recorded, and a
700+
schema change to this table in a future release may clear its contents.
701+
702+
<!-- RELATION_SPEC mz_internal.mz_object_hydration_history -->
703+
| Field | Type | Meaning |
704+
| -------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
705+
| `object_id` | [`text`] | The ID of the index or materialized view. May name an object that no longer exists. |
706+
| `cluster_id` | [`text`] | The ID of the object's cluster. |
707+
| `replica_id` | [`text`] | The ID of the cluster replica. May name a replica that no longer exists. |
708+
| `installed_at` | [`timestamp with time zone`] | When the object's dataflow was installed on the replica. |
709+
| `started_at` | [`timestamp with time zone`] | When hydration work began, or `NULL` if the replica did not observe a start for this episode. |
710+
| `finished_at` | [`timestamp with time zone`] | When hydration finished. |
711+
| `status` | [`text`] | The terminal status. Currently always `hydrated`. |
712+
691713
## `mz_object_transitive_dependencies`
692714

693715
The `mz_object_transitive_dependencies` view describes the transitive dependency structure between

src/adapter/src/catalog/open/builtin_schema_migration.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ use futures::future::BoxFuture;
3737
use mz_build_info::{BuildInfo, DUMMY_BUILD_INFO};
3838
use mz_catalog::builtin::{
3939
BUILTIN_LOOKUP, Builtin, Fingerprint, MZ_CATALOG_RAW, MZ_CATALOG_RAW_DESCRIPTION,
40-
MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_DESCRIPTION, MZ_STORAGE_USAGE_BY_SHARD,
40+
MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_DESCRIPTION, MZ_OBJECT_HYDRATION_HISTORY,
41+
MZ_OBJECT_HYDRATION_HISTORY_DESCRIPTION, MZ_STORAGE_USAGE_BY_SHARD,
4142
MZ_STORAGE_USAGE_BY_SHARD_DESCRIPTION, RUNTIME_ALTERABLE_FINGERPRINT_SENTINEL,
4243
};
4344
use mz_catalog::config::BuiltinItemMigrationConfig;
@@ -725,6 +726,17 @@ impl Migration {
725726
"mz_object_arrangement_size_history cannot be migrated or else the table will be truncated"
726727
);
727728

729+
// Unlike the two tables above, there is no correctness hazard here, a
730+
// truncation would only lose history. This is a tripwire so that the
731+
// loss is chosen rather than stumbled into: if a schema change to
732+
// this table is worth clearing it for, remove this assert along with
733+
// the exemption in `plan_forced_migration`, and say in the release
734+
// notes that the history restarts.
735+
assert_ne!(
736+
&*MZ_OBJECT_HYDRATION_HISTORY_DESCRIPTION, object,
737+
"migrating mz_object_hydration_history clears it, see the comment above"
738+
);
739+
728740
// `mz_catalog_raw` cannot be migrated because it contains the durable catalog and it
729741
// wouldn't be very durable if we allowed it to be truncated.
730742
assert_ne!(
@@ -790,9 +802,17 @@ impl Migration {
790802
.filter(|(_, info)| {
791803
use Builtin::*;
792804
match info.builtin {
793-
// Filter out the 'mz_storage_usage_by_shard' table since we need to retain
794-
// that info for billing purposes.
795-
Table(table) => **table != *MZ_STORAGE_USAGE_BY_SHARD,
805+
// A forced migration allocates a fresh shard, which discards
806+
// the table's contents. Exclude the tables whose contents
807+
// are the point: storage usage is retained for billing, and
808+
// hydration history cannot be rebuilt from any other source.
809+
// The hydration exemption is best effort, not a guarantee.
810+
// See the tripwire in `plan_migration` for how to give it up
811+
// deliberately.
812+
Table(table) => {
813+
**table != *MZ_STORAGE_USAGE_BY_SHARD
814+
&& **table != *MZ_OBJECT_HYDRATION_HISTORY
815+
}
796816
MaterializedView(..) => true,
797817
Source(source) => **source != *MZ_CATALOG_RAW,
798818
Log(..) | View(..) | Type(..) | Func(..) | Index(..) | Connection(..) => false,

src/adapter/src/coord.rs

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ use mz_adapter_types::dyncfgs::{
9898
use mz_auth::password::Password;
9999
use mz_build_info::BuildInfo;
100100
use mz_catalog::builtin::{
101-
BUILTINS, BUILTINS_STATIC, MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY, MZ_STORAGE_USAGE_BY_SHARD,
101+
BUILTINS, BUILTINS_STATIC, MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY, MZ_OBJECT_HYDRATION_HISTORY,
102+
MZ_STORAGE_USAGE_BY_SHARD,
102103
};
103104
use mz_catalog::config::{AwsPrincipalContext, BuiltinItemMigrationConfig, ClusterReplicaSizeMap};
104105
use mz_catalog::durable::OpenableDurableCatalogState;
@@ -149,7 +150,7 @@ use mz_secrets::cache::CachingSecretsReader;
149150
use mz_secrets::{SecretsController, SecretsReader};
150151
use mz_sql::ast::{Raw, Statement};
151152
use mz_sql::catalog::{CatalogCluster, EnvironmentId};
152-
use mz_sql::names::{QualifiedItemName, ResolvedIds, SchemaSpecifier};
153+
use mz_sql::names::{QualifiedItemName, ResolvedIds};
153154
use mz_sql::optimizer_metrics::OptimizerMetrics;
154155
use mz_sql::plan::{
155156
self, AlterSinkPlan, ConnectionDetails, CreateConnectionPlan, HirRelationExpr,
@@ -3064,29 +3065,19 @@ impl Coordinator {
30643065
debug!("coordinator init: resetting system tables");
30653066
let read_ts = self.get_local_read_ts().await;
30663067

3067-
// Filter out tables whose contents must survive restarts:
3068-
// 'mz_storage_usage_by_shard' for billing, and
3069-
// 'mz_object_arrangement_size_history', which accumulates history that
3070-
// is pruned by its own retention period instead.
3071-
let mz_storage_usage_by_shard_schema: SchemaSpecifier = self
3072-
.catalog()
3073-
.resolve_system_schema(MZ_STORAGE_USAGE_BY_SHARD.schema)
3074-
.into();
3075-
let arrangement_size_history_schema: SchemaSpecifier = self
3076-
.catalog()
3077-
.resolve_system_schema(MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY.schema)
3078-
.into();
3079-
let is_retained_across_restarts = |meta: &TableMetadata| -> bool {
3080-
(meta.name.item == MZ_STORAGE_USAGE_BY_SHARD.name
3081-
&& meta.name.qualifiers.schema_spec == mz_storage_usage_by_shard_schema)
3082-
|| (meta.name.item == MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY.name
3083-
&& meta.name.qualifiers.schema_spec == arrangement_size_history_schema)
3084-
};
3068+
let retained_across_restarts = BTreeSet::from([
3069+
self.catalog()
3070+
.resolve_builtin_table(&MZ_STORAGE_USAGE_BY_SHARD),
3071+
self.catalog()
3072+
.resolve_builtin_table(&MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY),
3073+
self.catalog()
3074+
.resolve_builtin_table(&MZ_OBJECT_HYDRATION_HISTORY),
3075+
]);
30853076

30863077
let mut retraction_tasks = Vec::new();
30873078
let system_tables: Vec<_> = table_metas
30883079
.iter()
3089-
.filter(|meta| meta.id.is_system() && !is_retained_across_restarts(meta))
3080+
.filter(|meta| meta.id.is_system() && !retained_across_restarts.contains(&meta.id))
30903081
.collect();
30913082

30923083
for system_table in system_tables {

src/catalog/src/builtin.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,14 @@ pub static MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_DESCRIPTION: LazyLock<SystemObject
836836
object_type: CatalogItemType::Table,
837837
object_name: MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY.name.to_string(),
838838
});
839+
840+
/// Identifies [`MZ_OBJECT_HYDRATION_HISTORY`] for the schema-migration guard.
841+
pub static MZ_OBJECT_HYDRATION_HISTORY_DESCRIPTION: LazyLock<SystemObjectDescription> =
842+
LazyLock::new(|| SystemObjectDescription {
843+
schema_name: MZ_OBJECT_HYDRATION_HISTORY.schema.to_string(),
844+
object_type: CatalogItemType::Table,
845+
object_name: MZ_OBJECT_HYDRATION_HISTORY.name.to_string(),
846+
});
839847
pub const MZ_SYSTEM_ROLE: BuiltinRole = BuiltinRole {
840848
id: MZ_SYSTEM_ROLE_ID,
841849
name: SYSTEM_USER_NAME,
@@ -1463,6 +1471,7 @@ pub static BUILTINS_STATIC: LazyLock<Vec<Builtin<NameReference>>> = LazyLock::ne
14631471
Builtin::View(&MZ_INDEX_ADVICE),
14641472
Builtin::View(&MZ_MCP_DATA_PRODUCTS),
14651473
Builtin::View(&MZ_MCP_DATA_PRODUCT_DETAILS),
1474+
Builtin::Table(&MZ_OBJECT_HYDRATION_HISTORY),
14661475
];
14671476

14681477
builtin_items.extend(notice::builtins());

src/catalog/src/builtin/mz_internal.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4965,6 +4965,105 @@ pub static MZ_OBJECT_ARRANGEMENT_SIZE_HISTORY_TS_IND: LazyLock<BuiltinIndex> =
49654965
is_retained_metrics_object: true,
49664966
});
49674967

4968+
/// Completed hydration episodes, one row per object, replica, and installation.
4969+
///
4970+
/// Exempt from the bootstrap reset and from forced schema migrations, since the
4971+
/// contents cannot be rebuilt from anything else. Clearing them for a schema
4972+
/// change is still allowed, see the tripwire in `plan_migration`.
4973+
pub static MZ_OBJECT_HYDRATION_HISTORY: LazyLock<BuiltinTable> = LazyLock::new(|| BuiltinTable {
4974+
name: "mz_object_hydration_history",
4975+
schema: MZ_INTERNAL_SCHEMA,
4976+
oid: oid::TABLE_MZ_OBJECT_HYDRATION_HISTORY_OID,
4977+
desc: RelationDesc::builder()
4978+
.with_column("object_id", SqlScalarType::String.nullable(false))
4979+
.with_column("cluster_id", SqlScalarType::String.nullable(false))
4980+
.with_column("replica_id", SqlScalarType::String.nullable(false))
4981+
.with_column(
4982+
"installed_at",
4983+
SqlScalarType::TimestampTz { precision: None }.nullable(false),
4984+
)
4985+
.with_column(
4986+
"started_at",
4987+
SqlScalarType::TimestampTz { precision: None }.nullable(true),
4988+
)
4989+
.with_column(
4990+
"finished_at",
4991+
SqlScalarType::TimestampTz { precision: None }.nullable(true),
4992+
)
4993+
.with_column("status", SqlScalarType::String.nullable(false))
4994+
.finish(),
4995+
column_comments: BTreeMap::from_iter([
4996+
(
4997+
"object_id",
4998+
"The ID of the index or materialized view. May name an object that no longer exists.",
4999+
),
5000+
("cluster_id", "The ID of the object's cluster."),
5001+
(
5002+
"replica_id",
5003+
"The ID of the cluster replica. May name a replica that no longer exists.",
5004+
),
5005+
(
5006+
"installed_at",
5007+
"When the object's dataflow was installed on the replica.",
5008+
),
5009+
(
5010+
"started_at",
5011+
"When hydration work began, or `NULL` if the replica did not observe a start for this episode.",
5012+
),
5013+
("finished_at", "When hydration finished."),
5014+
(
5015+
"status",
5016+
"The terminal status. Currently always `hydrated`.",
5017+
),
5018+
]),
5019+
// Not a retained-metrics object: that would pin a 30 day compaction window,
5020+
// and our history lives in the rows, which the retention sweep retracts on
5021+
// its own schedule. Nothing reads this table at an old timestamp.
5022+
is_retained_metrics_object: false,
5023+
access: vec![PUBLIC_SELECT],
5024+
ontology: Some(Ontology {
5025+
entity_name: "object_hydration_event",
5026+
description: "Completed hydration of an index or materialized view on a replica",
5027+
// NOTE: These references outlive what they point at. A row deliberately
5028+
// survives the object and the replica it describes, so resolving one
5029+
// against the catalog can come up empty.
5030+
links: &const {
5031+
[
5032+
OntologyLink {
5033+
name: "hydration_of_object",
5034+
target: "object",
5035+
properties: LinkProperties::fk_typed(
5036+
"object_id",
5037+
"id",
5038+
Cardinality::ManyToOne,
5039+
mz_repr::SemanticType::CatalogItemId,
5040+
),
5041+
},
5042+
OntologyLink {
5043+
name: "hydrated_on_cluster",
5044+
target: "cluster",
5045+
properties: LinkProperties::fk("cluster_id", "id", Cardinality::ManyToOne),
5046+
},
5047+
OntologyLink {
5048+
name: "hydrated_on_replica",
5049+
target: "replica",
5050+
properties: LinkProperties::fk_typed(
5051+
"replica_id",
5052+
"id",
5053+
Cardinality::ManyToOne,
5054+
mz_repr::SemanticType::CatalogItemId,
5055+
),
5056+
},
5057+
]
5058+
},
5059+
column_semantic_types: &[
5060+
("object_id", SemanticType::CatalogItemId),
5061+
("cluster_id", SemanticType::ClusterId),
5062+
("replica_id", SemanticType::ReplicaId),
5063+
],
5064+
}),
5065+
});
5066+
49685067
pub static MZ_COMPUTE_HYDRATION_STATUSES: LazyLock<BuiltinView> = LazyLock::new(|| BuiltinView {
49695068
name: "mz_compute_hydration_statuses",
49705069
schema: MZ_INTERNAL_SCHEMA,

src/pgrepr-consts/src/oid.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,3 +822,4 @@ pub const FUNC_PARSE_CONNECTION_DETAILS_OID: u32 = 17112;
822822
pub const FUNC_MZ_AWS_ACCOUNT_ID_OID: u32 = 17113;
823823
pub const FUNC_MZ_AWS_EXTERNAL_ID_PREFIX_OID: u32 = 17114;
824824
pub const FUNC_MZ_AWS_CONNECTION_ROLE_ARN_OID: u32 = 17115;
825+
pub const TABLE_MZ_OBJECT_HYDRATION_HISTORY_OID: u32 = 17116;

test/sqllogictest/autogenerated/mz_internal.slt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,17 @@ object_type text The␠type␠of␠the␠object:␠one␠of␠`table`,␠`sour
382382
created_at timestamp␠with␠time␠zone Wall-clock␠timestamp␠of␠when␠the␠object␠was␠created.␠`NULL`␠for␠built␠in␠system␠objects.
383383
dropped_at timestamp␠with␠time␠zone Wall-clock␠timestamp␠of␠when␠the␠object␠was␠dropped.␠`NULL`␠for␠built␠in␠system␠objects␠or␠if␠the␠object␠hasn't␠been␠dropped.
384384

385+
query TTT
386+
SELECT name, type, comment FROM objects WHERE schema = 'mz_internal' AND object = 'mz_object_hydration_history' ORDER BY position
387+
----
388+
object_id text The␠ID␠of␠the␠index␠or␠materialized␠view.␠May␠name␠an␠object␠that␠no␠longer␠exists.
389+
cluster_id text The␠ID␠of␠the␠object's␠cluster.
390+
replica_id text The␠ID␠of␠the␠cluster␠replica.␠May␠name␠a␠replica␠that␠no␠longer␠exists.
391+
installed_at timestamp␠with␠time␠zone When␠the␠object's␠dataflow␠was␠installed␠on␠the␠replica.
392+
started_at timestamp␠with␠time␠zone When␠hydration␠work␠began,␠or␠`NULL`␠if␠the␠replica␠did␠not␠observe␠a␠start␠for␠this␠episode.
393+
finished_at timestamp␠with␠time␠zone When␠hydration␠finished.
394+
status text The␠terminal␠status.␠Currently␠always␠`hydrated`.
395+
385396
query TTT
386397
SELECT name, type, comment FROM objects WHERE schema = 'mz_internal' AND object = 'mz_object_transitive_dependencies' ORDER BY position
387398
----
@@ -830,6 +841,7 @@ mz_object_dependencies
830841
mz_object_fully_qualified_names
831842
mz_object_global_ids
832843
mz_object_history
844+
mz_object_hydration_history
833845
mz_object_lifetimes
834846
mz_object_oid_alias
835847
mz_object_transitive_dependencies

test/sqllogictest/catalog_server_explain.slt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9969,7 +9969,7 @@ query T multiline
99699969
EXPLAIN SELECT * FROM "mz_internal"."mz_ontology_entity_types";
99709970
----
99719971
Explained Query (fast path):
9972-
→Constant (134 rows)
9972+
→Constant (135 rows)
99739973

99749974
Target cluster: mz_catalog_server
99759975

@@ -9979,7 +9979,7 @@ query T multiline
99799979
EXPLAIN SELECT * FROM "mz_internal"."mz_ontology_link_types";
99809980
----
99819981
Explained Query (fast path):
9982-
→Constant (173 rows)
9982+
→Constant (176 rows)
99839983

99849984
Target cluster: mz_catalog_server
99859985

@@ -9993,7 +9993,7 @@ Explained Query:
99939993
cte l0 =
99949994
→Differential Join %1:mz_schemas[#0{id}] » %2:mz_objects[#2{schema_id}] » %0[#0{schema_name}, #1{table_name}] » %3:mz_columns[#0{id}]
99959995
→Arrange (#0{schema_name}, #1{table_name})
9996-
→Constant (134 rows)
9996+
→Constant (135 rows)
99979997
→Arrange (#0{id})
99989998
→Fused with Child Map/Filter/Project
99999999
Project: #1, #3
@@ -10046,7 +10046,7 @@ Explained Query:
1004610046
→Differential Join %0:l4[#0{entity_name}, #1{name}] » %1[#0{entity_name}, #1{column_name}]
1004710047
→Arranged l4
1004810048
→Arrange (#0{entity_name}, #1{column_name})
10049-
→Constant (272 rows)
10049+
→Constant (275 rows)
1005010050
→Return
1005110051
→Union
1005210052
→Map/Filter/Project

test/sqllogictest/information_schema_tables.slt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,10 @@ mz_object_history
497497
VIEW
498498
materialize
499499
mz_internal
500+
mz_object_hydration_history
501+
BASE TABLE
502+
materialize
503+
mz_internal
500504
mz_object_lifetimes
501505
VIEW
502506
materialize

test/sqllogictest/mz_catalog_server_index_accounting.slt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ mz_message_batch_counts_received_raw_s2_primary_idx CREATE␠INDEX␠"mz_messag
8383
mz_message_batch_counts_sent_raw_s2_primary_idx CREATE␠INDEX␠"mz_message_batch_counts_sent_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_message_batch_counts_sent_raw"␠("channel_id",␠"from_worker_id",␠"to_worker_id")
8484
mz_message_counts_received_raw_s2_primary_idx CREATE␠INDEX␠"mz_message_counts_received_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_message_counts_received_raw"␠("channel_id",␠"from_worker_id",␠"to_worker_id")
8585
mz_message_counts_sent_raw_s2_primary_idx CREATE␠INDEX␠"mz_message_counts_sent_raw_s2_primary_idx"␠IN␠CLUSTER␠[s2]␠ON␠"mz_introspection"."mz_message_counts_sent_raw"␠("channel_id",␠"from_worker_id",␠"to_worker_id")
86-
mz_notices_ind CREATE␠INDEX␠"mz_notices_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s835␠AS␠"mz_internal"."mz_notices"]␠("id")
86+
mz_notices_ind CREATE␠INDEX␠"mz_notices_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s836␠AS␠"mz_internal"."mz_notices"]␠("id")
8787
mz_object_arrangement_size_history_object_ind CREATE␠INDEX␠"mz_object_arrangement_size_history_object_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s753␠AS␠"mz_internal"."mz_object_arrangement_size_history"]␠("object_id")
8888
mz_object_arrangement_size_history_ts_ind CREATE␠INDEX␠"mz_object_arrangement_size_history_ts_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s753␠AS␠"mz_internal"."mz_object_arrangement_size_history"]␠("collection_timestamp")
8989
mz_object_arrangement_sizes_ind CREATE␠INDEX␠"mz_object_arrangement_sizes_ind"␠IN␠CLUSTER␠[s2]␠ON␠[s751␠AS␠"mz_internal"."mz_object_arrangement_sizes"]␠("replica_id")

0 commit comments

Comments
 (0)