docs/deploy/logical-replication/multi-database.mdx
Organizations often have multiple Postgres databases, each connected to a different microservice. The goal is to logically replicate all of these databases into a single ParadeDB instance. This enables:
However, table naming collisions can occur since each microservice and its database operate independently.
Postgres' Logical Replication is designed from the perspective of one source database and one destination database. Logical replication resolves tables by their schema-qualified name. It does not have native primitives to remap schema or table names during replication.
For logical replication to work, all source database tables need to have a unique signature that avoids name collisions. They also need to be identifiable by their source database. This can be achieved by using a different schema in each database instead of the public schema. The schema name should match the database name.
The solution involves replicating multiple independent microservice databases into a single ParadeDB instance. Each source database uses a schema named after the database itself, ensuring no naming conflicts.
As shown in the diagram:
db1.table1, db2.table1)SELECT db1.users.user_id FROM db1.users, db2.orders WHERE db1.users.id = db2.orders.user_idInstead of having all tables in the public schema across multiple databases:
Database: users_service
Schema: public
- users
- profiles
Database: orders_service
Schema: public
- orders
- payments
Reorganize each database to use a dedicated schema:
Database: users_service
Schema: users_service
- users
- profiles
Database: orders_service
Schema: orders_service
- orders
- payments
This approach ensures that when replicated to ParadeDB, all tables have unique fully-qualified names and you can identify the source of each table.
This migration strategy reorganizes tables from the public schema into dedicated schemas while maintaining complete backwards compatibility through updatable views.
For each microservice database, execute the following:
BEGIN;
-- Create new schema named after the database
CREATE SCHEMA IF NOT EXISTS <database_name>;
-- Move tables to new schema
ALTER TABLE public.table1 SET SCHEMA <database_name>;
ALTER TABLE public.table2 SET SCHEMA <database_name>;
-- Repeat for all tables...
-- Create backwards-compatible views in public schema
CREATE OR REPLACE VIEW public.table1 AS SELECT * FROM <database_name>.table1;
CREATE OR REPLACE VIEW public.table2 AS SELECT * FROM <database_name>.table2;
-- Repeat for all tables...
COMMIT;
For a users_service database:
BEGIN;
-- Create new schema
CREATE SCHEMA IF NOT EXISTS users_service;
-- Move tables
ALTER TABLE public.users SET SCHEMA users_service;
ALTER TABLE public.profiles SET SCHEMA users_service;
-- Create backwards-compatible views
CREATE OR REPLACE VIEW public.users AS SELECT * FROM users_service.users;
CREATE OR REPLACE VIEW public.profiles AS SELECT * FROM users_service.profiles;
COMMIT;
public schema can be safely removedAfter completing the schema migration for all source databases:
-- On users_service database
CREATE PUBLICATION users_pub FOR TABLES IN SCHEMA users_service;
-- On orders_service database
CREATE PUBLICATION orders_pub FOR TABLES IN SCHEMA orders_service;
-- On ParadeDB instance
CREATE SUBSCRIPTION users_sub
CONNECTION 'host=users_db port=5432 dbname=users_service user=replicator password=...'
PUBLICATION users_pub;
CREATE SUBSCRIPTION orders_sub
CONNECTION 'host=orders_db port=5432 dbname=orders_service user=replicator password=...'
PUBLICATION orders_pub;
users_service) instead of public