Livesync replication advanced topics
Advanced Livesync replication scenarios for migrating to Tiger Cloud
Advanced scenarios for Livesync replication migrations: continuous aggregates, compressed hypertables on older TimescaleDB versions, and identity columns.
Migrating continuous aggregates
Section titled “Migrating continuous aggregates”Livesync replicates the continuous aggregate‘s underlying materialization hypertable, not the view. The continuous aggregate must already exist with data on the source and be defined (empty) on the target.
-
Resolve materialization hypertable names on both source and target. The
_materialized_hypertable_<N>suffix differs per environment:SELECT materialization_hypertable_schema AS mat_schema,materialization_hypertable_name AS mat_nameFROM timescaledb_information.continuous_aggregatesWHERE view_schema = '<schema>' AND view_name = '<cagg_name>'; -
Set replica identity on the source materialization hypertable. Required when the publication replicates
UPDATE/DELETE(the default). Continuous aggregate refreshes issueDELETEs; without a replica identity the next refresh fails withcannot delete from table ... because it does not have a replica identity and publishes deletes.ALTER TABLE _timescaledb_internal._materialized_hypertable_<N>REPLICA IDENTITY FULL; -
Add the materialization hypertable to the publication:
ALTER PUBLICATION <publication_name>ADD TABLE _timescaledb_internal._materialized_hypertable_<N>; -
Map source matview hypertable to target matview hypertable.
-
Console: edit the connector, select the source
_materialized_hypertable_<N>, and set its target mapping to the target’s_materialized_hypertable_<M>. -
Docker: add a
--table-mapentry and refresh:--table-map '{"source": {"schema": "_timescaledb_internal", "table": "_materialized_hypertable_<N>"},"target": {"schema": "_timescaledb_internal", "table": "_materialized_hypertable_<M>"}}'
-
-
Do not attach a refresh policy on the target. While Livesync is running, the target continuous aggregate is kept current via replication. Attach the refresh policy on the target only after cutover.
Replica identity on compressed hypertables (older TimescaleDB)
Section titled “Replica identity on compressed hypertables (older TimescaleDB)”On older TimescaleDB versions, ALTER TABLE ... REPLICA IDENTITY ... fails on compressed hypertables:
ERROR: operation not supported on hypertables that have compression enabledNewer versions accept the command directly on the hypertable and propagate it to chunks. If you can upgrade TimescaleDB on the source first, do that and skip this section.
If upgrading isn’t an option, wrap the work in timescaledb_pre_restore() / timescaledb_post_restore() (these disable the catalog hooks that block the operation). Iterate over all chunks of the hypertable, set REPLICA IDENTITY FULL on each, and set it on the hypertable itself so new chunks inherit:
psql "$SOURCE" -v schema='<schema>' -v hypertable='<hypertable>' <<'EOF'BEGIN;SELECT timescaledb_pre_restore();
SELECT format('ALTER TABLE %I.%I REPLICA IDENTITY FULL;', chunk_schema, chunk_name)FROM timescaledb_information.chunksWHERE hypertable_schema = :'schema' AND hypertable_name = :'hypertable'\gexec
ALTER TABLE :"schema".:"hypertable" REPLICA IDENTITY FULL;
SELECT timescaledb_post_restore();COMMIT;EOFRun as a single transaction. Dry-run on a non-production instance first.
Tables with GENERATED ALWAYS AS IDENTITY columns
Section titled “Tables with GENERATED ALWAYS AS IDENTITY columns”CDC UPDATE replication currently fails on target tables whose columns are defined as GENERATED ALWAYS AS IDENTITY, because the apply worker tries to write the source value into a column that PostgreSQL forbids assigning to. Until Livesync handles this automatically, work around it by relaxing the column to GENERATED BY DEFAULT for the duration of the migration. This does not rewrite the column or change runtime behavior for existing sequences.
-
Find affected columns on the source:
psql "$SOURCE" <<'EOF'SELECTn.nspname AS schema,c.relname AS table,a.attname AS columnFROM pg_attribute aJOIN pg_class c ON c.oid = a.attrelidJOIN pg_namespace n ON n.oid = c.relnamespaceWHERE a.attidentity = 'a' -- 'a' = ALWAYS, 'd' = BY DEFAULTAND c.relkind IN ('r', 'p')AND n.nspname NOT IN ('pg_catalog', 'information_schema')ORDER BY n.nspname, c.relname, a.attnum;EOF -
Relax to
BY DEFAULTbefore migration. For each row returned above, run on both source and target:ALTER TABLE <schema>.<table>ALTER COLUMN <column> SET GENERATED BY DEFAULT; -
Restore to
ALWAYSafter cutover. After the application is running on Tiger Cloud, restore the original constraint on the target:ALTER TABLE <schema>.<table>ALTER COLUMN <column> SET GENERATED ALWAYS;