# Architecture Overview
Source: https://docs.peerdb.io/architecture
PeerDB is fundamentally made up of two parts: the platform and the connectors.
The **platform** encompasses the essential services necessary to configure and run data querying and movement operations, which include the Nexus Query Layer and the Flow Data Transfer Component.
* **Nexus Query Layer**: Located in the `nexus` subfolder in the root repository, Nexus is a Rust-implemented service that enables Postgres-compatible SQL querying across various data sources and sinks. It supports the PGWire protocol and can be horizontally scaled to manage high demand.
* **Flow Data Transfer Component**: Stored in the `flow` subfolder of the root repository, Flow is written in Golang. It manages data transfer between sources and sinks, and consists of a Flow API and horizontally scalable Flow Workers.
The **connectors** signify various data sources and sinks that PeerDB can interact with. They include databases like Postgres, MySQL (sources), and Bigquery, Snowflake (sinks).
### Detailed Components
* **Nexus Query Layer**: This is the user interface to run SQL queries. It communicates with both data sources and sinks.
* **Flow Data Transfer Component**: It has two parts - the Flow API that manages the process and the Flow Workers that perform the actual data transfer.
* **Sources**: These are the databases from which data can be fetched, like Postgres and MySQL.
* **Sinks**: These are the databases where data can be deposited, like Bigquery and Snowflake.
### Dependencies
PeerDB has two primary dependencies:
1. **[Temporal Orchestration Engine](https://www.temporal.io/)**: This external service orchestrates the data transfer process within the Flow component.
2. **Catalog Database (Postgres)**: This database stores metadata related to PeerDB's operations.
The main strengths of PeerDB are its scalability and flexibility, allowing for the addition of Nexus and Flow Worker instances to handle increased load efficiently.
# Benchmarking Postgres Replication: PeerDB vs Airbyte
Source: https://docs.peerdb.io/benchmarks/benchmarking-Postgres-Replication:-PeerDB-vs-Airbyte
We at [PeerDB](https://www.peerdb.io/) are working on fast and simple data movement in and out of Postgres. Other data-movement tools also support the Postgres connector and have been investing in improving this. For example, [Airbyte](https://airbyte.com) has released a [series](https://airbyte.com/blog/replicate-postgres-datasets-of-any-size-in-airbyte) [of](https://airbyte.com/blog/postgres-replication-performance-benchmark-airbyte-vs-fivetran) blog posts demonstrating improvements they have made to their Postgres connector, leading to significant performance gains over [Fivetran](https://www.fivetran.com/).
In the past few weeks, we spent some time running a benchmark captured in [this](https://airbyte.com/blog/postgres-replication-performance-benchmark-airbyte-vs-fivetran) Airbyte blog. The primary goal was to understand - how we stack up against other tools, how our existing features impact performance and how can we further improve our product.
## Assumptions
Airbyte’s [benchmark](https://airbyte.com/blog/postgres-replication-performance-benchmark-airbyte-vs-fivetran) was performing a one-time transfer of a single large table from Postgres to Snowflake. Since we are moving data already present in the source table instead of incrementally moving fresh data, this is what we call a **Full Refresh** in Airbyte and an **Initial Snapshot** in PeerDB.
Benchmarking a large migration like this is highly dependent not only on the performance of the migration platform but also on the performance of the source Postgres and target Snowflake instances. Network throughput between all these parts is also crucial.
So we generated a dataset and tested PeerDB and Airbyte against it, using instances for Postgres and Snowflake which we felt best represented a production deployment. The entire infrastructure was positioned within a single AWS region, reducing network bottlenecks. More details on the setup can be found [**here**](https://github.com/PeerDB-io/ab-scale-testing#benchmark-setup)**.**
## Generating the Data
While Airbyte provided the schema of the table, it wasn’t enough to generate a dataset, as we didn’t know the size of a row or the number of rows in the table. We decided to run the test on a table with 6 billion rows and a 1.5TB size.
We worked out that each row should be around 230-235 bytes. We then arrived at a size for each variable length field that should get us the table size we wanted. We also converted one of the columns in the table to be a generated primary key because PeerDB currently [requires](https://docs.peerdb.io/usecases/real-time-cdc/postgres-to-snowflake#prerequisites) one for CDC mirroring.
```sql theme={null}
CREATE TABLE IF NOT EXISTS public.xxxxx
(
f0 BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
f1 BIGINT,
f2 BIGINT,
f3 INTEGER,
f4 DOUBLE PRECISION,
f5 DOUBLE PRECISION,
f6 DOUBLE PRECISION,
f7 DOUBLE PRECISION,
f8 VARCHAR COLLATE pg_catalog.\"default\",
f9 VARCHAR COLLATE pg_catalog.\"default\",
f10 DATE,
f11 DATE,
f12 DATE,
f13 VARCHAR COLLATE pg_catalog.\"default\",
f14 VARCHAR COLLATE pg_catalog.\"default\",
f15 VARCHAR COLLATE pg_catalog.\"default\"
)
```
After doing *all* this, we wrote a [small Rust program](https://github.com/PeerDB-io/ab-scale-testing/blob/main/src/main.rs) that could generate 6 billion rows and insert them into a Postgres instance we provisioned on AWS RDS. After some debugging, we were in business!
```rust theme={null}
[2023-09-12T10:08:33Z INFO firenibble] Finished inserting 6000000000 rows in 12689.01s seconds
[2023-09-12T10:08:33Z INFO firenibble] Throughput: 472850.12
```
```plaintext theme={null}
postgres=> SELECT pg_size_pretty(pg_relation_size('public.xxxxx'));
pg_size_pretty
----------------
1578 GB
(1 row)
```
## Testing!
Both AirByte and PeerDB have an Open Source offering and are available as Docker Compose Applications. So we decided to use these for our testing, on a sufficiently powerful AWS EC2 instance. To reiterate, we are only looking for the performance of the initial load, and not an incremental sync.
### Airbyte
With Airbyte, we already knew from their numbers that a run could take multiple days. So after deploying Airbyte and setting up our connectors, we kicked off a run, checking in once every few hours.
After an initial failure because of hitting a [timeout (of 72 hours)](https://github.com/airbytehq/airbyte/issues/7525#issuecomment-959778866), Airbyte completed successfully. It took **83 hours** to move the table to Snowflake.
### PeerDB
PeerDB [implements parallelism for these heavy initial loads](https://blog.peerdb.io/parallelized-initial-load-for-cdc-based-streaming-from-postgres), and we launched five runs in total with 1, 8, 16, 32 and 48 parallel threads.
With 32 and 48 threads, PeerDB moved over **1.5TB** of Postgres table in under **5 hours**. Even scaling down to 8 threads, we still see a runtime of under **9** hours. This performance derives from the optimizations PeerDB has done to make reads as efficient as possible and also the parallelism multiplier.
Airbyte does not support parallelism at the moment. We decided to do an additional run with parallelism set to 1, as a fair comparison to Airbyte. With this, we got a run time of **43** hours.
## Results
Airbyte took **83 hours** to move a 1.5TB table from Postgres to Snowflake. With a parallelism of 32 threads, PeerDB took 5 hours to do the same job. So PeerDB was **16x** faster. Even considering a single-threaded run, PeerDB is **\~2x** faster. We felt that a comparison with Fivetran was out of scope for this article. Airbyte had already shown that Fivetran was slower than Airbyte and we could expect a full refresh to take **150+ hours**.
## What makes PeerDB faster?
### Parallelism
One of the more obvious reasons is our early adoption of parallelism for long-running operations such as moving large tables from Postgres to Snowflake. We do this by logically partitioning the large table based on internal tuple identifiers (CTID) and parallelly streaming those partitions to Snowflake. The implementation is inspired by this DuckDb [**blog**](https://duckdb.org/2022/09/30/postgres-scanner.html#parallel). Based on the load you can put on the source Postgres database, you can [**configure**](https://docs.peerdb.io/sql/commands/create-mirror#mirror-for-cdc) the parallelism for the sync. More details can be found in [this](https://blog.peerdb.io/parallelized-initial-load-for-cdc-based-streaming-from-postgres) blog
Large table logically partitioned based on CTID ranges and streamed in parallel, reliably and efficiently to the target data-store. During the initial load, a snapshot connection needs to be maintained to ensure data consistency on the target.
### Batching
The second is [configurable batching](https://docs.peerdb.io/sql/commands/create-mirror#mirror-for-cdc) while reading from Postgres and writing to Snowflake. If you have PeerDB running on a large machine you could have a larger batch size (ex: 1mill). This reduces the network roundtrips across Postgres, PeerDB and Snowflake thereby improving performance. Configurable batching also helps meet Snowflake's [recommendation](https://docs.snowflake.com/en/user-guide/data-load-considerations-prepare#general-file-sizing-recommendations) for faster loads. In the above tests, we configured a batch size of \~750K to meet this recommendation.
### Binary format for data transfer
This third is using [Avro](https://github.com/PeerDB-io/peerdb/pull/123) as the intermediary data format. Avro enables data to be stored in binary (compressed) format and still supports a [**wide variety of data types**](https://avro.apache.org/docs/1.10.2/spec.html#schema_complex) (unlike parquet). This enables fast data movement, without compromising data integrity.
### Glimpses into the future
We are working on multiple other features incl. concurrent reading of the replication slot during the Initial Snapshot; parallelized writing of Change Data Capture to Target tables; and others to further improve performance
## Closing Remarks
Keeping performance aside, we were quite impressed with Airbyte's web interface and a staggering variety of connectors. We would recommend it if the breadth of available connectors is more important to you.
At PeerDB we instead have a laser focus on Postgres with the primary goal of providing the highest quality source and destination connectors for it.
If Postgres is a central part of your data stack and you want to stream data from Postgres to data warehouses, message queues or storage engines faster, simpler and cheaper, **come talk to us** [**here**](https://www.peerdb.io/sign-up). You could also try out our free and open offering [here](https://github.com/PeerDB-io/peerdb).
If you want to try benchmarking PeerDB and Airbyte yourself, we have put info about our benchmark [here](https://github.com/PeerDB-io/ab-scale-testing).
# Postgres to ClickHouse: Data Modeling Tips
Source: https://docs.peerdb.io/bestpractices/clickhouse_datamodeling
[PeerDB](https://www.peerdb.io/) makes it fast and simple to replicate data from [Postgres](https://www.postgresql.org/) to [ClickHouse](https://clickhouse.com/). A common question from PeerDB users is how to model their data in ClickHouse after the replication process to maximize the benefits of ClickHouse.
This question arises because ClickHouse and Postgres differ in data modeling, as each is a **purpose-built database** highly optimized for its specific workload -Postgres is a transactional (OLTP) database, while ClickHouse is an analytical (OLAP) columnar database. This guide walks you through essential data modeling concepts in ClickHouse for users coming from the Postgres world.
## ReplacingMergeTree table engine
PeerDB maps PostgreSQL tables to ClickHouse using the [ReplacingMergeTree](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replacingmergetree) engine. ClickHouse performs best with append-only workloads and [does not recommend](https://clickhouse.com/docs/en/guides/developer/mutations) frequent UPDATEs. This is where ReplacingMergeTree is particularly powerful.
`ReplacingMergeTree` supports workloads that involve both data ingestion and modifications. Each table is append-only, with user updates ingested as versioned INSERTs. The ReplacingMergeTree engine manages deduplication (merging) of rows in the background. This is one of the key factors that enables ClickHouse to deliver exceptional real-time ingestion performance.
In PeerDB, both INSERTs and UPDATEs from Postgres are captured as new rows with different versions (using `_peerdb_version`) in ClickHouse. The `ReplacingMergeTree` table engine periodically handles deduplication in the background using the Ordering Key (ORDER BY columns), retaining only the row with the latest `_peerdb_version`. DELETEs from PostgreSQL are propagated as new rows marked as deleted (using the `_peerdb_is_deleted` column). The snippet below shows the target table definition for the `public_goals` table in ClickHouse.
```sql theme={null}
clickhouse-cloud :) SHOW CREATE TABLE public_goals;
CREATE TABLE peerdb.public_goals
(
`id` Int64,
`owned_user_id` String,
`goal_title` String,
`goal_data` String,
`enabled` Bool,
`ts` DateTime64(6),
`_peerdb_synced_at` DateTime64(9) DEFAULT now(),
`_peerdb_is_deleted` Int8,
`_peerdb_version` Int64
)
ENGINE = SharedReplacingMergeTree
('/clickhouse/tables/{uuid}/{shard}', '{replica}', _peerdb_version)
PRIMARY KEY id
ORDER BY id
SETTINGS index_granularity = 8192
```
## You might still see duplicates for rows—how should you handle them?
ReplacingMergeTree clears out duplicates asynchronously in the background but doesn't guarantee the absence of duplicates. So, when you query the data, you might still see duplicates for the same row or primary key but with different versions. This is expected. To remove duplicates, you have a couple of approaches:
### Use FINAL in your queries
ClickHouse has a unique modifier called [FINAL](https://clickhouse.com/docs/en/sql-reference/statements/select/from#final-modifier), which performs de-duplication (merging of rows) at query time. This de-duplication occurs after filtering (WHERE clause) but before aggregations (GROUP BY).
A historical concern has been that FINAL can slow down query performance. While it does impact query performance to some extent, recent releases of ClickHouse have introduced [significant improvements](https://github.com/ClickHouse/ClickHouse/issues/11722) to enhance FINAL query performance. So, don’t hesitate to use the FINAL clause and evaluate how your queries perform. Below is an example of how to use the FINAL clause:
```sql theme={null}
SELECT owner_user_id, COUNT(*) FROM goals FINAL
WHERE enabled = true GROUP BY owner_user_id;
```
### Use argMax to deduplicate rows at query time
In ClickHouse, [argMax](https://clickhouse.com/docs/en/sql-reference/aggregate-functions/reference/argmax) is a powerful function for deduplicating rows dynamically during query execution. This is particularly useful when you need to retain the most recent or relevant record based on a versioning or timestamp column.
For instance, if you're working with a table like `peerdb.public_goals`, where id is the primary key and `_peerdb_version` tracks versions, you can use argMax to select the row with the highest `_peerdb_version` for each `id`. This approach allows you to efficiently remove duplicates without altering the underlying data. You can then run your aggregations as a subquery over this deduplicated result set for further analysis. Below query is an example of using argMax
```sql theme={null}
SELECT
owned_user_id,
COUNT(*) AS active_goals_count,
MAX(ts) AS latest_goal_time
FROM
(
SELECT
id,
argMax(owned_user_id, _peerdb_version) AS owned_user_id,
argMax(goal_title, _peerdb_version) AS goal_title,
argMax(goal_data, _peerdb_version) AS goal_data,
argMax(enabled, _peerdb_version) AS enabled,
argMax(ts, _peerdb_version) AS ts,
argMax(_peerdb_synced_at, _peerdb_version) AS _peerdb_synced_at,
argMax(_peerdb_is_deleted, _peerdb_version) AS _peerdb_is_deleted,
max(_peerdb_version) AS _peerdb_version
FROM peerdb.public_goals
WHERE enabled = true
GROUP BY id
) AS deduplicated_goals
GROUP BY owned_user_id;
```
### Use WINDOW FUNCTIONS
You can use ClickHouse's [window functions](https://clickhouse.com/docs/en/sql-reference/window-functions) to achieve similar deduplication by selecting the row with the highest `_peerdb_version` within each id partition. Here's an example:
```sql theme={null}
SELECT
owned_user_id,
COUNT(*) AS active_goals_count,
MAX(ts) AS latest_goal_time
FROM
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY _peerdb_version DESC) AS rn
FROM peerdb.public_goals
WHERE enabled = true
) AS ranked_goals
WHERE rn = 1
GROUP BY owned_user_id;
```
### Use Views to simplify deduplication
Encapsulate deduplication in a [view](https://clickhouse.com/docs/en/sql-reference/statements/create/view) to make it simple for BI tools to query the most up-to-date data. For example, use a window function in the view to keep only the latest version of each row:
```sql theme={null}
CREATE VIEW goals AS
SELECT * FROM
(
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY _peerdb_version DESC) AS rn
FROM peerdb.public_goals
WHERE enabled = true
) WHERE rn = 1;
```
```sql theme={null}
SELECT
owned_user_id,
COUNT(*) AS active_goals_count,
MAX(ts) AS latest_goal_time
FROM goals
GROUP BY owned_user_id;
```
## Nullable Columns
If you're coming from the Postgres world, one surprising aspect of ClickHouse is that it doesn’t store NULL values for columns unless you explicitly wrap the column types in [`Nullable`](https://clickhouse.com/docs/en/sql-reference/data-types/nullable). For example, instead of storing NULL for dates, ClickHouse stores `1970-01-01` as the default value, which might be unexpected. This behavior is due to the fact that storing NULLs can [impact](https://clickhouse.com/docs/en/sql-reference/data-types/nullable) query performance in ClickHouse, as it’s a columnar database. Hence, ClickHouse requires users to explicitly define `Nullable` types.
In PeerDB, we’ve introduced a setting called `PEERDB_NULLABLE`, which, when set to `true`, automatically detects nullable columns in Postgres and marks them as `Nullable` in ClickHouse during the replication process. This means you don’t need to manually define `Nullable` types during replication. You can read more about this feature in the following [PR](https://github.com/PeerDB-io/peerdb/pull/2001).
## **Data Types**
ClickHouse offers a wide variety of data types, ranging from numbers, text, timestamps, dates, and arrays to the recently introduced [JSON](https://github.com/ClickHouse/ClickHouse/issues/54864) type. Many of the data types in Postgres can be natively stored in ClickHouse without much modification.
As a reference, here goes [the data type matrix](https://docs.peerdb.io/datatypes/datatype-matrix) we use at PeerDB when replicating data from Postgres to ClickHouse.
## The Ordering Key
### What is an Ordering Key?
Choosing the right ordering key is crucial for query performance in ClickHouse. Defined by the `ORDER BY` clause when creating a table, the ordering key functions similarly to a index in Postgres but is optimized for analytics. Unlike Postgres, which uses a B-tree index with entries pointing to each row, ClickHouse uses Sparse Indexing:
1. **Data is sorted based on Ordering Key:** The ordering key ensures that data on disk is sorted according to the specified columns. This allows for better [compression](https://clickhouse.com/docs/en/data-compression/compression-in-clickhouse), as correlated values are stored together.
2. **Ordering Key also creates a sparse index:** The ordering key also creates a sparse index, storing only ranges of columns, with each entry pointing to a group of sorted rows. This keeps the index small, allowing ClickHouse to quickly identify relevant groups of rows using a binary search and execute queries efficiently. You can read more about this [here](https://clickhouse.com/docs/en/migrations/postgresql/designing-schemas#primary-ordering-keys-in-clickhouse).
You can think of ordering keys as similar to [BRIN](https://www.postgresql.org/docs/current/indexes-types.html#INDEXES-TYPES-BRIN) indexes in Postgres, but in ClickHouse, the data is automatically sorted based on the ordering key via asynchronous merging of parts, so you don’t need to handle sorting during data ingestion.
### Choosing an appropriate Ordering Key
When selecting an ordering key, base your choice on the columns most frequently used in your query filters. **Prioritize columns that are commonly used in WHERE clauses, and order them in ascending sequence of cardinality**—starting with columns that have the fewest distinct values. This approach optimizes data compression and query performance. For a deeper understanding of this topic, refer to the detailed guide [here](https://clickhouse.com/docs/en/data-modeling/schema-design#choosing-an-ordering-key).
### **PRIMARY KEY vs Ordering Key**
If you observe the table definition of `public_goals`, it has a `PRIMARY KEY`. You might be wondering how the `PRIMARY KEY` differs from the Ordering Key. Let us understand how they differ:
1. `PRIMARY KEY`, if specified, defines the columns in the sparse index, while the columns in the `ORDER BY` clause determine how the data is sorted on disk. They are also used for deduplicating data by the `ReplacingMergeTree`.
2. If the `PRIMARY KEY` isn't specified, the Ordering Key automatically becomes the `PRIMARY KEY` and defines the columns in the sparse index.
**NOTE:** Columns in the `PRIMARY KEY` should always be prefixed in the Ordering Key. This ensures that the index aligns with the physical data order, maximizing query performance by minimizing unnecessary data scans.
**An example where** `PRIMARY KEY` **could differ from Ordering Key**
An example where you might have different `PRIMARY KEY` and `ORDER BY` columns is when your queries are primarily filtered on `customer_id` rather than `id`. In this case, you can define the `PRIMARY KEY` on just `customer_id` and the `ORDER BY` on `customer_id, id`. This approach ensures a smaller, more efficient sparse index for querying, while data deduplication occurs on `id`, ensuring no data is lost.
**NOTE:** Unlike in Postgres, where the `PRIMARY KEY` is a B-tree index that guarantees uniqueness, in ClickHouse, it does not ensure uniqueness. Instead, it defines the columns that should be part of the sparse index.
### Modifying the Ordering Key
Choosing the right [ordering key](https://clickhouse.com/docs/en/migrations/postgresql/designing-schemas#primary-ordering-keys-in-clickhouse) is crucial for query performance in ClickHouse, as it acts as an index when querying data. By default, PeerDB uses the PostgreSQL `PRIMARY KEY` to define the ordering key in ClickHouse tables, but you can change it using the following methods:
### Use materialized views
You can use materialized views to create a new table with a different ordering key suitable for your workload. Include the primary key columns at the end of the ordering key to ensure proper deduplication, as ReplacingMergeTree uses the ORDER BY clause for deduplication, and including the primary key ensures that no data is lost.
```sql theme={null}
CREATE MATERIALIZED VIEW goals_mv
ENGINE = ReplacingMergeTree(_peerdb_version)
ORDER BY (enabled, ts, id) POPULATE AS
SELECT * FROM peerdb.public_goals;
```
**NOTE:** After creating the materialized view, be sure to follow the steps described in the previous section on handling duplicates to ensure proper deduplication during query time.
### Predefine target tables with the desired Ordering Key
To change the ordering key, you can predefine new tables with your desired Ordering Key and then swap them with the existing tables. Here's how you can do it:
**1. Create a Dummy Mirror:** Create a dummy mirror in PeerDB to generate the default tables with the correct metadata columns and data types.
**2. Create a New Table with the Desired Ordering Key:** Use the table created by PeerDB to define a new table with your desired ordering key. Include the primary key columns at the end of the ordering key to ensure proper deduplication. Here is an example:
```sql theme={null}
CREATE TABLE public_events_new AS public_events
ENGINE = ReplacingMergeTree(_peerdb_version)
ORDER BY (user_id,id);
```
**3. Drop the Old Table:**
```sql theme={null}
DROP TABLE public_events;
```
**4. Rename the New Table:** Rename the new table to the actual table
```sql theme={null}
RENAME TABLE public_events_new TO public_events;
```
**5. Start MIRROR to Point to the New Table:** Configure the mirror to point to the actual table. PeerDB uses `CREATE TABLE IF NOT EXISTS` behind the scenes and continues to ingest data into the new table.
## Handling DELETEs
As mentioned, DELETEs from PostgreSQL are propagated as new rows marked as deleted (using the `_peerdb_is_deleted` column). To exclude deleted rows from your queries, you can create row-level policies in ClickHouse based on the `_peerdb_is_deleted` column. Here’s an example:
```sql theme={null}
CREATE ROW POLICY policy_name ON table_name
FOR SELECT USING _peerdb_is_deleted = 0;
```
This policy ensures that only rows where `_peerdb_is_deleted` is 0 are visible when querying the table.
## How to handle updates for primary keys?
To propagate primary key updates into ClickHouse, enable `PEERDB_CLICKHOUSE_ENABLE_PRIMARY_UPDATE` setting on your mirror. This instructs the PeerDB normalize step to generate a “delete + insert” pair for changed primary keys, using a sign column (in the `ReplacingMergeTree`) and a version column to remove the old record before inserting the new one, ensuring that your ClickHouse tables accurately reflect the latest state from the source system. It is highly uncommon for primary keys to be updated in Postgres.
## Conclusion
I hope you enjoyed reading the guide. We aimed to cover the most common data-modeling challenges you might encounter when migrating from PostgreSQL to ClickHouse. In the next blog, I plan to dive into more advanced topics, such as joins, writing efficient SQL queries, and so on. If you want to give PeerDB and ClickHouse a try to start replicating data from Postgres to ClickHouse, please check out the links below or reach out to us directly!
1. [Try PeerDB Cloud for Free](https://auth.peerdb.cloud/signup)
2. [Try ClickHouse Cloud for Free](https://clickhouse.com/docs/en/cloud-quick-start)
3. [Talk to the PeerDB team directly](https://www.peerdb.io/sign-up)
# Postgres to ClickHouse: Handling TOAST Columns
Source: https://docs.peerdb.io/bestpractices/clickhouse_toast_columns
When replicating data from PostgreSQL to ClickHouse, it's important to understand the limitations and special considerations for TOAST (The Oversized-Attribute Storage Technique) columns. This guide will help you identify and properly handle TOAST columns in your replication process.
## What are TOAST columns in PostgreSQL?
TOAST (The Oversized-Attribute Storage Technique) is PostgreSQL's mechanism for handling large field values. When a row exceeds the maximum row size (typically 2KB, but this can vary depending on the PostgreSQL version and exact settings), PostgreSQL automatically moves large field values into a separate TOAST table, storing only a pointer in the main table.
It's important to note that during Change Data Capture (CDC), unchanged TOAST columns are not included in the replication stream. This can lead to incomplete data replication if not handled properly.
During the initial load (snapshot), all column values, including TOAST columns, will be replicated correctly regardless of their size. The limitations described in this guide primarily affect the ongoing CDC process after the initial load.
You can read more about TOAST and its implementation in PostgreSQL here: [https://www.postgresql.org/docs/current/storage-toast.html](https://www.postgresql.org/docs/current/storage-toast.html)
## Identifying TOAST columns in a table
To identify if a table has TOAST columns, you can use the following SQL query:
```sql theme={null}
SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod) as data_type
FROM pg_attribute a
JOIN pg_class c ON a.attrelid = c.oid
WHERE c.relname = 'your_table_name'
AND a.attlen = -1
AND a.attstorage != 'p'
AND a.attnum > 0;
```
This query will return the names and data types of columns that could potentially be TOASTed. However, it's important to note that this query only identifies columns that are eligible for TOAST storage based on their data type and storage attributes. To determine if these columns actually contain TOASTed data, you'll need to consider whether the values in these columns exceed the size. The actual TOASTing of data depends on the specific content stored in these columns.
## Ensuring proper handling of TOAST columns
To ensure that TOAST columns are handled correctly during replication, you should set the `REPLICA IDENTITY` of the table to `FULL`. This tells PostgreSQL to include the full old row in the WAL for UPDATE and DELETE operations, ensuring that all column values (including TOAST columns) are available for replication.
You can set the `REPLICA IDENTITY` to `FULL` using the following SQL command:
```sql theme={null}
ALTER TABLE your_table_name REPLICA IDENTITY FULL;
```
Refer to [this blog post](https://xata.io/blog/replica-identity-full-performance) for performance considerations when setting `REPLICA IDENTITY FULL`.
## Replication behavior when REPLICA IDENTITY FULL is not set
If `REPLICA IDENTITY FULL` is not set for a table with TOAST columns, you may encounter the following issues when replicating to ClickHouse:
1. For INSERT operations, all columns (including TOAST columns) will be replicated correctly.
2. For UPDATE operations:
* If a TOAST column is not modified, its value will appear as NULL or empty in ClickHouse.
* If a TOAST column is modified, it will be replicated correctly.
3. For DELETE operations, TOAST column values will appear as NULL or empty in ClickHouse.
These behaviors can lead to data inconsistencies between your PostgreSQL source and ClickHouse destination. Therefore, it's crucial to set `REPLICA IDENTITY FULL` for tables with TOAST columns to ensure accurate and complete data replication.
## Conclusion
Properly handling TOAST columns is essential for maintaining data integrity when replicating from PostgreSQL to ClickHouse. By identifying TOAST columns and setting the appropriate `REPLICA IDENTITY`, you can ensure that your data is replicated accurately and completely.
# Generated Columns: Gotchas and Best Practices
Source: https://docs.peerdb.io/bestpractices/generated_columns
When using PostgreSQL's generated columns in tables that are being replicated, there are some important considerations to keep in mind. These gotchas can affect the replication process and data consistency in your destination systems.
## The Problem with Generated Columns
1. **Not Published via pgoutput:** Generated columns are not published through the pgoutput logical replication plugin. This means that when you're replicating data from PostgreSQL to another system, the values of generated columns are not included in the replication stream.
2. **Issues with Primary Keys:** If a generated column is part of your primary key, it can cause deduplication problems on the destination. Since the generated column values are not replicated, the destination system won't have the necessary information to properly identify and deduplicate rows.
## Best Practices
To work around these limitations, consider the following best practices:
1. **Recreate Generated Columns on the Destination:** Instead of relying on the replication process to handle generated columns, it's recommended to recreate these columns on the destination using tools like dbt (data build tool) or other data transformation mechanisms.
2. **Avoid Using Generated Columns in Primary Keys:** When designing tables that will be replicated, it's best to avoid including generated columns as part of the primary key.
## Upcoming improvements to UI
In upcoming versions, we are planning to add a UI to help users with the following:
1. **Identify Tables with Generated Columns:** The UI will have a feature to identify tables that contain generated columns. This will help users understand which tables are affected by this issue.
2. **Documentation and Best Practices:** The UI will include best practices for using generated columns in replicated tables, including guidance on how to avoid common pitfalls.
# Heartbeat Table For CDC
Source: https://docs.peerdb.io/bestpractices/heartbeat
**Disclaimer**: The below guide is more relevant if you are using read replicas or your Postgres instance is below Postgres 14.
For primary Postgres instances of versions 14 and above, PeerDB now has inbuilt functionality to mitigate slot growth by default.
Consider a scenario where you kick off a CDC mirror from PostgreSQL to a data warehouse to sync one table. The mirror creates a logical replication slot in PostgreSQL to stream changes.
Now, this table rarely gets rows ingested to it on the source. However, the replication slot keeps growing because of the WAL logs generated by the changes in other tables. This can lead to the database disk getting filled up.
This is common in development or staging environments where the database is not used heavily.
In order to mitigate this, you can create a `heartbeat` table in the source database.
## Creating a `heartbeat` table on Postgres
This table will have a single row that gets updated every minute.
By including this table in the CDC mirror, PeerDB will pick up changes to this table, sync them and flush the slot periodically, keeping the slot size in check.
The below is an example of what we're talking about. Ensure that the heartbeat table has [required permissions](/connect/postgres/rds_postgres#creating-peerdb-user-and-granting-permissions) to be a part of the mirror.
```sql theme={null}
CREATE TABLE _peerdb_heartbeat (
id SERIAL PRIMARY KEY,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO _peerdb_heartbeat DEFAULT VALUES;
-- Update the row every minute (this can be done with, say, pg_cron)
UPDATE _peerdb_heartbeat SET last_updated = CURRENT_TIMESTAMP;
```
### PeerDB Implementation
PeerDB has the facility to perform periodic updates on your heartbeat table.
This has the benefit of not needing to install an extension like pg\_cron.
Currently, updates are done every 12 minutes. This will soon be configurable.
PeerDB will require update permission on the heartbeat table:
```sql theme={null}
GRANT UPDATE ON _peerdb_heartbeat TO ;
```
In PeerDB UI, head over to `Settings` in the sidebar. Search for `WAL` in the search bar on the right.
Edit the current value fields of the following settings:
* `PEERDB_ENABLE_WAL_HEARTBEAT`: Set this to `true` (no quotes or anything)
* `PEERDB_WAL_HEARTBEAT_QUERY`: Set this to the update command to be run periodically:
```sql theme={null}
UPDATE _peerdb_heartbeat SET last_updated = CURRENT_TIMESTAMP;
```
This sets up updates to the heartbeat table every 12 minutes.
### Manual Implementation
Periodic update can also be done with the below pg\_cron command, for example:
```sql theme={null}
-- updates every 30 seconds
SELECT cron.schedule('*/30 * * * *', $$UPDATE _peerdb_heartbeat SET last_updated = CURRENT_TIMESTAMP$$);
```
## Include the heartbeat table in the mirror
Now, you can include it as part of the tables in the mirror either via the Create Mirror UI or through the SQL Layer as shown below.
```sql theme={null}
CREATE MIRROR heartbeat_mirror
FROM postgres_peer TO warehouse_peer
WITH TABLE MAPPING (
public._peerdb_heartbeat: _peerdb_heartbeat_target,
-- other tables
)
WITH(
...
);
```
For an existing mirror, the [mirror can be edited](/features/edit-mirror) to add this table.
# Defining the Ordering Key in ClickHouse differently from the Primary Key in Postgres
Source: https://docs.peerdb.io/bestpractices/ordering-key-different
PeerDB is now natively integrated with ClickHouse Cloud!
We recently announced the Postgres CDC connector in ClickPipes, now available in Public Preview.
This connector is fully powered by PeerDB.
As a ClickHouse Cloud customer, you get a seamless, native experience for moving data from your Postgres databases to ClickHouse Cloud. Simply navigate to the **Data Sources** tab and add a Postgres source to start ingesting data.
Deduplication inconsistencies in ReplacingMergeTree could occur when the Ordering Key in ClickHouse differs from the Primary Key in Postgres. In ClickHouse, the Ordering Key defines: a) the skip index and data order on disk, and b) the deduplication key - group of columns on which data de-duplication occurs.
Users might select an Ordering Key that differs from the Primary Key in Postgres to optimize query performance, without realizing that this choice can lead to deduplication inconsistencies in the data. Below are scenarios where deduplication can go wrong:
* **UPDATE on an Ordering Key Column:** For a row, if a column in the Ordering Key is updated, PeerDB replicates the latest version of that row from Postgres, as Postgres logical replication provides only the latest version by default. ClickHouse does not deduplicate this row with the previous version because the Ordering Key value has changed and is distinct from the previous version. This results in an additional row in ClickHouse compared to Postgres.
* **DELETEs:** If you delete a row, PeerDB replicates the deleted row with null values in all columns (including those in the Ordering Key) except for the Primary Key. This occurs because Postgres logical replication only provides the value of the Primary Key column for the row being deleted. As a result, ClickHouse does not deduplicate the existing row with the new row marked as deleted (soft delete), since the Ordering Key column values of the incoming deleted row are different from those of the existing row. This again results in an additional row in ClickHouse compared to Postgres.
### Prerequisites for the Ordering Key in ClickHouse to differ from the Primary Key in Postgres
If you follow the steps below, there will be no deduplication inconsistencies, even if you define an Ordering Key in ClickHouse that differs from the Primary Key in Postgres:
1. **Primary Key in PG should be a suffix to the Ordering Key in Clickhouse:** Ensure that the Primary Key in Postgres is a suffix to the Ordering Key in ClickHouse. This is essential for accurate deduplication, as the Primary Key in Postgres represents the lowest granularity for a row. Defining an Ordering Key without the Primary Key can lead to lost rows.
2. **Define REPLICA IDENTITY as FULL or UNIQUE INDEX:** If you define the REPLICA IDENTITY of a table as FULL or as a UNIQUE INDEX on the columns in the Ordering Key, Postgres logical replication provides both the older and newer versions of the row, with the Ordering Key column values populated. This enables PeerDB to accurately handle the scenarios of updating an Ordering Key column and deletions.
To ensure accurate de-duplication, PeerDB internally treats the update as a DELETE of the old row and an INSERT of the new row, allowing ClickHouse to manage deduplication correctly. Similarly, for deletions, PeerDB marks the older row with the appropriate Ordering Key columns as deleted, ensuring accurate deduplication.
To Define REPLICA IDENTITY FULL, you could run the below command:
```sql theme={null}
ALTER TABLE table_name REPLICA IDENTITY FULL;
```
**Impact of REPLICA IDENTITY FULL**:
[This](https://xata.io/blog/replica-identity-full-performance) is a great blog regarding the impact on your instance if you define REPLICA IDENTITY FULL. **TL;DR** the impact from REPLICA IDENTITY FULL will likely be manageable as long as the replicated tables have a primary key!
**OR**
To define REPLICA IDENTITY using a UNIQUE INDEX, you can use the following commands:
```sql theme={null}
-- Create an index on the Ordering Key columns if it doesn't exist
CREATE UNIQUE INDEX orderingkey_index ON
table_name (ordering_key_column1, ordering_key_column2, ...);
-- Create index on the Ordering Key Column if it doesnt exists
ALTER TABLE table_name REPLICA IDENTITY USING
INDEX orderingkey_index;
```
# Upgrading the PostgreSQL Peer Of An Ongoing CDC Mirror
Source: https://docs.peerdb.io/bestpractices/postgres-upgrade
This is a guide on how you can upgrade your PostgreSQL instance that is part of an ongoing CDC mirror.
For PeerDB Cloud users: Note that one of the steps below requires the intervention of [PeerDB support](https://slack.peerdb.io).
## Steps
1. Create a dummy table, and [add the table to all mirrors](/features/edit-mirror#adding-tables)
```sql theme={null}
CREATE TABLE _peerdb_heartbeat (
id SERIAL PRIMARY KEY,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
2. Make sure ALL writes to the database stop. In other words, put the application in maintenance/downtime.
3. Add a row to the dummy table using :
```sql theme={null}
INSERT INTO _peerdb_heartbeat DEFAULT VALUES;
```
4. Wait for PeerDB to catch up. You can check the syncs of the mirrors in PeerDB UI in the **Overview** tab.
5. [Pause](/features/pause-mirror) all mirrors.
6. Save the name of your replication slot before dropping it, then upgrade your PostgreSQL instance.
7. **If you are using PeerDB OSS**:
Set the `last_offset` field of the mirrors to 0 in the `metadata_last_sync_state` table in the `catalog` Postgres container.
You can `psql` into that container and run :
```sql theme={null}
UPDATE metadata_last_sync_state SET last_offset = 0 WHERE job_name = ;
```
for every mirror which has this Postgres instance as its source peer.
**If you are using PeerDB Cloud**: Contact PeerDB Support on [PeerDB Slack](https://slack.peerdb.io).
8. After the upgrade is complete, create new logical replication slots for the mirrors.
It is very important that the name of these slots are the same as the previous slots which the mirrors were using.
If PeerDB created the replication slot of a mirror, then the slot name will be `peerflow_slot_`.
If you provided the replication slot name, then you should use that name (as stored earlier in step 6).
```sql theme={null}
-- If PeerDB created the replication slot:
SELECT pg_create_logical_replication_slot('peerflow_slot_', 'pgoutput');
-- If you provided the replication slot name:
SELECT pg_create_logical_replication_slot('', 'pgoutput');
```
9. Resume all mirrors.
10. Remove application from maintenance.
11. Check if the mirrors are syncing correctly.
# BigQuery Setup Guide
Source: https://docs.peerdb.io/connect/bigquery
BigQuery as a **destination** is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination. Note that BigQuery remains a **supported source**.
1. [Create a dedicated Service Account](https://cloud.google.com/iam/docs/keys-create-delete#iam-service-account-keys-create-console) for PeerDB through Google Cloud Console and specify `BigQuery Data Editor`, `BigQuery Data Viewer`, `BigQuery Job User`, `BigQuery Resource Viewer`
2. Add a key to the above created service account
3. Create a dataset dedicated to PeerDB with the name you prefer.
4. Using this service account key create the peer using PeerDB UI
# ClickHouse Setup Guide
Source: https://docs.peerdb.io/connect/clickhouse/clickhouse
PeerDB is now natively integrated with ClickHouse Cloud!
We recently announced the Postgres CDC connector in ClickPipes, now available in Public Preview.
This connector is fully powered by PeerDB.
As a ClickHouse Cloud customer, you get a seamless, native experience for moving data from your Postgres databases to ClickHouse Cloud. Simply navigate to the **Data Sources** tab and add a Postgres source to start ingesting data.
This is a document on setting a Clickhouse peer for PeerDB. PeerDB supports ClickHouse as a target for data replication.
### Steps on setting up the ClickHouse peer
1. Create a separate database for the ClickHouse peer called peerdb. This is where tables will be auto-created and synced by PeerDB.
```sql theme={null}
CREATE DATABASE peerdb;
```
Or if you have a ClickHouse cluster
```sql theme={null}
CREATE DATABASE peerdb ON CLUSTER '{cluster}' ENGINE = Replicated('/clickhouse/databases/peerdb/{uuid}/', '{replica}');
```
2. Create a Clickhouse user for PeerDB with the following permissions:
```sql theme={null}
-- We recommend creating a separate user for PeerDB
CREATE USER peerdb_user IDENTIFIED BY '';
-- PeerDB needs to create tables and insert data into the tables.
-- Drop table permission is needed for DROP MIRROR support
GRANT INSERT, SELECT, DROP, CREATE TABLE ON peerdb.* to peerdb_user;
-- PeerDB uses an intermediary S3 stage for performance
GRANT CREATE TEMPORARY TABLE, s3 on *.* to peerdb_user;
-- For automatic column-addition on the tables in the mirror
GRANT ALTER ADD COLUMN ON peerdb.* to peerdb_user;
```
on ClickHouse cluster
```sql theme={null}
CREATE USER peerdb_user IDENTIFIED BY '' ON CLUSTER '{cluster}';
GRANT INSERT, SELECT, DROP, CREATE TABLE ON peerdb.* to peerdb_user ON CLUSTER '{cluster}';
GRANT CREATE TEMPORARY TABLE, s3 on *.* to peerdb_user ON CLUSTER '{cluster}';
GRANT ALTER ADD COLUMN ON peerdb.* to peerdb_user ON CLUSTER '{cluster}';
```
When selecting the ReplicatedReplacingMergeTree/ReplicatedMergeTree table engine you need change [default settings](https://clickhouse.com/docs/operations/settings/settings#database_replicated_allow_replicated_engine_arguments).
```
2
```
If you need to whitelist PeerDB IPs in Clickhouse Cloud, you can find the IPs of your PeerDB instance [here](/peerdb-cloud/ip-table).
3. ClickHouse has several ports exposed, and PeerDB requires to use a port that exposes the `ClickHouse native protocol` which by default is `9440` for the secure TLS-enabled port and `9000` for the non-TLS port. If the default ports have been changed, please adjust them accordingly.
We do not recommend using the non-TLS enabled port for ClickHouse. If this is needed, please also check the `Disable TLS?` option.
4. If you are using PeerDB OSS, we use [MinIO](https://min.io/) as the internal transient stage. You might need to adjust your firewall rules to allow connections from ClickHouse to MinIO. In [PeerDB Cloud](https://app.peerdb.cloud/), we abstract all of this from you. If you run into issues, please reach out to [support@peerdb.io](mailto:support@peerdb.io) or join our Slack [channel](https://slack.peerdb.io).
5. Create the ClickHouse Peer through PeerDB UI
Enter all the details `Name`, `Host`, `Port` (as determined above), `User`, `Password` and `Database`.
6. Click on `Validate` to ensure that the connection is successful.
7. Click on `Create` to create the ClickHouse Peer.
### Troubleshooting
Here is a list of some validation errors that you might encounter and how to resolve them:
**You may need to disable TLS**
You may need to disable TLS. Validation errors such as the following may occur if the connection is not successful:
```
failed to ping to Clickhouse peer: tls:
first record does not look like a TLS handshake
```
**EOF**
If you see the following error, it means that the connection to the ClickHouse peer could not be established:
```
failed to open connection to Clickhouse peer:
failed to ping to Clickhouse peer: EOF
```
Please try the following:
1. Ensure that the PeerDB IP is whitelisted in the ClickHouse server. If you are using PeerDB Cloud, you can find the IPs of your PeerDB instance [here](/peerdb-cloud/ip-table).
2. You may need to enable TLS.
**Stuck on Validating...**
This means the port entered is incorrect. Please ensure that the port is correct and the ClickHouse server is reachable from the PeerDB server.
# ClickHouse Cloud Setup Guide
Source: https://docs.peerdb.io/connect/clickhouse/clickhouse-cloud
PeerDB is now natively integrated with ClickHouse Cloud!
We recently announced the Postgres CDC connector in ClickPipes, now available in Public Preview.
This connector is fully powered by PeerDB.
As a ClickHouse Cloud customer, you get a seamless, native experience for moving data from your Postgres databases to ClickHouse Cloud. Simply navigate to the **Data Sources** tab and add a Postgres source to start ingesting data.
This is a document on setting a [Clickhouse Cloud](https://clickhouse.com/cloud) peer for PeerDB.
If you are using ClickHouse Cloud, we recommend using [PeerDB Cloud](https://app.peerdb.cloud/), which comes with free trial and highly competitive pricing and PeerDB Cloud is specifically designed for ClickHouse Cloud.
### Steps on setting up the ClickHouse Cloud peer
Head over the **SQL Console** in the ClickHouse Cloud UI.
#### Permissions
1. Create a separate database for the ClickHouse peer called peerdb. This is where tables will be auto-created and synced by PeerDB.
```sql theme={null}
CREATE DATABASE peerdb;
```
2. Create a Clickhouse user for PeerDB with the following permissions:
```sql theme={null}
-- We recommend creating a separate user for PeerDB
CREATE USER peerdb_user IDENTIFIED BY '';
-- PeerDB needs to create tables and insert data into the tables.
-- Drop table permission is needed for DROP MIRROR support
GRANT INSERT, SELECT, DROP, CREATE TABLE ON peerdb.* to peerdb_user;
-- PeerDB uses an intermediary S3 stage for performance
GRANT CREATE TEMPORARY TABLE, s3 on *.* to peerdb_user;
-- For automatic column-addition on the tables in the mirror
GRANT ALTER ADD COLUMN ON peerdb.* to peerdb_user;
```
#### Whitelist PeerDB Cloud IPs
If you are using PeerDB Cloud, you need to whitelist the PeerDB Cloud IPs in the ClickHouse Cloud settings tab.
You can find the IPs of your PeerDB instance [here](/peerdb-cloud/ip-table).
3. ClickHouse has several ports exposed, and PeerDB requires to use a port that exposes the `ClickHouse native protocol` which by default is `9440` for the secure TLS-enabled port and `9000` for the non-TLS port. If the default ports have been changed, please adjust them accordingly.
We do not recommend using the non-TLS enabled port for ClickHouse. If this is needed, please also check the `Disable TLS?` option when creating the Clickhouse peer (as seen below).
4. If you are using [PeerDB OSS](https://github.com/PeerDB-io/peerdb), we use [MinIO](https://min.io/) as the internal transient stage. You might need to adjust your firewall rules to **allow connections from ClickHouse to MinIO**.
In [PeerDB Cloud](https://app.peerdb.cloud/), we abstract all of this from you. If you run into issues, please reach out to [support@peerdb.io](mailto:support@peerdb.io) or join our Slack [channel](https://slack.peerdb.io).
5. Create the ClickHouse Peer through PeerDB UI
Enter all the details `Name`, `Host`, `Port` (as determined above), `User`, `Password` and `Database`.
6. Click on `Validate` to ensure that the connection is successful.
7. Click on `Create` to create the ClickHouse Peer.
### Troubleshooting
Here is a list of some validation errors that you might encounter and how to resolve them:
**You may need to disable TLS**
You may need to disable TLS. Validation errors such as the following may occur if the connection is not successful:
```
failed to ping to Clickhouse peer: tls:
first record does not look like a TLS handshake
```
**EOF**
If you see the following error, it means that the connection to the ClickHouse peer could not be established:
```
failed to open connection to Clickhouse peer:
failed to ping to Clickhouse peer: EOF
```
Please try the following:
1. Ensure that the PeerDB IP is whitelisted in the ClickHouse server. If you are using PeerDB Cloud, you can find the IPs of your PeerDB instance [here](/peerdb-cloud/ip-table).
2. You may need to enable TLS.
**Stuck on Validating...**
This means the port entered is incorrect. Please ensure that the port is correct and the ClickHouse server is reachable from the PeerDB server.
# CockroachDB Source Setup Guide
Source: https://docs.peerdb.io/connect/cockroachdb
This is a guide on how to set up a CockroachDB peer which you can use as a source for replication in PeerDB. It applies to self-hosted CockroachDB as well as CockroachDB Cloud.
## Supported CockroachDB versions
PeerDB's test suite runs against CockroachDB v24.1, v25.4 (LTS) and v26.2. Older versions may work but are not tested. Snapshot timestamp protection (described below) requires v24.1 or later.
Let's create a dedicated user for PeerDB with the necessary permissions. Connect to your CockroachDB cluster and run the following SQL commands:
1. Create a dedicated user for PeerDB:
```sql theme={null}
CREATE USER peerdb_user WITH PASSWORD 'some-password';
```
2. Grant read access on the tables you want to replicate. The following example shows permissions for the `public` schema. Repeat these commands for each schema containing tables you want to replicate:
```sql theme={null}
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
```
3. If you plan to use Change Data Capture (CDC), also grant the `CHANGEFEED` privilege on the tables you want to replicate:
```sql theme={null}
GRANT CHANGEFEED ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
```
4. Mirror validation reads cluster settings to check that rangefeeds are enabled, which requires the `VIEWCLUSTERSETTING` privilege:
```sql theme={null}
GRANT SYSTEM VIEWCLUSTERSETTING TO peerdb_user;
```
5. Optionally, grant `REPLICATION` so PeerDB can protect the initial snapshot's timestamp from garbage collection during long loads (see [snapshot timestamp protection](#snapshot-timestamp-protection)). Without it, PeerDB logs a warning and the snapshot relies on `gc.ttlseconds` alone:
```sql theme={null}
GRANT SYSTEM REPLICATION TO peerdb_user;
```
On insecure (non-TLS) clusters, the `root` user can connect without a password. In that case you can leave the password empty when creating the peer.
PeerDB performs CDC from CockroachDB using [changefeeds](https://www.cockroachlabs.com/docs/stable/change-data-capture-overview), which require rangefeeds to be enabled on the cluster. See the [changefeed prerequisites](https://www.cockroachlabs.com/docs/stable/create-and-configure-changefeeds) in the CockroachDB docs for details.
1. On self-hosted CockroachDB, enable rangefeeds by running:
```sql theme={null}
SET CLUSTER SETTING kv.rangefeed.enabled = true;
```
This requires the `admin` role or the `MODIFYCLUSTERSETTING` privilege.
2. On CockroachDB Cloud Standard and Basic clusters, rangefeeds are enabled by default and no action is needed.
Mirror validation fails with an explanatory error if rangefeeds are disabled and the mirror does CDC.
CockroachDB garbage-collects old row versions after the interval configured by the [`gc.ttlseconds`](https://www.cockroachlabs.com/docs/stable/configure-replication-zones#gc-ttlseconds) zone variable. PeerDB's changefeed cursor can only resume from a timestamp that has not yet been garbage collected. If PeerDB is down for longer than `gc.ttlseconds`, the cursor expires and the mirror needs a resync. The same window bounds the initial snapshot, which reads all tables `AS OF SYSTEM TIME` at one fixed timestamp.
Mirror validation requires an effective `gc.ttlseconds` of at least 24 hours (86400 seconds) on every replicated table. The effective value is the minimum across the table's zone configuration and any partition zone configurations, since a partition-level setting overrides the table's. When validation fails, the error message names the table or partition and includes the exact `CONFIGURE ZONE` statement to raise the setting. For example, to allow up to 48 hours:
```sql theme={null}
ALTER TABLE my_table CONFIGURE ZONE USING gc.ttlseconds = 172800;
```
See the [CockroachDB docs](https://www.cockroachlabs.com/docs/stable/configure-replication-zones#gc-ttlseconds) for default values, which differ between self-hosted and CockroachDB Cloud cluster types. On cluster types whose default is below 24 hours, raise the zone configuration for the replicated tables before creating the mirror.
Increasing `gc.ttlseconds` causes CockroachDB to retain more row versions, which increases storage usage and can slow down reads on frequently updated tables. Pick a value that covers your expected downtime while accounting for these costs.
TLS is enabled by default for CockroachDB peers. CockroachDB Cloud clusters and secure self-hosted clusters require it.
1. If your cluster's certificate is not signed by a publicly trusted certificate authority, provide the cluster's root CA certificate (`root_ca`). For CockroachDB Cloud, you can download the CA certificate from the cluster's **Connect** dialog in the Cloud Console.
2. If you connect through a load balancer or tunnel where the hostname you dial differs from the hostname in the server certificate, set **TLS Hostname** (`tls_host`) to the certificate's hostname.
3. For certificate-based client authentication, provide a client certificate and private key (`client_tls`).
4. For insecure self-hosted clusters, turn on **Disable TLS?** (`disable_tls`).
`skip_cert_verification` disables server certificate verification and should only be used for testing.
You can create the CockroachDB peer through the PeerDB UI or via SQL.
**Using the UI:**
1. Head over to the PeerDB UI and click on **Create Peer**. Select **CockroachDB** as the source.
2. Fill in the connection details of your CockroachDB cluster, using the user you created earlier. The default port is `26257`.
3. For TLS clusters, provide the **Root Certificate** if needed. For insecure clusters, turn on **Disable TLS?**.
4. To connect through an SSH tunnel, turn on **Configure SSH Tunnel** and fill in the SSH host, port, user and credentials.
5. Click on **Validate** and once that's green, you can go ahead and click on **Create** to create the peer!
**Using SQL:**
```sql theme={null}
CREATE PEER cockroachdb_peer FROM COCKROACHDB WITH
(
host = '',
port = '26257',
user = 'peerdb_user',
password = '',
database = '',
root_ca = ''
);
```
See [Creating Peers](/sql/commands/create-peer#cockroachdb-peer) for the full list of options.
## How replication works
CDC is the recommended mirror type for CockroachDB sources. A CDC mirror runs in two phases:
1. **Initial snapshot.** PeerDB captures a cluster logical timestamp and reads table data in consistent partitioned chunks using `AS OF SYSTEM TIME` queries at that timestamp, with watermark-based partitioning.
2. **Change streaming.** A sinkless changefeed then streams changes starting from that same timestamp, so the snapshot and the change stream line up exactly. Resolved timestamps from the changefeed drive checkpointing, so PeerDB can resume from where it left off after a restart.
### Delivery semantics
Delivery is at least once. Each sync cycle resumes the changefeed from the last checkpointed resolved timestamp, so a bounded window of already-delivered events can be re-delivered, both between sync cycles and after restarts. ClickHouse destination tables use the ReplacingMergeTree engine with a version column, so re-delivered rows collapse to a single row on merge.
### Snapshot timestamp protection
While the initial snapshot runs, PeerDB automatically attempts to protect the snapshot timestamp from garbage collection. The protection is refreshed periodically while the snapshot runs, released when the initial load completes, and expires on its own after a bounded window as a safety guard.
Protection requires CockroachDB v24.1 or later, the `REPLICATION` privilege for the PeerDB user, and on v26.1 or later the `allow_unsafe_internals` session setting or its cluster-wide override. If protection cannot be engaged, PeerDB logs a warning and proceeds; the initial load then relies on `gc.ttlseconds` alone.
## Monitoring
The CockroachDB connector emits the following metrics through PeerDB's [OpenTelemetry metrics](/metrics/native-metrics), with the standard flow name attributes:
| Metric | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------- |
| `cockroachdb_resolved_lag` | How many seconds the changefeed's resolved timestamp trails the current wall clock time. |
| `cockroachdb_records_received` | Counter of changefeed data records received on the CDC pull path. |
## Connecting through a proxy
Connection proxies with short idle timeouts (for example, haproxy defaults to around 30 seconds) can drop idle PeerDB connections between sync cycles. PeerDB reconnects automatically, but raising the proxy's idle timeout reduces reconnect noise in the logs.
## Limitations
1. Newly added columns are detected from changefeed data and propagated to the destination. Column drops, renames and type changes are not replicated and require a resync of the mirror.
2. `TRUNCATE` or `DROP` of a replicated table stops the mirror with a terminal error; recreate or resync the mirror afterwards.
3. Changefeeds with webhook or Kafka sinks are not supported; PeerDB only uses sinkless changefeeds.
4. If PeerDB is down for longer than the table's effective `gc.ttlseconds`, the changefeed cursor expires and the mirror needs a resync.
# Confluent Cloud Setup Guide
Source: https://docs.peerdb.io/connect/confluent-cloud
Kafka as a destination (including the Confluent and Redpanda variants) is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
# Prerequisites
To connect Confluent Cloud to PeerDB, you need a Confluent Cloud account with Kafka Server running.
# Setup Instructions
## Gather the following details from Confluent Cloud
```toml theme={null}
bootstrap.servers=:9092
security.protocol=SASL_SSL
sasl.mechanisms=PLAIN
sasl.username={{ CLUSTER_API_KEY }}
sasl.password={{ CLUSTER_API_SECRET }}
```
## Create the Kafka Peer
And then in UI you can create the Confluent Cloud / Kafka peer like so:
1. Click on `Create Peer`
2. Select `Kafka`
3. For `Name` use a desired name, e.g. `confluent_kafka_1`, only lowercase alphanumeric and underscores are allowed.
4. For `Bootstrap Servers` use the `bootstrap.servers` value from the previous step. Multiple servers can be specified as a comma separated list.
5. For `Security Protocol` use `SASL_SSL`.
6. For `SASL Mechanism` use `PLAIN`.
7. For `Username` use the `CLUSTER_API_KEY` from the previous step.
8. For `Password` use the `CLUSTER_API_SECRET` from the previous step.
9. Click `Validate Connection`
10. Click `Create Peer`
PeerDB only supports plaintext and SASL authentication. If username isn't supplied then PeerDB will attempt to connect without authentication.
Partitioner can be usually be ignored; it maps to partitioning strategies in [franz-go.](https://pkg.go.dev/github.com/twmb/franz-go/pkg/kgo#Partitioner) To set partitioning keys you'll need to specify `Script` when creating mirror, see [Lua reference](https://docs.peerdb.io/lua/reference) for details.
# Elasticsearch Setup Guide
Source: https://docs.peerdb.io/connect/elasticsearch
Elasticsearch as a destination is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
# Prerequisites
PeerDB can authenticate with Elasticsearch via either basic auth or an API key, or no auth at all. In general, Elasticsearch Cloud authenticates via API keys and self-hosted Elasticsearch can vary. If applicable, atleast the following privileges need to be granted to the PeerDB role: `auto_configure`, `create_doc`, `write`.
## Create the Elasticsearch Peer
1. From the PeerDB home page, click on `Create Peer` and then on `Elasticsearch`.
2. Name the peer as desired, only lowercase alphanumeric and underscores are allowed.
3. The server to connect to should be specified in `Addresses`. Multiple servers can be specified as a comma separated list.
4. Depending on the desired authentication type, choose one of `None`, `Basic Auth` or `API Key` and fill in the required fields.
5. Click `Validate`. If validation succeeds, finish by clicking `Create Peer`.
# GCS Setup Guide
Source: https://docs.peerdb.io/connect/gcs
GCS (a Google Cloud Storage destination) is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
1. Create a new Cloud Storage bucket or ensure an existing bucket is available for use.
2. We need to create an access key pair, for connecting to this bucket. This access key can be on a user account or on a service account. We recommend [creating](https://cloud.google.com/iam/docs/service-accounts-create) a dedicated service account for PeerDB, with the `Storage Object User` role. After this, [create a HMAC key-pair](https://cloud.google.com/storage/docs/authentication/managing-hmackeys) for the service account.
3. In the PeerDB UI, select the Peers menu and select the New Peer option on the top right. Select the peer type as S3 (GCS is very similar to S3 and in PeerDB they share the same menu) and click on continue.
4. Choose a peer name, and fill your bucket URL (with optional prefix, in case you want PeerDB's files to be nested within the bucket), access key and secret access key. Click `Validate` to see if any issues crop up and fix them accordingly. Then click Create peer to finish peer creation.
# Kafka Setup Guide
Source: https://docs.peerdb.io/connect/kafka
Kafka as a destination (including the Confluent and Redpanda variants) is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
If looking to try out without an already setup Kafka endpoint, [see Redpanda quickstart,](https://docs.redpanda.com/current/get-started/quick-start) by default no authentication is necessary.
To get the above redpanda container to work with PeerDB on OSS, you can first add it to the PeerDB containers' network:
```bash theme={null}
# container id of redpanda-0
docker network connect peerdb_network $(docker container ls -qf "name=redpanda-0")
# container id of redpanda-console
docker network connect peerdb_network $(docker container ls -qf "name=redpanda-console")
```
And then in UI you can create the Kafka peer like so:
PeerDB only supports plaintext and SASL authentication. If username isn't supplied then PeerDB will attempt to connect without authentication.
Multiple servers can be specified as a comma separated list.
Partitioner can be usually be ignored; it maps to partitioning strategies in [franz-go.](https://pkg.go.dev/github.com/twmb/franz-go/pkg/kgo#Partitioner) To set partitioning keys you'll need to specify `Script` when creating mirror, see [Lua reference](https://docs.peerdb.io/lua/reference) for details.
# Azure Flexible Server Postgres Source Setup Guide
Source: https://docs.peerdb.io/connect/postgres/azure_flexible_server_postgres
## Supported Postgres versions
Anything on or after Postgres 12
## Enable Logical Replication
**You don't need** to follow the below steps if `wal_level` is set to `logical`. This setting should mostly be pre-configured if you are migrating from another data replication tool.
1. Click on the **Server parameters** section
2. Edit the `wal_level` to `logical`
3. This change would require a server restart. So restart when requested.
## Creating PeerDB User and Granting permissions
Connect to your Azure Flexible Server Postgres through the admin user and run the below commands:
1. Create a dedicated user for PeerDB.
1. ```sql theme={null}
CREATE USER peerdb_user PASSWORD 'some-password';
```
2. Grant schema-level, read-only access to the user you created in the previous step. The following example shows permissions for the `public` schema. Repeat these commands for each schema containing tables you want to replicate:
1. ```sql theme={null}
GRANT USAGE ON SCHEMA "public" TO peerdb_user;
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA "public" GRANT SELECT ON TABLES TO peerdb_user;
```
3. Grant replication privileges to the user:
1. ```sql theme={null}
ALTER USER peerdb_user WITH REPLICATION;
```
4. Create a [publication](https://www.postgresql.org/docs/current/logical-replication-publication.html) with the tables you want to replicate. We strongly recommend only including the tables you need in the publication to avoid performance overhead.
Any table included in the publication must either have a **primary key** defined *or* have its **replica identity** configured to `FULL`.
1. To create a publication for specific tables:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLE table_to_replicate, table_to_replicate2;
```
2. To create a publication for all tables in a specific schema:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLES IN SCHEMA "public";
```
The `peerdb_publication` publication will contain the set of change events generated from the specified tables, and will later be used to create the MIRROR (replication).
5. Set `wal_sender_timeout` to 0 for `peerdb_user`:
```sql theme={null}
ALTER ROLE peerdb_user SET wal_sender_timeout to 0;
```
The PeerDB user must not be restricted by RLS policies, as it can lead to missing data. You can disable RLS policies for the user by running the below command:
```sql theme={null}
ALTER USER peerdb_user BYPASSRLS;
```
## PeerDB SSH Tunneling Guide (Optional)
Sometimes to connect to your Postgres database you may need PeerDB to use an SSH tunnel.
This is typically used when your database is not publicly accessible and you need to connect to it a jump server in your VPC.
This is done by creating an SSH tunnel to your jump server and then connecting to the database through the tunnel. All
of this is handled by PeerDB natively.
Generate a key-pair using the following command:
```bash theme={null}
ssh-keygen -t rsa -b 4096 -C "peerdb-ssh-tunnel" -f peerdb_key.pem
```
This will generate a private key (`peerdb_key.pem`) and a public key (`peerdb_key.pub`).
Add the public key to your jump server. This can be done by adding the public key to the `~/.ssh/authorized_keys` file on the jump server.
```bash theme={null}
# On the jump server
cat peerdb_key.pub >> ~/.ssh/authorized_keys
```
When creating a Postgres peer you can specify the option to use an SSH tunnel. There you will be able to provide the private key you generated in the first step along with the jump server details.
## Add PeerDB Cloud IPs to Firewall
If you are using **PeerDB Cloud**, please follow the below steps to add peerdb ips to your network.
1. Go to the **Networking** tab and add the [public IPs of your PeerDB Cloud instance](/peerdb-cloud/ip-table) to the Firewall
of your Azure Flexible Server Postgres OR the Jump Server/Bastion if you are using SSH tunneling.
## Create Azure Flexible Server Postgres Peer in PeerDB
Through the PeerDB UI, create the Flexible Postgres Peer using the `peerdb_user` that you created in the previous step.
# Google CloudSQL Postgres Source Setup Guide
Source: https://docs.peerdb.io/connect/postgres/cloudsql_postgres
## Supported Postgres versions
Anything on or after Postgres 12
## Enable Logical Replication
**You don't need** to follow the below steps if the settings `cloudsql. logical_decoding` is on and `wal_sender_timeout` is 0. These settings should mostly be pre-configured if you are migrating from another data replication tool.
1. Click on **Edit** button on the Overview page.
2. Go to Flags and change `cloudsql.logical_decoding` to on and `wal_sender_timeout` to 0. These changes will need restarting your Postgres server.
## Creating PeerDB User and Granting permissions
Connect to your CloudSQL Postgres through the admin user and run the below commands:
1. Create a dedicated user for PeerDB:
1. ```sql theme={null}
CREATE USER peerdb_user PASSWORD 'some-password';
```
2. Grant schema-level, read-only access to the user you created in the previous step. The following example shows permissions for the `public` schema. Repeat these commands for each schema containing tables you want to replicate:
1. ```sql theme={null}
GRANT USAGE ON SCHEMA "public" TO peerdb_user;
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA "public" GRANT SELECT ON TABLES TO peerdb_user;
```
3. Grant replication privileges to the user:
1. ```sql theme={null}
ALTER USER peerdb_user WITH REPLICATION;
```
4. Create a [publication](https://www.postgresql.org/docs/current/logical-replication-publication.html) with the tables you want to replicate. We strongly recommend only including the tables you need in the publication to avoid performance overhead.
Any table included in the publication must either have a **primary key** defined *or* have its **replica identity** configured to `FULL`.
1. To create a publication for specific tables:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLE table_to_replicate, table_to_replicate2;
```
2. To create a publication for all tables in a specific schema:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLES IN SCHEMA "public";
```
The `peerdb_publication` publication will contain the set of change events generated from the specified tables, and will later be used to create the MIRROR (replication).
The PeerDB user must not be restricted by RLS policies, as it can lead to missing data. You can disable RLS policies for the user by running the below command:
```sql theme={null}
ALTER USER peerdb_user BYPASSRLS;
```
## PeerDB SSH Tunneling Guide (Optional)
Sometimes to connect to your Postgres database you may need PeerDB to use an SSH tunnel.
This is typically used when your database is not publicly accessible and you need to connect to it a jump server in your VPC.
This is done by creating an SSH tunnel to your jump server and then connecting to the database through the tunnel. All
of this is handled by PeerDB natively.
Generate a key-pair using the following command:
```bash theme={null}
ssh-keygen -t rsa -b 4096 -C "peerdb-ssh-tunnel" -f peerdb_key.pem
```
This will generate a private key (`peerdb_key.pem`) and a public key (`peerdb_key.pub`).
Add the public key to your jump server. This can be done by adding the public key to the `~/.ssh/authorized_keys` file on the jump server.
```bash theme={null}
# On the jump server
cat peerdb_key.pub >> ~/.ssh/authorized_keys
```
When creating a Postgres peer you can specify the option to use an SSH tunnel. There you will be able to provide the private key you generated in the first step along with the jump server details.
## Add PeerDB Cloud IPs to Firewall
If you are using **PeerDB Cloud**, please follow the below steps to add PeerDB IPs to your network.
If your are using SSH Tunnel, then you need to add the PeerDB Cloud IPs to the firewall rules of the Jump Server/Bastion.
1. Go to **Connections** section
2. Go to the Networking subsection
3. Add the [public IPs of your PeerDB Cloud instance](/peerdb-cloud/ip-table)
## Create CloudSQL Postgres Peer in PeerDB
Through the PeerDB UI, create the CloudSQL Peer using the `peerdb_user` that you created in the previous step.
# Crunchy Bridge Postgres Source Setup Guide
Source: https://docs.peerdb.io/connect/postgres/crunchy_bridge
## Enable Logical Replication
Crunchy Bridge comes with logical replication enabled by [default](https://docs.crunchybridge.com/how-to/logical-replication). Ensure that the settings below are configured correctly. If not, adjust them accordingly.
```sql theme={null}
SHOW wal_level; -- should be logical
SHOW max_wal_senders; -- should be 10
SHOW max_replication_slots; -- should be 10
```
## Creating PeerDB User and Granting permissions
Connect to your Crunchy Bridge Postgres through the `postgres` user and run the below commands:
1. Create a dedicated user for PeerDB:
1. ```sql theme={null}
CREATE USER peerdb_user PASSWORD 'some-password';
```
2. Grant schema-level, read-only access to the user you created in the previous step. The following example shows permissions for the `public` schema. Repeat these commands for each schema containing tables you want to replicate:
1. ```sql theme={null}
GRANT USAGE ON SCHEMA "public" TO peerdb_user;
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA "public" GRANT SELECT ON TABLES TO peerdb_user;
```
3. Grant replication privileges to the user:
1. ```sql theme={null}
ALTER USER peerdb_user WITH REPLICATION;
```
4. Create a [publication](https://www.postgresql.org/docs/current/logical-replication-publication.html) with the tables you want to replicate. We strongly recommend only including the tables you need in the publication to avoid performance overhead.
Any table included in the publication must either have a **primary key** defined *or* have its **replica identity** configured to `FULL`.
1. To create a publication for specific tables:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLE table_to_replicate, table_to_replicate2;
```
2. To create a publication for all tables in a specific schema:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLES IN SCHEMA "public";
```
The `peerdb_publication` publication will contain the set of change events generated from the specified tables, and will later be used to create the MIRROR (replication).
The PeerDB user must not be restricted by RLS policies, as it can lead to missing data. You can disable RLS policies for the user by running the below command:
```sql theme={null}
ALTER USER peerdb_user BYPASSRLS;
```
## Safe list PeerDB Cloud IPs
If you are using PeerDB Cloud [safelist the public IPs of your PeerDB Cloud instance](/peerdb-cloud/ip-table) by adding the Firewall Rules in Crunchy Bridge.
## Create Crunchy Bridge Peer in PeerDB
Through the PeerDB UI, create the Crunchy Bridge Postgres Peer using the `peerdb_user` that you created in the previous step.
# Generic PostgreSQL Source Setup Guide
Source: https://docs.peerdb.io/connect/postgres/generic_postgres
This is a guide on how to create a generic PostgreSQL peer which you can use for replication in PeerDB.
If you use one of the supported providers (in the sidebar), please refer to the specific guide for that provider.
1. To enable replication on your PostgreSQL instance, we need to make sure that the following settings are set:
```sql theme={null}
wal_level = logical
```
To check the same, you can run the following SQL command:
```sql theme={null}
SHOW wal_level;
```
The output should be `logical`. If not, run:
```sql theme={null}
ALTER SYSTEM SET wal_level = logical;
```
2. Additionally, the following settings are recommended to be set on the PostgreSQL instance:
```sql theme={null}
max_wal_senders > 1
max_replication_slots >= 4
```
To check the same, you can run the following SQL commands:
```sql theme={null}
SHOW max_wal_senders;
SHOW max_replication_slots;
```
If the values do not match the recommended values, you can run the following SQL commands to set them:
```sql theme={null}
ALTER SYSTEM SET max_wal_senders = 10;
ALTER SYSTEM SET max_replication_slots = 10;
```
3. If you have made any changes to the configuration as mentioned above, you NEED to RESTART the PostgreSQL instance for the changes to take effect.
Let's create a new user for PeerDB with the necessary permissions suitable for CDC,
and also create a publication that we'll use for replication. For this, you can connect to your PostgreSQL instance and run the following SQL commands:
The PeerDB user must not be restricted by RLS policies, as it can lead to missing data. You can disable RLS policies for the user by running the below command:
```sql theme={null}
ALTER USER peerdb_user BYPASSRLS;
```
1. Create a dedicated user for PeerDB:
1. ```sql theme={null}
CREATE USER peerdb_user PASSWORD 'some-password';
```
2. Grant schema-level, read-only access to the user you created in the previous step. The following example shows permissions for the `public` schema. Repeat these commands for each schema containing tables you want to replicate:
1. ```sql theme={null}
GRANT USAGE ON SCHEMA "public" TO peerdb_user;
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA "public" GRANT SELECT ON TABLES TO peerdb_user;
```
3. Grant replication privileges to the user:
1. ```sql theme={null}
ALTER USER peerdb_user WITH REPLICATION;
```
4. Create a [publication](https://www.postgresql.org/docs/current/logical-replication-publication.html) with the tables you want to replicate. We strongly recommend only including the tables you need in the publication to avoid performance overhead.
Any table included in the publication must either have a **primary key** defined *or* have its **replica identity** configured to `FULL`.
1. To create a publication for specific tables:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLE table_to_replicate, table_to_replicate2;
```
2. To create a publication for all tables in a specific schema:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLES IN SCHEMA "public";
```
The `peerdb_publication` publication will contain the set of change events generated from the specified tables, and will later be used to create the MIRROR (replication).
If you are self serving, you need to allow connections to the PeerDB user from the PeerDB IP addresses by following the below steps. If you are using a managed service, you can do the same by following the provider's documentation.
1. Make necessary changes to the `pg_hba.conf` file to allow connections to the PeerDB user from the PeerDB IP addresses. An example entry in the `pg_hba.conf` file would look like:
```
host all peerdb_user 0.0.0.0/0 scram-sha-256
```
2. Reload the PostgreSQL instance for the changes to take effect:
```sql theme={null}
SELECT pg_reload_conf();
```
1. Head over to PeerDB UI and click on **Create Peer**. Select **Postgres** as the source.
2. Now you can fill in the connection details of the PostgreSQL instance, but make sure to use the username and password you created earlier in the SQL commands in Step 2.
4. Click on **Validate** and once that's green, you can go ahead and click on **Create** to create the peer!
This is a recommended configuration change to ensure that large transactions/commits do not cause the replication slot to be dropped.
You can increase the `max_slot_wal_keep_size` parameter for your PostgreSQL instance to a higher value (at least 100GB or `102400`) by updating the `postgresql.conf` file.
```sql theme={null}
max_slot_wal_keep_size = 102400
```
You can reload the PostgreSQL instance for the changes to take effect:
```sql theme={null}
SELECT pg_reload_conf();
```
For better recommendation of this value you can contact the PeerDB team.
When creating the Mirror, make sure to reuse the same publication you created earlier in Step 2
# Neon Postgres Source Setup Guide
Source: https://docs.peerdb.io/connect/postgres/neon_postgres
This is a guide on how to create a Neon PostgreSQL peer which you can use for replication in PeerDB.
Make sure you're signed in to your [Neon console](https://console.neon.tech/app/projects) for this setup.
## Creating a user with permissions
Let's create a new user for PeerDB with the necessary permissions suitable for CDC,
and also create a publication that we'll use for replication. For this, you can head over to the **SQL Console** tab.
1. Create a dedicated user for PeerDB:
1. ```sql theme={null}
CREATE USER peerdb_user PASSWORD 'some-password';
```
2. Grant schema-level, read-only access to the user you created in the previous step. The following example shows permissions for the `public` schema. Repeat these commands for each schema containing tables you want to replicate:
1. ```sql theme={null}
GRANT USAGE ON SCHEMA "public" TO peerdb_user;
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA "public" GRANT SELECT ON TABLES TO peerdb_user;
```
3. Grant replication privileges to the user:
1. ```sql theme={null}
ALTER USER peerdb_user WITH REPLICATION;
```
4. Create a [publication](https://www.postgresql.org/docs/current/logical-replication-publication.html) with the tables you want to replicate. We strongly recommend only including the tables you need in the publication to avoid performance overhead.
Any table included in the publication must either have a **primary key** defined *or* have its **replica identity** configured to `FULL`.
1. To create a publication for specific tables:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLE table_to_replicate, table_to_replicate2;
```
2. To create a publication for all tables in a specific schema:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLES IN SCHEMA "public";
```
The `peerdb_publication` publication will contain the set of change events generated from the specified tables, and will later be used to create the MIRROR (replication).
The PeerDB user must not be restricted by RLS policies, as it can lead to missing data. You can disable RLS policies for the user by running the below command:
```sql theme={null}
ALTER USER peerdb_user BYPASSRLS;
```
Click on **Run** to have a publication and a user ready.
## Enable Logical Replication
In Neon, you can enable logical replication through the UI. This is necessary for PeerDB's CDC to replicate data.
Head over to the **Settings** tab and then to the **Logical Replication** section.
Click on **Enable** to be all set here. You should see the below success message once you enable it.
Let's verify the below settings in your Neon Postgres instance:
```sql theme={null}
SHOW wal_level; -- should be logical
SHOW max_wal_senders; -- should be 10
SHOW max_replication_slots; -- should be 10
```
## IP Whitelisting (For Neon Enterprise plan)
If you have Neon Enterprise plan, you can whitelist the [PeerDB Cloud IP addresses](/peerdb-cloud/ip-table) (or the equivalent for PeerDB OSS/Enterprise) to allow replication from PeerDB Cloud to your Neon Postgres instance.
To do this you can click on the **Settings** tab and go to the **IP Allow** section.
## Copy Connection Details
Now that we have the user, publication ready and replication enabled, we can copy the connection details to create a Neon Postgres peer in PeerDB.
Head over to the **Dashboard** and at the text box where it shows the connection string,
change the view to **Parameters Only**. We will need these parameters for our next step.
## Create Neon Postgres Peer in PeerDB UI
Now that we have the connection details, we can create a Neon Postgres peer in PeerDB.
Head over to the PeerDB UI and click on **Create Peer**. Select **Neon** as the source.
Fill in the Neon connection details that we copied earlier in the following form.
Click on **Validate** and once that's green, you can go ahead and click on **Create** to create the peer!
## Important Gotchas
In Neon databases that are idle (no activity), slots can be dropped. To prevent this, you need to ensure that the replication slot actively receives database changes. You can use pg\_logical\_emit\_message()—a system function for emitting a logical decoding message into the WAL. PeerDB picks up the message as part of its WAL processing and flushes the slot at the frequency of the CDC sync interval.
You'd need to grant EXECUTE permissions for the peerdb replication user on this function:
```SQL theme={null}
GRANT EXECUTE ON FUNCTION pg_logical_emit_message( transactional boolean, prefix text, content text )
TO ;
```
Edit the current value fields of the following settings in the **Settings** tab in UI:
* `PEERDB_ENABLE_WAL_HEARTBEAT`: Set this to `true` (no quotes or anything)
* `PEERDB_WAL_HEARTBEAT_QUERY`: Set this to the emit\_message function call command to be run periodically:
```sql theme={null}
SELECT pg_logical_emit_message(false,'heartbeat','')
```
Currently, PeerDB emits a message every 12 minutes. This will soon be configurable.
# RDS Postgres Source Setup Guide
Source: https://docs.peerdb.io/connect/postgres/rds_postgres
## Supported Postgres versions
Anything on or after Postgres 12
## Enable Logical Replication
**You don't need** to follow the below steps if the settings `rds.logical_replication` is 1 and `wal_sender_timeout` is 0. These settings should mostly be pre-configured if you are migrating from another data replication tool.
1. Create a new parameter group for your Postgres version with `rds.logical_replication` set to 1; and `wal_sender_timeout` set to 0.
2. Modify the RDS Postgres database by adding the new parameter group.
3. Reboot your RDS Postgres database for the above parameters to kick in.
## Creating PeerDB User and Granting permissions
Connect to your RDS postgres through the admin user and run the below commands:
1. Create a dedicated user for PeerDB:
1. ```sql theme={null}
CREATE USER peerdb_user PASSWORD 'some-password';
```
2. Grant schema-level, read-only access to the user you created in the previous step. The following example shows permissions for the `public` schema. Repeat these commands for each schema containing tables you want to replicate:
1. ```sql theme={null}
GRANT USAGE ON SCHEMA "public" TO peerdb_user;
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA "public" GRANT SELECT ON TABLES TO peerdb_user;
```
3. Grant replication privileges to the user:
1. ```sql theme={null}
GRANT rds_replication TO peerdb_user;
```
4. Create a [publication](https://www.postgresql.org/docs/current/logical-replication-publication.html) with the tables you want to replicate. We strongly recommend only including the tables you need in the publication to avoid performance overhead.
Any table included in the publication must either have a **primary key** defined *or* have its **replica identity** configured to `FULL`.
1. To create a publication for specific tables:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLE table_to_replicate, table_to_replicate2;
```
2. To create a publication for all tables in a specific schema:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLES IN SCHEMA "public";
```
The `peerdb_publication` publication will contain the set of change events generated from the specified tables, and will later be used to create the MIRROR (replication).
The PeerDB user must not be restricted by RLS policies, as it can lead to missing data. You can disable RLS policies for the user by running the below command:
```sql theme={null}
ALTER USER peerdb_user BYPASSRLS;
```
## PeerDB SSH Tunneling Guide (Optional)
Sometimes to connect to your Postgres database you may need PeerDB to use an SSH tunnel.
This is typically used when your database is not publicly accessible and you need to connect to it a jump server in your VPC.
This is done by creating an SSH tunnel to your jump server and then connecting to the database through the tunnel. All
of this is handled by PeerDB natively.
Generate a key-pair using the following command:
```bash theme={null}
ssh-keygen -t rsa -b 4096 -C "peerdb-ssh-tunnel" -f peerdb_key.pem
```
This will generate a private key (`peerdb_key.pem`) and a public key (`peerdb_key.pub`).
Add the public key to your jump server. This can be done by adding the public key to the `~/.ssh/authorized_keys` file on the jump server.
```bash theme={null}
# On the jump server
cat peerdb_key.pub >> ~/.ssh/authorized_keys
```
When creating a Postgres peer you can specify the option to use an SSH tunnel. There you will be able to provide the private key you generated in the first step along with the jump server details.
## Safe list PeerDB Cloud IPs
If you are using PeerDB Cloud [safelist public IPs of your PeerDB Cloud instance](/peerdb-cloud/ip-table) by editing the `Inbound rules` of the `Security group` in which your
RDS Postgres (OR the Jump Server/Bastion if you are using SSH tunneling) is located.
## Create RDS Postgres Peer in PeerDB
Through the PeerDB UI, create the RDS Postgres Peer using the `peerdb_user` that you created in the previous step.
# Supabase Postgres Source Setup Guide
Source: https://docs.peerdb.io/connect/postgres/supabase_postgres
This is a guide on how to create a Supabase PostgreSQL peer which you can use for replication in PeerDB.
PeerDB Cloud supports Supabase via IPv6 natively for seemless replication.
Let's create a new user for PeerDB with the necessary permissions suitable for CDC,
and also create a publication that we'll use for replication. For this, you can head over to the **SQL Editor** for your Supabase Project.
1. Create a dedicated user for PeerDB:
1. ```sql theme={null}
CREATE USER peerdb_user PASSWORD 'some-password';
```
2. Grant schema-level, read-only access to the user you created in the previous step. The following example shows permissions for the `public` schema. Repeat these commands for each schema containing tables you want to replicate:
1. ```sql theme={null}
GRANT USAGE ON SCHEMA "public" TO peerdb_user;
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA "public" GRANT SELECT ON TABLES TO peerdb_user;
```
3. Grant replication privileges to the user:
1. ```sql theme={null}
ALTER USER peerdb_user WITH REPLICATION;
```
4. Create a [publication](https://www.postgresql.org/docs/current/logical-replication-publication.html) with the tables you want to replicate. We strongly recommend only including the tables you need in the publication to avoid performance overhead.
Any table included in the publication must either have a **primary key** defined *or* have its **replica identity** configured to `FULL`.
1. To create a publication for specific tables:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLE table_to_replicate, table_to_replicate2;
```
2. To create a publication for all tables in a specific schema:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLES IN SCHEMA "public";
```
The `peerdb_publication` publication will contain the set of change events generated from the specified tables, and will later be used to create the MIRROR (replication).
Click on **Run** to have a publication and a user ready.
The PeerDB user must not be restricted by RLS policies, as it can lead to missing data. You can disable RLS policies for the user by running the below command:
```sql theme={null}
ALTER USER peerdb_user BYPASSRLS;
```
Make sure to replace `peerdb_user` and `peerdb_password` with your desired username and password.
Also, remember to use the same publication name when creating the mirror in PeerDB.
1. Head over to your Supabase Project's `Project Settings` -> `Database` (under `Configuration`).
**Important**: Disable `Display connection pooler` on this page and head over to the `Connection parameters` section and note/copy the parameters.
2. Head over to PeerDB UI and click on **Create Peer**. Select **Postgres** as the source.
3. Now you can fill in the connection details you copied earlier, but make sure to use the username and password you created earlier in the SQL Editor in Step 1.
4. Click on **Validate** and once that's green, you can go ahead and click on **Create** to create the peer!
This is a recommended configuration change to ensure that large transactions/commits do not cause the replication slot to be dropped.
This step will restart your Supabase database and may cause a brief downtime.
You can increase the `max_slot_wal_keep_size` parameter for your Supabase database to a higher value (at least 100GB or `102400`) by following the [Supabase Docs](https://supabase.com/docs/guides/database/custom-postgres-config#cli-supported-parameters)
For better recommendation of this value you can contact the PeerDB team.
When creating the Mirror, make sure to reuse the same publication you created earlier in Step 1
# Supabase Postgres Source Setup Guide on PeerDB Cloud
Source: https://docs.peerdb.io/connect/postgres/supabase_postgres_peerdb_cloud
This is a guide on how to create a supabase PostgreSQL peer which you can use for replication in PeerDB.
PeerDB Cloud supports Supabase via IPv6 natively for seemless replication.
Let's create a new user for PeerDB with the necessary permissions suitable for CDC,
and also create a publication that we'll use for replication. For this, you can head over to the **SQL Editor** for your Supabase Project.
1. Create a dedicated user for PeerDB:
1. ```sql theme={null}
CREATE USER peerdb_user PASSWORD 'some-password';
```
2. Grant schema-level, read-only access to the user you created in the previous step. The following example shows permissions for the `public` schema. Repeat these commands for each schema containing tables you want to replicate:
1. ```sql theme={null}
GRANT USAGE ON SCHEMA "public" TO peerdb_user;
GRANT SELECT ON ALL TABLES IN SCHEMA "public" TO peerdb_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA "public" GRANT SELECT ON TABLES TO peerdb_user;
```
3. Grant replication privileges to the user:
1. ```sql theme={null}
ALTER USER peerdb_user WITH REPLICATION;
```
4. Create a [publication](https://www.postgresql.org/docs/current/logical-replication-publication.html) with the tables you want to replicate. We strongly recommend only including the tables you need in the publication to avoid performance overhead.
Any table included in the publication must either have a **primary key** defined *or* have its **replica identity** configured to `FULL`.
1. To create a publication for specific tables:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLE table_to_replicate, table_to_replicate2;
```
2. To create a publication for all tables in a specific schema:
```sql theme={null}
CREATE PUBLICATION peerdb_publication FOR TABLES IN SCHEMA "public";
```
The `peerdb_publication` publication will contain the set of change events generated from the specified tables, and will later be used to create the MIRROR (replication).
Click on **Run** to have a publication and a user ready.
Make sure to replace `peerdb_user` and `peerdb_password` with your desired username and password.
Also, remember to use the same publication name when creating the mirror in PeerDB.
Make sure you are signed in to your [Supabase console](https://supabase.com/) for this step.
Creating the Supabase Peer in PeerDB Cloud is as simple as granting PeerDB access to your Supabase Project.
1. Head over to the PeerDB UI and click on **Create Peer**. Select **Supabase** as the source.
2. You should be redirected to Supabase to authorize PeerDB to access your Supabase Project.
Make sure to select the correct organization from the dropdown and click on **Authorize PeerDB**.
3. You should now see a list of your Supabase Projects. Click on the project you want to create the peer for.
4. Once you select the project, you should see a screen like below with connection details filled in automatically.
Fill in the username and password you created earlier in the SQL Editor in Step 1.
5. Click on **Validate** and once that's green, you can go ahead and click on **Create** to create the peer!
The PeerDB user must not be restricted by RLS policies, as it can lead to missing data. You can disable RLS policies for the user by running the below command:
```sql theme={null}
ALTER USER peerdb_user BYPASSRLS;
```
This is a recommended configuration change to ensure that large transactions/commits do not cause the replication slot to be dropped.
This step will restart your Supabase database and may cause a brief downtime.
You can increase the `max_slot_wal_keep_size` parameter for your Supabase database to a higher value (at least 100GB or `102400`) by following the [Supabase Docs](https://supabase.com/docs/guides/database/custom-postgres-config#cli-supported-parameters)
For better recommendation of this value you can contact the PeerDB team.
When creating the Mirror, make sure to reuse the same publication you created earlier in Step 1
# Unsupported PostgreSQL Providers
Source: https://docs.peerdb.io/connect/postgres/unsupported_providers
The following providers do not support CDC (Change Data Capture) via Logical Replication and thus are not supported by PeerDB for CDC based replication:
1. Heroku - [Support Article](https://help.heroku.com/TVS8OHTR/does-heroku-postgres-support-logical-replication)
2. DigitalOcean Managed Databases - [Community Question](https://www.digitalocean.com/community/questions/managed-postgres-logical-streaming-or-wal-replication-from-do-to-outside-do?comment=197259)
However they can still be used for PeerDB's [Query Based Mirrors](/features/feature-matrix#query-based-or-watermark-based-replication).
# PubSub Setup Guide
Source: https://docs.peerdb.io/connect/pubsub
Google Pub/Sub as a destination is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
1. [Create a dedicated Service Account](https://cloud.google.com/iam/docs/keys-create-delete#iam-service-account-keys-create-console)
for PeerDB through Google Cloud Console and specify the following roles:
* `Pub/Sub Viewer` : PeerDB requires this role to check if your provided topic exists.
* `Pub/Sub Publisher` : PeerDB requires this role to publish messages to the topic.
2. Add a key to the above created service account
3. Using this service account key create the peer using PeerDB UI
***
### Topic creation
By default, you would need to create the destination topic in PubSub before creating a mirror.
However, if you'd like PeerDB to create the topic for you, you can turn on the following setting in PeerDB UI:
Note that you must create a subscription on the topic for messages to be retained.
# S3 Setup Guide
Source: https://docs.peerdb.io/connect/s3
S3 as a destination is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
1. Create an S3 bucket or ensure an existing bucket is available for use.
2. For PeerDB to access the S3 Peer, you can either use an existing AWS user or create a new AWS user.
3. Create access keys for that user through [AWS Console](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey) or [AWS CLI](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey_CLIAPI) or [AWS API](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey_API). By the end, you should have an access key along with its secret.
4. For the same user, create and attach the policy below using the [JSON editor](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-and-attach-iam-policy.html). Be sure to substitute the bucket name with your own. PeerDB requires `s3:ListAllMyBuckets`, `s3:GetObject`, `s3:PutObject`, `s3:ListBucket` and `s3:DeleteObject` on that bucket.
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::",
"arn:aws:s3:::/*"
]
}
]
}
```
5. In the PeerDB UI, select the Peers menu and select the New Peer option on the top right. Select the peer type as S3 and click on continue.
6. Choose a peer name, and fill your bucket URL (with optional prefix, in case you want PeerDB's files to be nested within the bucket), access key and secret access key along with the region. Click `Validate` to see if any issues crop up and fix them accordingly. Then click Create peer to finish peer creation.
# Snowflake Setup Guide
Source: https://docs.peerdb.io/connect/snowflake
Snowflake as a destination is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
## Prerequisites
To connect Snowflake to PeerDB, you need a Snowflake account with the appropriate permissions to create a user and warehouse for PeerDB.
We have provided a script that you can use to create a user and warehouse for PeerDB. The script also creates a role and grants the role
the appropriate permissions to access the warehouse and database.
## Setup Roles and Permissions
You can choose to create an exclusive warehouse for PeerDB or use an existing warehouse:
1. (Recommended) You can create and use an exclusive warehouse for PeerDB. PeerDB operations will never contend with your queries for resources. You will have to pay the cost of running the warehouse.
2. You can use a shared warehouse to reduce your warehouse running cost. PeerDB operations may have to contend with your queries for the shared resources.
Depending on whether you want to create a new warehouse or use a shared warehouse, do either of the following:
1. If you want to create a new exclusive warehouse, don't make any changes to the `PEERDB_WAREHOUSE` value in the script
2. If you want PeerDB to use a shared warehouse to process source queries, change the `PEERDB_WAREHOUSE` value in the script to the name of the shared warehouse
Replace the default `PEERDB_ROLE`, `PEERDB_DATABASE`, `PEERDB_USER`, and `PEERDB_5TR0NG_P455W0RD` values with values that conform to your specific naming conventions for those resources.
Do not use the actual value of `PEERDB_USER` for any other purpose.
1. Log in to your Snowflake data warehouse.
2. Copy the following script to a new [worksheet](https://docs.snowflake.com/en/user-guide/ui-worksheet.html) and edit as needed (to add schemas).
```sql Setup PeerDB Role theme={null}
begin;
-- create variables for user / password / role / warehouse / database (needs to be uppercase for objects)
set role_name = 'PEERDB_ROLE';
set user_name = 'PEERDB_USER';
set user_password = 'PEERDB_5TR0NG_P455W0RD';
set warehouse_name = 'PEERDB_WAREHOUSE';
set database_name = 'YOUR_DATABASE';
set internal_schema = '_PEERDB_INTERNAL'; -- do not change this value
-- change role to securityadmin for user / role steps
use role securityadmin;
-- create role for peerdb
create role if not exists identifier($role_name);
-- create a user for peerdb
create user if not exists identifier($user_name)
password = $user_password
default_role = $role_name
default_warehouse = $warehouse_name;
-- grant the role to the peerdb user
grant role identifier($role_name) to user identifier($user_name);
-- change role to sysadmin for warehouse / database steps
use role sysadmin;
-- Only perform this step if you want to create a
-- dedicated warehouse for peerdb (recommended)
create warehouse if not exists identifier($warehouse_name)
warehouse_size = xsmall
warehouse_type = standard
auto_suspend = 60
auto_resume = true
initially_suspended = true;
-- change role to accountadmin to grant permissions
use role ACCOUNTADMIN;
-- grant peerdb role access to warehouse
grant usage on warehouse identifier($warehouse_name)
to role identifier($role_name);
-- grant peerdb access to database
grant usage on database identifier($database_name)
to role identifier($role_name);
use database identifier($database_name);
-- create peerdb internal schema and give all permissions to peerdb role
create schema if not exists identifier($internal_schema);
grant all on schema identifier($internal_schema) to role identifier($role_name);
grant create table on schema identifier($internal_schema) to role identifier($role_name);
-- add a statement like this one for each schema you want to have accessed by peerdb
-- EXAMPLE: grant usage on schema PUBLIC to role identifier($role_name);
grant usage on schema to role identifier($role_name);
-- add statements granting select permissions and create table permissions
-- EXAMPLE: grant create table on schema PUBLIC to role identifier($role_name);
grant create table on schema to role identifier($role_name);
commit;
```
Run the script. Make sure to select the **All Queries** checkbox.
Log in as the newly created user and verify that the schemas to sync to are visible in the Snowflake UI.
## Setup Key-pair Authentication (Required)
Open the command line in a terminal window.
Generate a private key (`rsa_key.p8`). You can generate an encrypted version of the private key or an unencrypted version of the private key.
To generate an unencrypted version, you can execute the following commands:
```bash theme={null}
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
```
To generate an encrypted keypair, execute the command:
```bash theme={null}
openssl genrsa 2048 | openssl pkcs8 -topk8 -v2 AES256 -inform PEM -out rsa_key.p8
```
You will be prompted to enter a password. Choose a strong one, and don't forget to note it down!
You can also use different algorithms instead of the recommended `AES256` if needed. PeerDB supports the following alternative algorithms:
* `AES128`
* `DES3`
From the command line, generate the public key (`rsa_key.pub`) by referencing the private key. Execute the command
```bash theme={null}
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub
```
Assign the public key to the Snowflake user. In a Snowflake worksheet, execute the command
You must replace the `` value with the string between the `-----BEGIN PUBLIC KEY----- and -----END PUBLIC KEY-----` statements.
Exclude the `-----BEGIN PUBLIC KEY-----` and `-----END PUBLIC KEY-----` parts of the string.
Apart from that, multiple lines in the public key are fine.
```sql theme={null}
BEGIN;
use role accountadmin;
alter user set rsa_public_key='';
COMMIT;
```
Refer to this [doc](https://docs.snowflake.com/en/user-guide/key-pair-auth#configuring-key-pair-authentication) for more details.
## Configure PeerDB
To get the Snowflake `account_id`, you can either get it via a query or from the Snowflake UI:
To get the Snowflake `account_id`, run the following query in Snowflake worksheet:
```sql theme={null}
select t.value:host || '' snowflake
from table(flatten(parse_json(system$whitelist()))) t
where t.value:type = 'SNOWFLAKE_DEPLOYMENT'
```
remove `.snowflakecomputing.com` from the output of the above query to get the account identifier.
Example in `lixxxxx.us-east-1.snowflakecomputing.com`, you want to use `lixxxxx.us-east-1` as the account identifier.
Open the account selector form the bottom left of the Snowflake Web Interface and click the Copy icon as below:
Replace any dots (`.`) in the account identifier with hyphens (`-`).
Example, in `AB1234.XYZ987`, you want `AB1234-XYZ987`
The account identifier is case insensitive.
### PeerDB UI
In the PeerDB UI, after selecting Snowflake as the source, you can configure the connection details as follows:
`password` is NOT the account password. It is the password used to encrypt the
private key, if using an encrypted private key.
Validate the connection and create the Peer!
### PeerDB SQL
In the PeerDB SQL interface, you can create a peer to Snowflake using the following command:
`password` is NOT the account password. It is the password used to encrypt the
private key, if using an encrypted private key.
```sql theme={null}
CREATE PEER snowflake_peer FROM SNOWFLAKE WITH
(
account_id = '',
username = '',
private_key ='',
password = '' -- only provide when the private key is encrypted
database = '',
schema = '', -- default schema (most likely PUBLIC)
warehouse = '',
role = ''
);
-- Query away tables in Snowflake
SELECT * FROM sf_peer..;
```
### Considerations
1. **Database Specific:** PeerDB only supports querying tables within a database. Cross database joins are not supported yet.
2. **Supported Datatypes:** All string, numeric and timestamp based datatypes are supported for querying.
3. **SQL Coverage:** Most SQL constructs in reads incl. Simple Selects, JOINs, aggregations, window functions, CTEs etc are supported. You can run both Postgres compatible and SF compatible queries through PeerDBs interface.
4. **Error Handling:** If a query fails on the Snowflake side because of lack of auth or query coverage or timeout, PeerDB handles that error and propagates the entire message as a JSON text to the end-user. We also capture this ERROR message within PeerDB logs.
# Datatype matrix
Source: https://docs.peerdb.io/datatypes/datatype-matrix
Below table shows supported data types across **PostgreSQL, ClickHouse, BigQuery and Snowflake**.
#### Primitive Data Types
| Source | Destinations | | | | |
| -------------------------- | -------------------------- | --------------- | ---------------- | ----------------- | -------------------- |
| PostgreSQL | PostgreSQL | BigQuery | Snowflake | Clickhouse | ElasticSearch |
| `smallint` | `smallint` | `INTEGER` | `INTEGER` | `Int16` | `long` |
| `integer` | `integer` | `INTEGER` | `INTEGER` | `Int32` | `long` |
| `bigint` | `bigint` | `INTEGER` | `INTEGER` | `Int64` | `long` |
| `float4` | `float4` | `FLOAT` | `FLOAT` | `Float32` | `float` |
| `double precision` | `double precision` | `FLOAT` | `FLOAT` | `Float64` | `float` |
| `boolean` | `bool` | `BOOLEAN` | `BOOLEAN` | `Bool` | `boolean` |
| `"char"` | `CHAR` | `STRING` | `STRING` | `FixedString(1)` | `text` |
| `varchar` | `varchar` | `STRING` | `STRING` | `String` | `text` |
| `date` | `date` | `DATE` | `DATE` | `Date` | `date` |
| `json` | `json` | `JSON` | `VARIANT` | `String` | unnested subdocument |
| `jsonb` | `jsonb` | `JSON` | `VARIANT` | `String` | unnested subdocument |
| `numeric` | `numeric` | `BIGNUMERIC` | `NUMBER` | `Decimal` | `text` |
| `text` | `text` | `STRING` | `STRING` | `String` | `text` |
| `timestamp` | `timestamp` | `TIMESTAMP` | `TIMESTAMP_NTZ` | `DateTime64(6)` | `date` |
| `timestamp with time zone` | `timestamp with time zone` | `TIMESTAMP` | `TIMESTAMP_TZ` | `DateTime64(6)` | `date` |
| `time` | `time` | `TIME` | `TIME` | `String` | `date` |
| `bit` | `bit` | `BYTES` | `BINARY` | `String` | `text` |
| `bit varying` | `varbit` | `BYTES` | `BINARY` | `String` | `text` |
| `bytea` | `bytea` | `BYTES` | `BINARY` | `String` | `text` |
| `geography` | `geography` | `GEOGRAPHY` | `GEOGRAPHY` | `String` | Coming soon! |
| `geometry` | `geometry` | `GEOGRAPHY` | `GEOMETRY` | `String` | Coming soon! |
| `inet` | `inet` | `STRING` | `STRING` | `String` | `text` |
| `macaddr` | `macaddr` | `STRING` | `STRING` | `String` | `text` |
| `cidr` | `cidr` | `STRING` | `STRING` | `String` | `text` |
| `hstore` | `hstore` | `JSON` | `VARIANT` | `String` | Coming soon! |
| `uuid` | `uuid` | `STRING` | `STRING` | `uuid` | Coming soon! |
#### Array Data Types
| Source | Destinations | | | |
| ------------------------- | ------------------------- | ------------------------- | ---------------- | ----------------- |
| PostgreSQL Type | PostgreSQL | BigQuery | Snowflake | Clickhouse |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `Array` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `Array` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `Array` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `Array` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `Array` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `Array` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `Array` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `Array` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `String` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `String` |
| `ARRAY` | `ARRAY` | `ARRAY` | `VARIANT` | `String` |
### Design Choices
We recognise that there are various approaches to handling certain data types. Here are some decisions we've taken for PeerDB.
#### Numeric Type
For Snowflake, we map PostgreSQL's `numeric` type as follows:
* `numeric` with no specified precision and scale is mapped to `NUMBER(38,20)`.
* `numeric` with precision OR scale which is beyond 38 and 37 is mapped to `NUMBER(38, 20)`.
* `numeric` with precision AND scale within the above limits is mapped to `NUMBER(precision, scale)`.
For BigQuery, we map PostgreSQL's `numeric` type as follows:
* `numeric` with no specified precision and scale is mapped to `BIGNUMERIC(38,20)`.
* `numeric` with precision OR scale which is beyond 38 and 37 respectively, is mapped to `BIGNUMERIC(38, 20)`.
* `numeric` with precision AND scale within the above limits is mapped to `BIGNUMERIC(precision, scale)`.
For Clickhouse, we map PostgreSQL's `numeric` type as follows:
* `numeric` with no specified precision and scale is mapped to `Decimal(76,38)`.
* Values with more than 38 fractional digits will be truncated to 38 fractional digits and log a warning.
* Values with more than 38 integer digits will be set to 0 and log a warning.
* `numeric` with precision OR scale which is beyond 76 and 38 respectively, is mapped to `Decimal(76,38)`.
* `numeric` with precision AND scale within the above limits is mapped to `Decimal(precision, scale)`.
#### JSON/JSONB Data
Postgres JSON/JSONB supports very long numbers that are not IEEE754 compliant and can cause issues for the destination stores. PeerDB converts numeric fields it can't parse as float64 to strings at pull time.
#### Geospatial Data
PeerDB detects invalid shapes (for example, a `linestring` with only one point) among PostGIS values it pulls, and writes them as null on the destination.
We keep a log of this data and it can be retrieved if needed.
Valid geospatial data is written on BigQuery and Snowflake in `Well-Known Text (WKT)` format,
while to PostgreSQL destinations it is written as it is received.
#### HStore Data
PeerDB writes `HSTORE` data as `JSON` on BigQuery. All intricaces of the `HSTORE` data type are preserved, such as:
* `NULL` values. Example: `'"a"=>NULL'` will be written as `{"a":null}`
* Empty keys. Example: `'""=>1'` will be written as `{"":1}`
* Overriding duplicate key values. Example: `'"a"=>"1", "a"=>"2"'` will be written as `{"a":2}`
To Snowflake, it is written as a `VARIANT` data type, although it is
formatted as a `JSON` and can be queried as such - `snowflake_hstore_column:key`.
#### Nulls in BigQuery Arrays
PeerDB removes `null` values from BigQuery arrays. This is because BigQuery does not support `null` values in arrays during their insertion.
#### Elasticsearch
We currently rely on Elasticsearch dynamic mapping for data type mappings, so this mapping may not be accurate for all cases. We are working on enabling explicit mappings for Elasticsearch.
# Running Flow tests
Source: https://docs.peerdb.io/dev/running-tests
## Getting dependencies
Make sure you have the following dependencies available:
* A Linux, macOS, or Windows machine
* `git` (used for source version control)
* An `ssh` client (used to authenticate with GitHub)
* `go` and `rust` setup on your local machine (used by `flow` and `nexus` respectively)
## Getting the source
Run the following steps to set up your environment:
1. Configure your machine with an SSH key that is known to github by following the directions [here](https://help.github.com/articles/generating-ssh-keys/).
2. Clone the repo locally using `git clone --recursive git@github.com:PeerDB-io/peerdb.git` command.
## Setting up Postgres
1. Install and run postgres, installation depends on your platform.
2. Check the status to ensure postgres is running.
3. To check if postgres is installed, run `psql postgres`. To set up a dev environment, it is important to have a user named postgres because end-to-end tests use `postgres` user
4. You can download pgadmin or any other postgres-compatible viewer for GUI-based interface.
5. Following the [prerequisites](/usecases/real-time-cdc/postgres-to-postgres#prerequisites) to setup real-time CDC using postgres, connect to postgres using psql CLI and run the below commands -
6. To change `wal_level` to logical, run `ALTER SYSTEM SET wal_level = 'logical'`
7. To change `max_wal_senders`, run `ALTER SYSTEM SET max_wal_senders = 10`
8. To change `max_replication_slots`, run `ALTER SYSTEM SET max_replication_slots = 4`
9. Restart the postgres instance using `brew services restart postgresql` to reload the configuration for the changes to take effect.
10. To verify the information, run the following commands -
11. Check if `wal_level` has been set to logical, run `SHOW wal_level;`
12. Check if `max_wal_senders` has been set to 10, run `SHOW max_wal_senders;`
13. Check if `max_replication_slots` has been set to 4, run `SHOW max_replication_slots;`
## Setting up Bigquery
You should have a GCP account and Project set up. The Project should be associated with a billing account. If you don't have a credit card, you can set up the bigquery sandbox by following the instructions [here](https://cloud.google.com/bigquery/docs/sandbox). We will be using a Service Account and Key file to authenticate bigquery from our local machine.
### Creating a Service Account
1. From the [Google Cloud Platform Console](https://console.cloud.google.com/) click on the options menu (three bars in the upper left corner), Select IAM & Admin and then [Service Accounts](https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts) from the fly-out menu.
2. Click on the Create Service Account button.
3. Fill in the service account name. The Service account ID will be generated based on the service account name. Click the Create and Continue button.
4. Add the below roles:
5. BigQuery Connection User: This will allow your external application to make connections
6. BigQuery User: This will provide access to run queries, create datasets, read dataset metadata, and list tables
7. BigQuery Data Viewer: This will provide access to view datasets and all of their contents.
8. BigQuery Job User: This will provide access to run jobs
9. When done Click Continue button.
### Creating a Key File
1. Once the service account has been created, all of the service accounts will be listed. Click on the account just created on the list.
2. Click on the tab for KEYS. Then click the Add Key button. Then click on the Create new key option.
3. Choose the JSON file type and click the CREATE button.
4. The Key File will be generated and then your web browser will prompt you for download.
5. Open the xxxx.json in a text editor, and change the "type": "service\_account" into "auth\_type": "service\_account".
6. Add the line "dataset\_id": "e2e\_test\_dataset" at the end to run e2e tests for peerdb.
7. Rename the json file to bq-creds.json
After all the edits, the bq-creds.json file should look something like this -
```json theme={null}
{
"auth_type": "service_account",
"project_id": "xxxx",
"private_key_id": "xxxxx",
"private_key": "-----BEGIN PRIVATE KEY-----xx-----END PRIVATE KEY-----\n",
"client_email": "xxx@xxx.iam.gserviceaccount.com",
"client_id": "xxx",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/github-cixxxx",
"universe_domain": "googleapis.com",
"dataset_id": "e2e_test_dataset"
}
```
### Configuring BQ as a peer
To configure bigquery as a peer, you will have to modify the environment variable `TEST_BQ_CREDS` to point to the path of the JSON file. If you are using VSCode, you can add the below entry under settings.json file.
```json theme={null}
"go.testEnvVars": {
"TEST_BQ_CREDS": "/Users/xxxx/peerdb/bq-creds.json",
}
```
## Setting up Snowflake
You should have a Snowflake account and warehouse set up. If you don't you can sign up for a free-trial and create an account with Snowflake. Your role should have enough permissions to create a database, schema and tables. PeerDB uses snowflake's key pair authentication. Please follow the steps below -
### Configuring Key Pair Authentication
1. To generate a private key in p8 format, run
`openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt`
2. To generate a public key with respect to the above private key, run
`openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub`
3. Copy the generated public key into the keyboard, either using pbcopy or manual copy-paste.
`pbcopy < rsa_key.pub`
4. To assign the public key to a snowflake user, run,
`ALTER USER jsmith SET RSA_PUBLIC_KEY='MIIBIjANBgkqh...';`
5. Verify the user's public key fingerprint,
`DESC USER jsmith;`
For more information, please follow the official link [here](https://docs.snowflake.com/en/user-guide/key-pair-auth#supported-snowflake-clients)
### Creating a Key File JSON
The JSON used to authenticate snowflake from inside peerDB is of the below format -
1. `account_id`: `-`. You can find this information under Admin Page -> Accounts.
2. `username`: ``. Go to Admin -> Users & Roles -> Users, find the relevant user\_name
3. `private_key`: \
The rsa\_key.p8 file generated in the above step needs to be converted to string, which means all new lines should be converted to the "\n" symbol.
4. `database`: "peerdb". Create a new database. You can use an existing one, but make sure your role does have permissions to read/write to the database.
5. `schema`: "peerdb"
6. `warehouse`: "COMPUTE\_WH" or whatever is available under Admin -> Warehouses
7. `role`: "ACCOUNTADMIN" or whatever is available under Admin -> Users & Roles -> Role
8. `query_timeout`: 300
Save the above json file into sf-creds.json. After all the edits, the bq-creds.json file should look something like this -
```json theme={null}
{
"account_id": "iyrtvcb-ec18828",
"username": "tlodaya",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIxxxxfhI=\n-----END PRIVATE KEY-----",
"database": "PEERDB",
"schema": "TPCH_SF1",
"warehouse": "COMPUTE_WH",
"role": "ACCOUNTADMIN",
"query_timeout": 300
}
```
### Configuring SnowFlake as a peer
To configure snowflake as a peer, you will have to modify the environment variable `TEST_SF_CREDS` to point to the path of the JSON file. If you are using VSCode, you can add the below entry under settings.json file.
```json theme={null}
"go.testEnvVars": {
"TEST_SF_CREDS": "/Users/xxxx/peerdb/sf-creds.json",
}
```
## Configuring go.test timeout
You can run go tests, but before that, keep a timeout of 300s or higher. If you are using vscode, the default timeout is 60s, which will make the test fail.
In vscode, change the settings.json to have an entry
`"go.testTimeout": "300s"`
You are all set! Start testing the code and contributing!
# Frequently Asked Questions
Source: https://docs.peerdb.io/faqs/faqs
Here we cover some of the frequently asked questions about PeerDB.
### What is the difference between CDC and Query Replication?
At a high level, CDC mirrors are a way to replicate changes (inserts/updates/deletes) for tables in a database. CDC uses logical replication of Postgres and reads the WAL.
Query replication is a technique to periodically replicate the results of a query, for example - `SELECT * FROM table`. It streams the results of the query to a single table in your destination peer.
Query replication does not spin up/require a replication slot in Postgres.
## Initial Load FAQs
### What is initial load in CDC?
Initial load or initial snapshot - if enabled - will first perform a one-time copy of existing data in the tables you're syncing, and then proceed with CDC.
This is useful when you're setting up a new mirror and want to sync all the data from the beginning.
After initial load is finished, CDC will start syncing newer changes.
### If I kick off an initial load + CDC mirror with pre-existing data, will it duplicate the data?
Yes. Unlike CDC, initial load blindly copies all the data from the source to the destination.
If you have existing source data in the destination, it can be duplicated.
For restarting a mirror/doing a fresh sync with the same tables, we recommend performing a resync via UI, if supported for the target peer.
Otherwise, drop the target tables and start the mirror again.
## CDC FAQs
### What is sync interval in PeerDB CDC?
\*\*For Warehouse peers (Postgres, Snowflake, BigQuery, Clickhouse etc.):
PeerDB continuously reads rows from the WAL and stores them as internal, temporary staging files.
Once the sync interval is reached, PeerDB starts to flush the rows that it has read uptil that point into the target warehouse.
**For PeerDB Streams**:
Sync interval is not applicable. PeerDB Streams syncs data to your queue as soon as it is read from the WAL.
### What is pull batch size in PeerDB CDC?
\*\*For Warehouse peers (Postgres, Snowflake, BigQuery, Clickhouse etc.):
PeerDB continuously reads rows from the WAL and stores them as internal, temporary staging files.
Once PeerDB has read `pull_batch_size` amount of rows, PeerDB starts to flush the rows that it has read uptil that point into the target warehouse.
### The current sync has read more than pull batch size number of rows/has been running for more than sync interval time. Why is it still running?
Probably because you have long running transactions in your source database. PeerDB waits for the transactions to commit before flushing the rows to the destination.
### Does pausing a mirror stop replication slot growth?
No. The replication slot will continue to grow. The only way to make the slot size drop is having a mirror running and syncing the changes.
### Can I pause a mirror during initial load or setup phase?
No.
## Schema changes FAQs
### If I add a table to my source schema, will PeerDB automatically pick it up and sync it?
No. For adding tables, you must [edit the mirror](/features/edit-mirror).
### If I add a column to a table which is part of a mirror, will that column automatically be added in destination?
Yes. The column will be synced in the next CDC sync (or the first CDC sync if you did this during initial load).
### If I rename a column, will PeerDB automatically rename the column in the destination?
No. The old column will be present in destination and all future rows will have this column as null.
### If I drop a column from a table which is part of a mirror, will PeerDB automatically drop the column in the destination?
No. The column will remain and future values of it will be null in destination.
### If I change the data type of a column on source, will PeerDB automatically change the data type in destination?
No. The column will remain with the old data type in destination. The sync may fail if the data type change is incompatible.
## Drop/Delete Mirror FAQs
### Does PeerDB drop the replication slot once I delete the mirror?
If the slot was created by PeerDB (i.e, starts with peerflow\_slot\_something), then it will drop the slot.
If you provided a slot while creating a mirror, that slot will not be dropped.
### Does PeerDB drop the publication once I delete the mirror?
If the publication was created by PeerDB (i.e, starts with peerflow\_pub\_something), then it will drop the publication.
If you provided a publication while creating a CDC mirror, that publication will not be dropped.
## Miscellaneous FAQs
### My CDC mirror is not working with my Supabase/CloudNativePg/pgbouncer Postgres instance. What should I do?
Make sure to use direct connections instead of the connection pooler, and use IPv4 hostnames.
## Query Replication FAQs
### When should I use query replication ?
Some use-cases are:
1. You need to replicate a view.
2. You need to replicate a join of two tables or a complex query.
3. You need to replicate a table with no primary key/replica identity.
4. You don't want/cannot have a replication slot in your Postgres instance.
### Does Query Replication support deletes?
No. Use CDC if you want deletes to be synced.
### Can I edit a query replication mirror?
No. You can only edit CDC mirrors. If you need to change the query, you will have to create a new mirror.
# Email Alerting
Source: https://docs.peerdb.io/features/alerting/email-alerting
PeerDB can be configured to automatically send alerts via for issues such as Slot Lag Growth and Open Connections.
Email alerting currently uses AWS SES behind the scenes, this requires configuration for non-PeerDB Cloud environments [like this](/features/alerting/email-alerting#additional-configuration-for-non-peerdb-cloud-environment).
If you are on [PeerDB Cloud](https://app.peerdb.cloud/) this is already configured for you out-of-the-box.
# Configuring PeerDB UI
## Adding a configuration
1. Click on "Alert Configuration" from the left side of the PeerDB UI and then click "Add Configuration".
2. Now select "Email" from the list of alert providers and enter the Email Address to be notified.
To add multiple emails for a given configuration, add them comma-separated
3. Click on "Create"
# Additional configuration for non-PeerDB Cloud Environment
The following list describes the list of environment variables used for configuring Email alerts:
| Variable Name | Description |
| ------------------------------------------------- | ----------------------------------------------------- |
| `PEERDB_ALERTING_EMAIL_SENDER_SOURCE_EMAIL` | Source Email Address |
| `PEERDB_ALERTING_EMAIL_SENDER_CONFIGURATION_SET` | SES Configuration Set to use |
| `PEERDB_ALERTING_EMAIL_SENDER_REGION` | (Optional) SES Region |
| `PEERDB_ALERTING_EMAIL_SENDER_REPLY_TO_ADDRESSES` | (Optional) Comma-separated list of Reply-To addresses |
These need to be set in all the `flow` components of PeerDB.
The PeerDB environment must have `ses:SendEmail` permissions. Refer to the [AWS Documentation](https://docs.aws.amazon.com/sdkref/latest/guide/settings-reference.html) to know more.
# Slack Alerting
Source: https://docs.peerdb.io/features/alerting/slack-alerting
PeerDB can be configured to automatically send alerts via for issues such as Slot Lag Growth and Open Connections.
# Configuring Slack
## Creating and Installing a Slack App (One-Time)
This step is not required if you already have an Auth token that starts with `xoxb-`
Follow the [Slack Apps Quickstart](https://api.slack.com/start/quickstart) (upto Step 3) to create and install a Slack App on your Workspace with `chat:write` permissions.
You can find the Auth token starting with `xoxb-` under
## Inviting the app to the required channels
In order to make sure that the newly created app can post in the required channels, go ahead and invite it to those channels by sending this message:
```
/invite @
```
## Getting the channel IDs
Click the Channel Name if you have the channel open or right-click the channel and click "View channel details" from the
side bar to get the channel view.
Now the Channel ID can be copied at the bottom of the channel info dialog:
# Configuring PeerDB UI
## Adding a configuration
1. Click on "Alert Configuration" from the left side of the PeerDB UI and then click "Add Configuration".
2. Now select "Slack" from the list of alert providers and paste the Auth Token and Channel ID from before.
To add multiple channel IDs for a given configuration, add them comma-separated
3. Click on "Create"
# Editing a CDC Mirror
Source: https://docs.peerdb.io/features/edit-mirror
PeerDB allows you to [pause a CDC mirror](/features/pause-mirror) during CDC and then do three things:
1. Edit the pull batch size of the mirror.
2. Edit the sync interval of the mirror.
3. Add tables to the mirror
### Use-cases for editing a mirror
PeerDB reads the slot until either the sync interval amount of time is reached, or pull batch size amount of records have been read from the slot.
Then, PeerDB flushes (syncs) the records it has read to the destination.
Based on that, you may want to, say, reduce the sync interval so that you get your data quicker.
Or, if let's say you're syncing to a data warehouse where frequent writes are expensive, you would want to have a high pull batch size and sync interval so that you sync less frequently.
## Edit Mirror Guide
Select the mirror you created from the Mirrors page:
In order to edit the mirror, it needs to be paused first. We can click on the **Pause** button under the **Actions** menu:
Once clicked, you can refresh the page and see that the **Status** is now **Paused**.
Now, we can click on the **Edit Mirror** button under **Actions** in the **Overview** tab:
This takes to the **Edit Mirror** page where you can edit the **Pull Batch Size** and **Sync Interval**:
Once you have made the changes, click on the **Edit Mirror** button in the bottom right. This will take you back to the **Overview** tab where you the status of the mirror will be **Running**.
### Adding Tables
You can add tables in the Edit Mirror page by clicking on any of the schemas and selecting tables.
If you've provided a publication of your own for this mirror, you must add new tables to that publication
After selecting them and clicking **Edit Mirror**, you will be taken to the Overview tab where the **Status** will be **Snapshot**.
This indicates that the **initial load** of the new tables are ongoing. While the new tables are being added, the syncing of the existing tables of the mirror will be **paused** until the table is added.
Your replication slot **will grow** in the period where you're adding tables. Depending on the use case, consider creating a separate mirror instead.
Once the table is added, the **Status** will change to **Running** and the CDC syncs of the other tables along with the new ones will resume.
# Feature matrix
Source: https://docs.peerdb.io/features/feature-matrix
The actively-maintained destinations are **ClickHouse**, **ClickHouse Cloud**, and **Postgres**. Snowflake, ElasticSearch, Kafka (including the Confluent and Redpanda variants), Azure Event Hubs, Google Pub/Sub, S3, GCS, and BigQuery as a destination are deprecated and no longer actively maintained. They remain fully functional and no code is currently being removed. BigQuery is deprecated **only as a destination**; it remains a **supported source**.
Query Based or Watermark Based Replication (QRep), including XMIN-based replication, is also a deprecated mirror type. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors.
# WAL or Change Data Capture (CDC) Based Replication
Below table shows supported features and features we are working on for WAL or CDC Based replication from **Postgres** to different targets.
✅ means supported. 🛠️ means **Work in Progress and Coming Soon!**.
## Warehouses
| Feature | Snowflake | BigQuery | Clickhouse | Postgres | S3/GCS |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------- | ---------- | -------- | ------ |
| [Initial Snapshot - Parallelizable](https://blog.peerdb.io/parallelized-initial-load-for-cdc-based-streaming-from-postgres#heading-parallelized-initial-snapshot-for-cdc-based-streaming) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Incremental Sync (CDC) | ✅ | ✅ | ✅ | ✅ | ✅ |
| DML Support - INSERT, UPDATE and DELETE | ✅ | ✅ | ✅ | ✅ | ✅ |
| [Schema Changes](/features/schema-changes) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Soft Delete | ✅ | ✅ | 🛠️ | ✅ | ✅ |
| [Partitioned Tables](/features/replicating-partitioned-tables) | ✅ | ✅ | ✅ | ✅ | ✅ |
| Advanced Types - Arrays, JSONB, HSTORE, Geospatial etc. | ✅ | ✅ | ✅ | ✅ | ✅ |
| Advanced Monitoring - Lag, Throughput, Postgres Wait Events etc | ✅ | ✅ | ✅ | ✅ | ✅ |
| Resync Mirrors | ✅ | ✅ | ✅ | ✅ | ✅ |
| Column Exclusion | ✅ | ✅ | ✅ | ✅ | ✅ |
| Add Tables | ✅ | ✅ | ✅ | ✅ | ✅ |
## Queues
| Feature | EventHubs | Kafka | Redpanda | PubSub |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | ----- | -------- | ------ |
| [Initial Snapshot - Parallelizable](https://blog.peerdb.io/parallelized-initial-load-for-cdc-based-streaming-from-postgres#heading-parallelized-initial-snapshot-for-cdc-based-streaming) | 🛠️ | ✅ | ✅ | ✅ |
| Incremental Sync (CDC) | ✅ | ✅ | ✅ | ✅ |
| DML Support - INSERT, UPDATE and DELETE | ✅ | N/A | N/A | N/A |
| [Schema Changes](/features/schema-changes) | ✅ | 🛠️ | 🛠️ | 🛠️ |
| [Partitioned Tables](/features/replicating-partitioned-tables) | ✅ | ✅ | ✅ | ✅ |
| Advanced Types - Arrays, JSONB, HSTORE, Geospatial etc. | ✅ | ✅ | ✅ | ✅ |
| Advanced Monitoring - Lag, Throughput, Postgres Wait Events etc | ✅ | ✅ | ✅ | ✅ |
| Resync Mirrors | 🛠️ | N/A | N/A | N/A |
| Column Exclusion | ✅ | ✅ | ✅ | ✅ |
# Query Based or Watermark Based Replication
Query Based or Watermark Based Replication (QRep), including XMIN-based replication, is a deprecated mirror type and no longer actively maintained. It remains fully functional and no code is currently being removed. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors.
Below table shows supported features and features we are working on for Query Based or Watermark Based Replication from **Postgres** to different targets.
✅ means supported. 🛠️ means **Work in Progress and Coming Soon!**.
| Feature | Snowflake | BigQuery | Postgres | S3/GCS |
| ----------------------------------------------------------------------- | --------- | -------- | -------- | ------ |
| Initial Snapshot | ✅ | ✅ | ✅ | ✅ |
| Incremental Sync Based on Watermark | ✅ | ✅ | ✅ | ✅ |
| DML Support - INSERT, UPDATE (if updated\_at & primary key are present) | ✅ | ✅ | ✅ | ✅ |
| Schema Changes - ADD COLUMN | ✅ | 🛠️ | 🛠️ | 🛠️ |
| Resync Mirrors | ✅ | 🛠️ | 🛠️ | 🛠️ |
| Partitioned Tables | ✅ | ✅ | ✅ | ✅ |
| Advanced Types - Arrays, JSONB, HSTORE, Geospatial etc. | ✅ | ✅ | ✅ | ✅ |
| Advanced Monitoring - Throughput, Postgres Wait Events etc | ✅ | ✅ | ✅ | ✅ |
| Column Exclusion | ✅ | ✅ | ✅ | ✅ |
# Transformations
Below table shows what targets we support transformations and their status
| Target | Status |
| ---------------- | --------------- |
| EventHubs | ✅ |
| Kafka / Redpanda | ✅ |
| PubSub | ✅ |
| Snowflake | Private Preview |
| BigQuery | Private Preview |
| Clickhouse | Private Preview |
| Postgres | Private Preview |
| S3/GCS | Private Preview |
# Pausing a CDC Mirror
Source: https://docs.peerdb.io/features/pause-mirror
PeerDB allows you to pause and resume a Change-Data Capture mirror.
1. As of today, mirrors can only be paused during CDC and not during initial load or query replication.
2. The PostgreSQL source replication slot will still exist and it **will continue to grow** as long the mirror is paused.
3. Pausing a mirror enables you to then add tables to the CDC mirror, along with editing the Sync Interval and Pull Batch Size.
### Why would I pause a mirror ?
1. You could want to run some initial set of validations and analysis on synced data.
2. You could want to [edit the mirror](/features/edit-mirror).
## Pause Mirror Guide
The prerequisites for this guide are as follows:
1. You have [a PeerDB setup running](/quickstart/quickstart#deploying-peerdb).
2. You've [kicked off a CDC mirror](/quickstart/quickstart#real-time-cdc)
First, select the mirror you created from the Mirrors page:
Once the mirror is in `Running` state, we can click on the **Pause** button under the **Actions** menu:
Once clicked, you can refresh the page and see that the **Status** is now **Paused**. To resume, we can click on the **Resume** button under the **Actions** menu:
Now the **Status** should be back to **Running**.
# Replicating partitioned tables
Source: https://docs.peerdb.io/features/replicating-partitioned-tables
# Why use Partitioned Tables in Postgres?
[Table partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html) in PostgreSQL is used to improve query performance and manage large datasets efficiently by dividing a table into smaller, more manageable segments, or partitions. It allows for faster data access and maintenance, as well as optimizing specific operations like archiving or purging old data:
1. **Faster queries** - through partition pruning, queries with partition column filter are scoped to a subset of data rather than scanning the whole table
2. **Efficient data expiry** - for tables partitioned on time, to expire older data you could just DROP the older partitions rather than running a DELETE command and incurring table bloat.
# Table Partitioning in Postgres is becoming a given
Over the past 5 years, the Table Partitioning feature is [constantly evolving](https://www.2ndquadrant.com/en/blog/partitioning-evolution-postgresql-11/) and its usage is only increasing. A reason for this is that Postgres is able to support a multitude of high-scale use cases such as Timeseries, IoT, and multi-tenant SaaS, where there is a natural dimension to partition data. Table Partitioning enhances the performance and scalability of Postgres for such use cases. Just to share some numbers, out of all the Postgres customers we are working with, close to 50% of them use partitioned tables.
# Change Data Capture (CDC) for Partitioned Tables is more relevant than ever
With the increased adoption of the Table partitioning feature and the [numerous use cases](https://medium.com/event-driven-utopia/8-practical-use-cases-of-change-data-capture-8f059da4c3b7) that rely on CDC from Postgres, it is important for a data movement tool to comprehensively support CDC for Partitioned tables. This includes streaming real-time changes from Partitioned tables to Data Warehouses, Queues, or Storage, and managing various scenarios like adding new partitions, dropping partitions, adding or dropping columns, and ensuring compatibility with different Postgres versions.
# PeerDB for replicating Partitioned Tables in Postgres
At PeerDB, we are building a specialized data-movement tool for Postgres. With that spirit, we took a [step forward](https://github.com/PeerDB-io/peerdb/pull/581) to add extensive support for Real-time Change Data Capture (CDC) for Partitioned Tables. Below is a list of the various scenarios that we handled:
Demo of replicating a partitioned table in Postgres to Snowflake. It covers various scenarios such as adding new partitions, adding columns, dropping partitions and so on.
1. **Just specify the parent table for replication** - While kicking off the [MIRROR](https://docs.peerdb.io/sql/commands/create-mirror#mirror-for-cdc) (a.k.a. replication) you just need to specify the name of the partitioned table (the parent) that you want to replicate. You don't need to specify the names of each partition. PeerDB takes care of a) Taking the initial snapshot of data across all the partitions and applying it to the target and b) Replaying CDC in real-time across all the partitions to the target table.
2. **New partitions can be created and replicated** - As new partitions are created and data is added to them, PeerDB automatically replicates that data to the target table.
3. **New columns can be added and replicated** - PeerDB supports [replicating schema changes](https://github.com/PeerDB-io/peerdb/pull/368) where you add a new column (ADD COLUMN). This works as expected for Partitioned Tables.
4. **Dropping partitions doesn't delete data on the target** - If you drop a partition to expire data, we don't propagate that to the target (ex: Snowflake) i.e. we don't delete data matching that partition. We made this design choice based on customer feedback - users don't want to delete data in their data warehouse. If you require a better way to handle this scenario, you can create an issue on [Github](https://github.com/PeerDB-io/peerdb) or submit a PR! :)
5. **Support Postgres versions 12 to 16** **-** Replicating partitioned tabled should be supported for all Postgres versions starting from 12 to 16. Postgres 12 required the publication to be created for all tables. Whereas with the rest of the versions, you can create the publication just for the partitioned table with [publish\_via\_partition\_root](https://amitlan.com/writing/pg/partition-logical-replication/) set to true.
# Conclusion
It was a common concern from our customers that existing generalized data movement tools either lacked features or were not reliable in handling partitioned tables. So, we decided to spend time adding extensive Change Data Capture (CDC) support for partitioned tables. If you want to give PeerDB a try on your existing Postgres partitioned tables, these links should prove useful: :)
1. [**Quickstart**](https://docs.peerdb.io/quickstart)
2. [**PeerDB's Github repo**](https://github.com/PeerDB-io/peerdb)
3. [**Join PeerDB's Slack community**](https://slack.peerdb.io)
4. [**PeerDB docs**](https://docs.peerdb.io/introduction)
# Resyncing a CDC Mirror
Source: https://docs.peerdb.io/features/resync-mirror
PeerDB allows you to resync a Change-Data Capture mirror. Resync is currently supported for the following target connectors:
1. Clickhouse
2. PostgreSQL
3. Snowflake
4. BigQuery
### What does Resync do?
Resync involves the following operations in order:
1. The existing mirror is dropped, and a new "resync" mirror is kicked off. Thus, changes to source table structures will be picked up by PeerDB when you resync.
2. The resync mirror creates (or replaces) a new set of destination tables which have the same names as the original tables except with a `_resync` suffix.
3. Initial load is performed on the `_resync` tables.
4. The `_resync` tables are then swapped with the original tables. Soft deleted rows are transferred from the original tables to the `_resync` tables before the swap.
All the settings of the original mirror are retained in the resync mirror. The statistics of the original mirror are cleared in the UI.
### Use cases for resyncing a mirror
Here are a few scenarios:
1. You may need to perform major schema changes on the source tables which would break the existing mirror and you would need to restart. You can just click Resync after performing the changes.
2. Specifically for Clickhouse, maybe you needed to change the ORDER BY keys on the target tables. You can Resync to re-populate data into the new table with the right sorting key.
3. The replication slot of the mirror is invalidated: Resync creates a new mirror and a new slot on the source database.
You can resync multiple times, however please account for the load on the source database when you resync,
since initial load with parallel threads is involved each time.
### Resync Mirror Guide
In PeerDB UI, click on the mirror which you wish to resync.
In the top-right corner, click on the **Actions** dropdown and select **Resync**.
You will see a confirmation dialog.
Click on **Resync** to proceed.
The resync operation will be kicked off. You can monitor the progress in the Mirror Details page.
In the **Overview** tab, you will see the **Status** of the mirror.
* If the status is **Setup**, the `_resync` tables are being created.
* If the status is **Snapshot**, the initial load is being performed to the `_resync` tables.
* If the status is dRunning\*\*, the `_resync` tables have been swapped and the resync is complete.
The mirror is now in **CDC**.
# Schema Changes Propagation Support
Source: https://docs.peerdb.io/features/schema-changes
PeerDB's Postgres connector can detect schema changes in the source tables. For Postgres, BigQuery and Snowflake destinations, it can propagate some of these changes to the corresponding destination tables as well. The way each schema change is handled is documented below:
| Schema Change Type | Behaviour |
| ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Adding a new column (`ALTER TABLE ADD COLUMN ...`) | Propagated automatically once the table gets an insert/update/delete, all rows after the change will have all columns filled |
| Adding a new column with a default value (`ALTER TABLE ADD COLUMN ... DEFAULT ...`) | Propagated automatically once the table gets an insert/update/delete, all rows after the change will have all columns filled but existing rows will not show the DEFAULT value without a full table refresh |
| Dropping an existing column (`ALTER TABLE DROP COLUMN ...`) | Detected, but not propagated. All rows after the change will have NULL for the dropped columns |
# Supported connectors
Source: https://docs.peerdb.io/features/supported-connectors
The actively-maintained destinations are **ClickHouse**, **ClickHouse Cloud**, and **Postgres**. The destinations marked *(deprecated)* below (Snowflake, ElasticSearch, Kafka including the Confluent and Redpanda variants, Azure Event Hubs, Google Pub/Sub, S3, GCS, and BigQuery) are deprecated and no longer actively maintained. They remain fully functional and no code is currently being removed. BigQuery is deprecated **only as a destination**; it remains a **supported source**.
Streaming Query Replication (QRep), including XMIN-based replication, is also a deprecated mirror type. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors.
Below table shows supported source and target connectors for [Real-time Change Data Capture](/usecases/real-time-cdc/overview) and [Streaming Query Replication](/usecases/streaming-query-replication/overview). ✅ means supported. ⚠️ means beta. 🛑 means unsupported. **N/A** means Not Applicable
| Source | Target | Real-time Change Data Capture (CDC) | Streaming Query or Watermark Based Replication | Guides |
| ----------- | -------------------------------------- | ----------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| PostgreSQL | Snowflake *(deprecated)* | ✅ | ✅ | [Change Data Capture](/mirror/cdc-pg-sf),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-snowflake) |
| PostgreSQL | BigQuery *(deprecated as destination)* | ✅ | ✅ | [Change Data Capture](/mirror/cdc-pg-bq),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-bigquery) |
| PostgreSQL | PostgreSQL | ✅ | ✅ | [Change Data Capture](/mirror/cdc-pg-pg),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-postgres) |
| PostgreSQL | ClickHouse | ✅ | ✅ | [Change Data Capture](/mirror/cdc-pg-clickhouse) |
| PostgreSQL | Kafka *(deprecated)* | ✅ | N/A | [Setup Kafka Peer](/connect/kafka) |
| PostgreSQL | Redpanda *(deprecated)* | ✅ | N/A | [Setup Redpanda Peer](/connect/kafka) |
| PostgreSQL | Google PubSub *(deprecated)* | ✅ | N/A | [Setup PubSub Peer](/connect/pubsub) |
| PostgreSQL | Azure EventHubs *(deprecated)* | ✅ | N/A | [Change Data Capture](/usecases/real-time-cdc/postgres-to-azure-eventhubs) |
| PostgreSQL | S3 *(deprecated)* | ✅ | ✅ | [Change Data Capture](/usecases/real-time-cdc/postgres-to-cloud),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-s3) |
| PostgreSQL | GCS *(deprecated)* | ✅ | ✅ | [Change Data Capture](/usecases/real-time-cdc/postgres-to-cloud),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-s3) |
| MySQL | Snowflake *(deprecated)* | ✅ | ✅ | |
| MySQL | BigQuery *(deprecated as destination)* | ✅ | ✅ | |
| MySQL | PostgreSQL | ✅ | ✅ | |
| MySQL | ClickHouse | ✅ | ✅ | |
| MySQL | Kafka *(deprecated)* | ✅ | N/A | |
| MySQL | Redpanda *(deprecated)* | ✅ | N/A | |
| MySQL | Google PubSub *(deprecated)* | ✅ | N/A | |
| MySQL | Azure EventHubs *(deprecated)* | ✅ | N/A | |
| MySQL | S3 *(deprecated)* | ✅ | ✅ | |
| MySQL | GCS *(deprecated)* | ✅ | ✅ | |
| MongoDB | ClickHouse | ✅ | ✅ | |
| CockroachDB | ClickHouse | ✅ | ✅ | [Setup CockroachDB Peer](/connect/cockroachdb) |
We are actively adding more sources and targets. If you need any specific connector as a source or target to your PostgreSQL database reach out to us at [contact@peerdb.io](mailto:contact@peerdb.io)
# PeerDB
Source: https://docs.peerdb.io/introduction
Welcome to PeerDB docs. Here you'll find everything you need to get started with PeerDB.
PeerDB is now natively integrated with ClickHouse Cloud!
We recently announced the Postgres CDC connector in ClickPipes, now available in Public Preview.
This connector is fully powered by PeerDB.
As a ClickHouse Cloud customer, you get a seamless, native experience for moving data from your Postgres databases to ClickHouse Cloud. Simply navigate to the **Data Sources** tab and add a Postgres source to start ingesting data.
## What is PeerDB?
At PeerDB, we are building a fast, simple and the most cost effective way to stream data from Postgres to Data Warehouses, Queues and Storage engines. If you are running Postgres at the heart of your data-stack and move data at scale from Postgres to any of the above targets, PeerDB can provide value.
We support different modes of streaming - log based (CDC), cursor based (timestamp or integer) and XMIN based. Performance wise, we are 10x faster than existing tools. Features wise, we support native Postgres features such as comprehensive set of data-types incl. jsonb/arrays/postgis, efficiently streaming toast columns, schema changes and so on.
## PeerDB is Free and Open
PeerDB is free to use and deploy. It's licensed under AGPL-3.0 license. Here goes the link to our github repo: [https://github.com/PeerDB-io/peerdb](https://github.com/PeerDB-io/peerdb)
## **Why PeerDB?**
Existing ETL tools primarily focus on supporting a wide range of data-stores. However, they fall short in providing a rich experience for any two specific data-stores. This becomes evident when your workloads need scale or have demanding feature requirements. It is common for such users to try out these tools and fail – tools not meeting their performance and reliability SLAs or lacking the required features. Such users resort to developing their own in-house solutions, investing a lot of time and resources.
#### **Data-store nativity at it’s core, enabling scalable ETL**
PeerDB takes a data-store first approach to ETL. It supports a set of highly adopted stores, implements multiple infrastructural and data-store native optimizations, providing a highly scalable and a feature-rich ETL experience. For example, in a sync from Postgres to BigQuery or Snowflake, PeerDB is 10 times faster than other tools. We are database experts and believe that an ETL tool should be datastore centric, than a hodge-podge of too many connectors.
#### **Postgres-compatible SQL interface to do ETL**
The Postgres-compatible SQL interface for ETL is unique to PeerDB and enables you to operate in a language you are familiar with. You can do ETL the same way you work with your databases.
You can use Postgres’ eco-system to manage your ETL —
1. Client tools like pgadmin, psql to run SQL commands.
2. BI tools like grafana, tableau to visually monitor syncs and transforms.
3. Database migration and versioning tools like Flyway to manage your ETL.
4. Any language (Python, Go, Node.JS etc) and Scheduler (AirFlow) for development.
5. And many more
Get started with PeerDB in less than 5 minutes.
Learn about the architecture of PeerDB.
# EventHubs
Source: https://docs.peerdb.io/lua/eventhubs
See [eventhubs/postgres cdc guide](/usecases/real-time-cdc/postgres-to-azure-eventhubs) for details specifying properties in destination table name, scripting is designed so it can be used in conjunction with the default behavior
EventHubs records may be a table, overriding the following:
```lua theme={null}
{
value = 'body',
contentType = 'application/json',
messageId = 'arbitrary',
headers = {
header1 = 'value1',
header2 = 'value2',
},
destination = '..', -- overrides mirror's destination table value. Following values will overwrite values from this string
namespace = 'otherspace', -- must exist in hub configs
partitionColumn = 'account_id', -- setting without `key` will use existing partition-by-column logic with this column
key = 'computed', -- sets partition key value, bypassing hashing columns
hub = 'otherhub', -- sets eventhub name
}
```
# Kafka
Source: https://docs.peerdb.io/lua/kafka
Kafka records may be a table, overriding the following:
```lua theme={null}
{
topic = 'override', -- will use this over the mirror's destination table
key = 'partition key',
value = 'record value',
partition = 91, -- for use with Manual partitioner
headers = {
header1 = 'value1',
header2 = 'value2',
},
}
```
# PubSub
Source: https://docs.peerdb.io/lua/pubsub
PubSub records may be a table, overriding the following:
```lua theme={null}
{
topic = 'override', -- will use this over the mirror's destination table
key = 'ordering key',
value = 'record value',
headers = {
header1 = 'value1',
header2 = 'value2',
},
}
```
# PeerDB Lua Scripting
Source: https://docs.peerdb.io/lua/reference
PeerDB uses [Gopher Lua](https://github.com/yuin/gopher-lua) for scripting
See [examples](https://github.com/PeerDB-io/examples) for sample scripts
Scripts can be added & edited in UI:
PeerDB Streams supports an `onRecord` function for complete control of message content. Result may be a table instead of a string to specify partition key, metadata, etc. See queue specific pages for supported fields. If multiple return values are given, multiple records will be written
For qrep mirrors `transformRow` can be defined. Row fields can be set to transform row. Schema may not be modified
For cdc mirrors `transformRow` will be called on the record's rows by default, unless `tranformRecord` is defined. The latter can be useful for comparing old & new field values
# `peerdb` functions
The set of functions in global `peerdb` table are:
#### `RowColumns(row) table`
Returns array of row's column names
#### `RowColumnKind(row, column) string`
Returns underlying `Kind` of row column, see [qvalue/kind.go](https://github.com/PeerDB-io/peerdb/blob/main/flow/model/qvalue/kind.go) for list of kinds
#### `Now() [Time]`
Returns current time as `[Time]`
#### `UUID(string?) [UUID]`
Returns random `[UUID]`, or parses passed in string
#### `Decimal(string | number)`
Returns Decimal based on passed in value
#### `type(any) string`
Returns `fmt.Sprintf("%T", value)` on underlying value of UserData. Returns `nil` for other types
#### `tostring(any) string`
Returns `fmt.Sprint(value)` on underlying value of UserData. Returns `nil` for other types
# types
PeerDB exposes records as UserData:
## `Record`
Represents a CDC change
#### `kind`
One of `insert`, `update`, `delete`, or `relation`. You will likely want to ignore `relation` messages
#### `row`
Canonical row values of change. For `update` this is the new row. Keep in mind that Postgres does not send unchanged toast column values in CDC updates
#### `old`
Previous row values, `nil` for insert
#### `new`
New row values, `nil` for delete
#### `checkpoint`
LSN of CDC message
#### `commit_time`
CommitTime of record's preceding BeginMessage
#### `target`
Destination table of record defined by mirror
#### `source`
Source table of record
#### `unchanged_columns`
Update records have a table mapping unchanged [toast](https://www.postgresql.org/docs/current/storage-toast.html) columns to `true`
## `Row`
PeerDB row values which cannot be represented as Lua numbers or strings are wrapped in UserData. All of these types implement `__tostring`. Available types:
#### `I64` / `U64`
Represents signed/unsigned 64 bit integers. Implements comparisons with each other & `__tostring` support. There are 3 conversion properties:
* `i64` cast to `[I64]`
* `u64` cast to `[U64]`
* `float64` cast to lua number
* `hi` returns highest 32 bits as an unsigned number
* `lo` returns lowest 32 bits as an unsigned number
## `Time`
Has properties for durations since Unix epoch. These are `[I64]` results, except `unix` which is a lua number
* unix\_nano
* unix\_micro
* unix\_milli
* unix\_second
* unix
& properties for datetime components as numbers:
* year
* month
* day
* yearday
* hour
* minute
* second
* nanosecond
## `UUID`
Index with `[0..16)` to access bytes *(first element at index 0)*
## `BigInt`
#### `sign`
`1`, `0`, or `-1` depending on sign of value
#### `bytes`
string of `*big.Int` Bytes method
#### `int64`
value as `[I64]`
#### `is64`
whether value can be represented by `int64`
## `Decimal`
#### `coefficient`
`[BigInt]` representing digits
#### `coefficient64`
`[I64]` representing digits
#### `exponent`
Exponent, value of decimal is `coefficient * (10 ^ exponent)`
#### `bigint`
Value of decimal as a `BigInt`
#### `int64`
Value of decimal as a `[I64]`
#### `float`
Value of decimal as a number
# package.preload
PeerDB offers some preloaded libraries, accessible via `require`:
| library | description |
| --------------------------------------------------- | ------------------------------------------------------------------------------- |
| [bit32](https://github.com/PeerDB-io/gluabit32) | [bit32 API included in Lua 5.2](https://www.lua.org/manual/5.2/manual.html#6.7) |
| [json](https://github.com/PeerDB-io/gluajson) | [JSON](https://json.org) encoding/decoding |
| [msgpack](https://github.com/PeerDB-io/gluamsgpack) | [msgpack](https://msgpack.org) encoding |
| [utf8](https://github.com/PeerDB-io/gluautf8) | [utf8 API included in Lua 5.3](https://www.lua.org/manual/5.3/manual.html#6.5) |
# Config Tuning for Change Data Capture (CDC)
Source: https://docs.peerdb.io/metrics/important_cdc_configs
The behavior of PeerDB while consuming changes from the logical replication slot is as follows:
1. PeerDB would start reading the slot and keep waiting until the first record appears. It **never exits** before the first record appears.
2. Once the first record appears - SyncFlow exits based on whichever comes first:
3. `PEERDB_CDC_IDLE_TIMEOUT_SECONDS` defaults to 60s. This is set as an environment variable for the flow worker. OR
4. `max_batch_size` defaults to 100K. This is set as a part an option (WITH part) of the `CREATE MIRROR` command.
Below are the list of a few recommendations that you can follow while tuning `PEERDB_CDC_IDLE_TIMEOUT_SECONDS` and `max_batch_size`
## Latency / Lag Sensitive Workloads
1. Low `PEERDB_CDC_IDLE_TIMEOUT_SECONDS` . You can leave this as default i.e. 60s. Other sane defaults incl. 30s, 40s etc.
2. High enough `max_batch_size` to avoid too many roundtrips and support larger throughputs. You can leave this as default i.e. 100K or go a bit higher say 500K
## Others
1. High `PEERDB_CDC_IDLE_TIMEOUT_SECONDS` . Can be 5mins, 10mins, 30mins based on what acceptable lag or realtime-ness you are aiming for.
2. High `enough max_batch_size` to avoid too many roundtrips and support larger throughputs. You can decide this based on the memory available on the PeerDB instance. For example 100K for instances with low memory (\<=16GB) and 1 million for vms with higher RAM (>=32GB RAM)
## Postgres configs
1. Make sure to set `wal_sender_timeout` to 0
2. If you constantly observing IO wait\_event\_type in pg\_stat\_activity while PeerDB is consuming the slot, consider increasing (say doubling) `logical_decoding_work_mem`
# Native Metrics
Source: https://docs.peerdb.io/metrics/native-metrics
PeerDB provides native tables with all the information about ongoing Change-Data Capture and Streaming Query Replication mirrors.
These tables can be found in your PeerDB instance's `peerdb_stats` schema. Each of those tables are explained below.
#### peerdb\_stats.cdc\_batch\_table
This is a table which contains information about how many rows are *to be* synced to the destination for each of the tables, of each mirror.
### peerdb\_stats.cdc\_batches
This is a table which contains information about batches of rows of each mirror - how many rows are in them, when the sync for each batch was started and ended, and so on.
### peerdb\_stats.cdc\_flows
This is a table which shows the latest LSN (Log Sequence Number - an integer denoting the position in the WAL) at the source and at the destination for every mirror.
### peerdb\_stats.qrep\_partitions
A highly informative table showing everything you need to know about your Query Replication run. This is crucial for both streaming query replication mirrors as well as snapshot (inital load) flows. It shows how many rows are in each partition of the job, timestamps, run ID for the partition and how many times a partition retried, among many other fields.
### peerdb\_stats.qrep\_run
This table tells you when each individual clone job was started and ended along with their run IDs.
### peerdb\_stats.peer\_slot\_size
A table providing information about your source PostgreSQL peer's replication slot. Among various fields, it periodically updates with the replication slot size/lag as the difference of current LSN and flushed LSN.
# CDC Setup from Neon Postgres to ClickHouse
Source: https://docs.peerdb.io/mirror/cdc-neon-clickhouse
PeerDB is now natively integrated with ClickHouse Cloud!
We recently announced the Postgres CDC connector in ClickPipes, now available in Public Preview.
This connector is fully powered by PeerDB.
As a ClickHouse Cloud customer, you get a seamless, native experience for moving data from your Postgres databases to ClickHouse Cloud. Simply navigate to the **Data Sources** tab and add a Postgres source to start ingesting data.
## Prerequisites
To perform CDC from Neon to ClickHouse, you first need to create a source and destination Peer.
1. Create a Source Peer for Neon. Follow the instructions depending on your Neon instance:
* [Neon](/connect/postgres/neon_postgres)
2. Create a Destination Peer for ClickHouse
* [ClickHouse](/connect/clickhouse)
## Mirror Overview
Once PeerDB is connected to your , we will first do a full initial load of all the selected tables from your database. Then the continuous sync process will start using WAL to capture changes from the source database and apply them to the destination database.
PeerDB will try to match the data types of the source and destination tables as closely as possible. If there are any data types that we are unable to match, we will use `TEXT` as the default data type. For data type mapping reference, please refer to the [Data Type Mapping](/datatypes/datatype-matrix) page.
Since in this walk through we are focussing on CDC based replication, choose CDC as the mirror type.
Enter a unique identifier for the mirror name. This is used to identify the mirror in the PeerDB UI. Make this alpha numeric and without any special characters except underscore. Typically users use something like: `prod_pg_to_clickhouse_v1` or `dev_pg_to_clickhouse`.
Select the source and destination peers that you created in the prerequisites in the drop down.
* **Initial Snapshot**: Selecting this option will do a full initial load of all the selected tables from your database. This is useful when you are setting up the mirror for the first time. Default is enabled.
* **Sync Interval (Seconds)**: This is the interval at which PeerDB will poll the source database for changes. Default is `60` seconds. This has implication on the warehouse activity, for cost-sensitive users we recommend to keep this at a higher value (over `3600`).
* **Publication Name**: This is the name of the publication that you created in the source database. This is used to capture changes from the source database. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have already created a publication dedicated to peerdb (`peerdb_publication`), don't forget adding that in this field.
* **Replication Slot Name**: This is the name of the replication slot that you created in the source database. This is used to capture changes from the source database. If you have not created a replication slot, you can leave this blank and PeerDB will create a replication slot for you.
* **Snapshot Number of Rows Per Partition**: This is the number of rows that will be fetched in each partition during the initial snapshot. Default is `500000`. This is useful when you have a large number of rows in your tables and you want to control the number of rows fetched in each partition.
* **Snapshot Maximum Parallel Workers**: This is the number of parallel workers that will be used to fetch the initial snapshot. Default is `1`. This is useful when you have a large number of tables and you want to control the number of parallel workers used to fetch the initial snapshot. This setting is per-table.
* **Snapshot Number of Tables In Parallel**: This is the number of tables that will be fetched in parallel during the initial snapshot. Default is `4`. This is useful when you have a large number of tables and you want to control the number of tables fetched in parallel.
* **Soft Delete**: This is set to `false` by default. If you want to capture soft deletes, you can set this to `true`. This will add a `_peerdb_is_deleted` column to the destination table and set it to `true` when a row is deleted in the source table without actually deleting the row in the destination table.
Select the tables that you want to replicate from the source database to the destination database. You can use the search bar to search for the tables. You can also use the filter to filter the tables based on the schema.
Review the mirror configuration and click on the `Validate Mirror` button. If there are any errors, you will see them on the screen. If there are no errors, you will see a success message. Once you see the success message, click on the `Create Mirror` button to create the mirror ✨.
## Data Modeling on ClickHouse \[IMPORTANT]
Once you've moved data from Postgres to ClickHouse, the next obvious question is how to model your data in ClickHouse to make the most of it. Please refer to this page on [ClickHouse Data Modeling Tips for Postgres users](/bestpractices/clickhouse_datamodeling) to help you model data in ClickHouse.
[This](/bestpractices/clickhouse_datamodeling) is especially important as ClickHouse differs from Postgres, and you might encounter some surprises. This guide helps address potential pitfalls and ensures you can take full advantage of ClickHouse.
## If Ordering Key in ClickHouse is different from PRIMARY KEY in Postgres
If you are defining a Ordering Key in ClickHouse differently from the Primary Key in Postgres, please don't forget to read all the [considerations](/mirror/ordering-key-different) around it!
## Handling TOAST Columns
When replicating data from PostgreSQL to ClickHouse, it's important to understand the limitations and special considerations for TOAST (The Oversized-Attribute Storage Technique) columns. This guide will help you identify and properly handle TOAST columns in your replication process.
Please refer to this page on [Handling TOAST Columns](/bestpractices/clickhouse_toast_columns) to help you handle TOAST columns in your replication process.
# CDC Setup from Postgres to Bigquery
Source: https://docs.peerdb.io/mirror/cdc-pg-bq
BigQuery as a **destination** is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination. Note that BigQuery remains a **supported source**.
## Prerequisites
To perform CDC from Postgres to BigQuery, you first need to create a source and destination Peer.
1. Create a Source Peer for Postgres. Follow the instructions depending on your Postgres instance:
* [RDS](/connect/postgres/rds_postgres)
* [Cloud SQL](/connect/postgres/cloudsql_postgres)
* [Azure Flexible Server](/connect/postgres/azure_flexible_server_postgres)
* [Crunchy Bridge](/connect/postgres/crunchy_bridge)
2. Create a Destination Peer for BigQuery
* [BigQuery](/connect/bigquery)
## Mirror Overview
Once PeerDB is connected to your PostgreSQL database or read replica, we will first do a full initial load of all the selected tables from your database. Then the continuous sync process will start using WAL to capture changes from the source database and apply them to the destination database.
PeerDB will try to match the data types of the source and destination tables as closely as possible. If there are any data types that we are unable to match, we will use `TEXT` as the default data type. For data type mapping reference, please refer to the [Data Type Mapping](/datatypes/datatype-matrix) page.
Since in this walk through we are focussing on CDC based replication, choose CDC as the mirror type.
Enter a unique identifier for the mirror name. This is used to identify the mirror in the PeerDB UI. Make this alpha numeric and without any special characters except underscore. Typically users use something like: `prod_pg_to_bigquery_v1` or `dev_pg_to_bigquery`.
Select the source and destination peers that you created in the prerequisites in the drop down.
* **Initial Snapshot**: Selecting this option will do a full initial load of all the selected tables from your database. This is useful when you are setting up the mirror for the first time. Default is enabled.
* **Sync Interval (Seconds)**: This is the interval at which PeerDB will poll the source database for changes. Default is `60` seconds. This has implication on the warehouse activity, for cost-sensitive users we recommend to keep this at a higher value (over `3600`).
* **Publication Name**: This is the name of the publication that you created in the source database. This is used to capture changes from the source database. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have already created a publication dedicated to peerdb (`peerdb_publication`), don't forget adding that in this field.
* **Replication Slot Name**: This is the name of the replication slot that you created in the source database. This is used to capture changes from the source database. If you have not created a replication slot, you can leave this blank and PeerDB will create a replication slot for you.
* **Snapshot Number of Rows Per Partition**: This is the number of rows that will be fetched in each partition during the initial snapshot. Default is `500000`. This is useful when you have a large number of rows in your tables and you want to control the number of rows fetched in each partition.
* **Snapshot Maximum Parallel Workers**: This is the number of parallel workers that will be used to fetch the initial snapshot. Default is `1`. This is useful when you have a large number of tables and you want to control the number of parallel workers used to fetch the initial snapshot. This setting is per-table.
* **Snapshot Number of Tables In Parallel**: This is the number of tables that will be fetched in parallel during the initial snapshot. Default is `4`. This is useful when you have a large number of tables and you want to control the number of tables fetched in parallel.
* **Soft Delete**: This is set to `false` by default. If you want to capture soft deletes, you can set this to `true`. This will add a `_peerdb_is_deleted` column to the destination table and set it to `true` when a row is deleted in the source table without actually deleting the row in the destination table.
Select the tables that you want to replicate from the source database to the destination database. You can use the search bar to search for the tables. You can also use the filter to filter the tables based on the schema.
Review the mirror configuration and click on the `Validate Mirror` button. If there are any errors, you will see them on the screen. If there are no errors, you will see a success message. Once you see the success message, click on the `Create Mirror` button to create the mirror ✨.
# CDC Setup from Postgres to ClickHouse
Source: https://docs.peerdb.io/mirror/cdc-pg-clickhouse
PeerDB is now natively integrated with ClickHouse Cloud!
We recently announced the Postgres CDC connector in ClickPipes, now available in Public Preview.
This connector is fully powered by PeerDB.
As a ClickHouse Cloud customer, you get a seamless, native experience for moving data from your Postgres databases to ClickHouse Cloud. Simply navigate to the **Data Sources** tab and add a Postgres source to start ingesting data.
## Prerequisites
To perform CDC from Postgres to ClickHouse, you first need to create a source and destination Peer.
1. Create a Source Peer for Postgres. Follow the instructions depending on your Postgres instance:
* [RDS](/connect/postgres/rds_postgres)
* [Cloud SQL](/connect/postgres/cloudsql_postgres)
* [Azure Flexible Server](/connect/postgres/azure_flexible_server_postgres)
* [Crunchy Bridge](/connect/postgres/crunchy_bridge)
* [Neon](/connect/postgres/neon_postgres)
2. Create a Destination Peer for ClickHouse
* [ClickHouse](/connect/clickhouse)
## Mirror Overview
Once PeerDB is connected to your , we will first do a full initial load of all the selected tables from your database. Then the continuous sync process will start using WAL to capture changes from the source database and apply them to the destination database.
PeerDB will try to match the data types of the source and destination tables as closely as possible. If there are any data types that we are unable to match, we will use `TEXT` as the default data type. For data type mapping reference, please refer to the [Data Type Mapping](/datatypes/datatype-matrix) page.
Since in this walk through we are focussing on CDC based replication, choose CDC as the mirror type.
Enter a unique identifier for the mirror name. This is used to identify the mirror in the PeerDB UI. Make this alpha numeric and without any special characters except underscore. Typically users use something like: `prod_pg_to_clickhouse_v1` or `dev_pg_to_clickhouse`.
Select the source and destination peers that you created in the prerequisites in the drop down.
* **Initial Snapshot**: Selecting this option will do a full initial load of all the selected tables from your database. This is useful when you are setting up the mirror for the first time. Default is enabled.
* **Sync Interval (Seconds)**: This is the interval at which PeerDB will poll the source database for changes. Default is `60` seconds. This has implication on the warehouse activity, for cost-sensitive users we recommend to keep this at a higher value (over `3600`).
* **Publication Name**: This is the name of the publication that you created in the source database. This is used to capture changes from the source database. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have already created a publication dedicated to peerdb (`peerdb_publication`), don't forget adding that in this field.
* **Replication Slot Name**: This is the name of the replication slot that you created in the source database. This is used to capture changes from the source database. If you have not created a replication slot, you can leave this blank and PeerDB will create a replication slot for you.
* **Snapshot Number of Rows Per Partition**: This is the number of rows that will be fetched in each partition during the initial snapshot. Default is `500000`. This is useful when you have a large number of rows in your tables and you want to control the number of rows fetched in each partition.
* **Snapshot Maximum Parallel Workers**: This is the number of parallel workers that will be used to fetch the initial snapshot. Default is `1`. This is useful when you have a large number of tables and you want to control the number of parallel workers used to fetch the initial snapshot. This setting is per-table.
* **Snapshot Number of Tables In Parallel**: This is the number of tables that will be fetched in parallel during the initial snapshot. Default is `4`. This is useful when you have a large number of tables and you want to control the number of tables fetched in parallel.
* **Soft Delete**: This is set to `false` by default. If you want to capture soft deletes, you can set this to `true`. This will add a `_peerdb_is_deleted` column to the destination table and set it to `true` when a row is deleted in the source table without actually deleting the row in the destination table.
Select the tables that you want to replicate from the source database to the destination database. You can use the search bar to search for the tables. You can also use the filter to filter the tables based on the schema.
Review the mirror configuration and click on the `Validate Mirror` button. If there are any errors, you will see them on the screen. If there are no errors, you will see a success message. Once you see the success message, click on the `Create Mirror` button to create the mirror ✨.
## Data Modeling on ClickHouse \[IMPORTANT]
Once you've moved data from Postgres to ClickHouse, the next obvious question is how to model your data in ClickHouse to make the most of it. Please refer to this page on [ClickHouse Data Modeling Tips for Postgres users](/bestpractices/clickhouse_datamodeling) to help you model data in ClickHouse.
[This](/bestpractices/clickhouse_datamodeling) is especially important as ClickHouse differs from Postgres, and you might encounter some surprises. This guide helps address potential pitfalls and ensures you can take full advantage of ClickHouse.
## If Ordering Key in ClickHouse is different from PRIMARY KEY in Postgres
If you are defining a Ordering Key in ClickHouse differently from the Primary Key in Postgres, please don't forget to read all the [considerations](/mirror/ordering-key-different) around it!
## Handling TOAST Columns
When replicating data from PostgreSQL to ClickHouse, it's important to understand the limitations and special considerations for TOAST (The Oversized-Attribute Storage Technique) columns. This guide will help you identify and properly handle TOAST columns in your replication process.
Please refer to this page on [Handling TOAST Columns](/bestpractices/clickhouse_toast_columns) to help you handle TOAST columns in your replication process.
# CDC Setup from Postgres to Elasticsearch
Source: https://docs.peerdb.io/mirror/cdc-pg-elasticsearch
Elasticsearch as a destination is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
## Prerequisites
To perform CDC from Postgres to Elasticsearch, you first need to create a source and destination Peer.
1. Create a Source Peer for Postgres. Follow the instructions depending on your Postgres instance:
* [RDS](/connect/postgres/rds_postgres)
* [Cloud SQL](/connect/postgres/cloudsql_postgres)
* [Azure Flexible Server](/connect/postgres/azure_flexible_server_postgres)
* [Crunchy Bridge](/connect/postgres/crunchy_bridge)
2. Create a Destination Peer for Elasticsearch
* [Elasticsearch](/connect/elasticsearch)
## Demo
## Mirror Overview
Once PeerDB is connected to your PostgreSQL database or read replica, we will first do a full initial load of all the selected tables from your database. Then the continuous sync process will start using WAL to capture changes from the source database and apply them to the destination database.
By default, PeerDB uses Elasticsearch [dynamic mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/dynamic-field-mapping.html) to map Postgres source types to Elasticsearch types. For reference, please refer to the [Data Type Mapping](/datatypes/datatype-matrix) page. In case a stricter mapping is required, you can use the [Elasticsearch Mapping API](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html) to define the mapping for your index before creating the mirror.
Since in this walkthrough we are focussing on CDC based replication, choose CDC as the mirror type.
Enter a unique identifier for the mirror name. This is used to uniquely identify the mirror in the PeerDB UI. Make this alphanumeric and without any special characters except underscores.
Select the source and destination peers that you created in the prerequisites in the drop down.
* **Initial Snapshot**: Selecting this option will do a full initial load of all the selected tables from your database. This is useful when you are setting up the mirror for the first time. Default is enabled.
* **Sync Interval (Seconds)**: This is the interval at which PeerDB will flush the record batch and then restart polling the source database for changes. Default is `60` seconds.
* **Publication Name**: This is the name of the publication that you created in the source database. This is used to capture changes from the source database. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have already created a publication dedicated to PeerDB, don't forget adding that in this field.
* **Replication Slot Name**: This is the name of the replication slot that you created in the source database. This is used to capture changes from the source database. If you have not created a replication slot, you can leave this blank and PeerDB will create a replication slot for you. Do note that initial snapshot is only supported if PeerDB is able to create a slot.
* **Snapshot Number of Rows Per Partition**: This is the number of rows that will be fetched in each partition during the initial snapshot. Default is `500000`. This is useful when you have a large number of rows in your tables and you want to control the number of rows fetched in each partition.
* **Snapshot Maximum Parallel Workers**: This is the number of parallel workers that will be used to fetch the initial snapshot. Default is `1`. This is useful when you have a large number of tables and you want to control the number of parallel workers used to fetch the initial snapshot. This setting is per-table.
* **Snapshot Number of Tables In Parallel**: This is the number of tables that will be fetched in parallel during the initial snapshot. Default is `4`. This is useful when you have a large number of tables and you want to control the number of tables fetched in parallel.
* **Soft Delete**: This is set to `true` by default. Elasticsearch does not support soft delete currently, so this should be set to false.
Select the tables that you want to replicate from the source database to the destination database. You can use the search bar to search for the tables. You can also use the filter to filter the tables based on the schema.
Review the mirror configuration and click on the `Validate Mirror` button. If there are any errors, you will see them on the screen. If there are no errors, you will see a success message. Once you see the success message, click on the `Create Mirror` button to create the mirror ✨.
# CDC Setup from Postgres to Kafka
Source: https://docs.peerdb.io/mirror/cdc-pg-kafka
Kafka as a destination (including the Confluent and Redpanda variants) is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
## Prerequisites
To perform CDC from Postgres to Kafka, you first need to create a source and destination Peer.
1. Create a Source Peer for Postgres. Follow the instructions depending on your Postgres instance:
* [RDS](/connect/postgres/rds_postgres)
* [Cloud SQL](/connect/postgres/cloudsql_postgres)
* [Azure Flexible Server](/connect/postgres/azure_flexible_server_postgres)
* [Crunchy Bridge](/connect/postgres/crunchy_bridge)
2. Create a Destination Peer for Kafka. Follow the instructions depending on your Kafka instance:
* [Confluent Cloud](/connect/confluent-cloud)
* [Apache Kafka](/connect/kafka)
## Demo
## Mirror Overview
Once PeerDB is connected to your PostgreSQL database or read replica, we will first do a full initial load of all the selected tables from your database. Then the continuous sync process will start using WAL to capture changes from the source database and apply them to the destination queue.
Depending on the script you've chosen you have complete control of the format on the destination. Default is `JSON`.
Since in this walk through we are focussing on CDC based replication, choose CDC as the mirror type.
Enter a unique identifier for the mirror name. This is used to identify the mirror in the PeerDB UI. Make this alpha numeric and without any special characters except underscore. Typically users use something like: `prod_pg_to_kafka_v1` or `dev_pg_to_kafka`.
Select the source and destination peers that you created in the prerequisites in the drop down.
* **Sync Interval (Seconds)**: This is the interval after which PeerDB will re-establish a connection to the source database. In case of queues the recommended value is over 600 seconds.
* **Publication Name**: This is the name of the publication that you created in the source database. This is used to capture changes from the source database. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have already created a publication dedicated to peerdb (`peerdb_publication`), don't forget adding that in this field.
* **Replication Slot Name**: This is the name of the replication slot that you created in the source database. This is used to capture changes from the source database. If you have not created a replication slot, you can leave this blank and PeerDB will create a replication slot for you.
* **Script**: This is the script that you want to use to transform the data from the source database to the destination database. You can use the default script which writes to `JSON` or you can create your own script, see: [Scripting](/lua/reference).
Select the tables that you want to replicate from the source database to the destination Kafka Server. You can use the search bar to search for the tables. You can also use the filter to filter the tables based on the schema. You can specify the destination topic name, by default we create a topic with the name `.`.
If broker does not have automatic topic creation enabled you will have to create the topic ahead of time and give it to PeerDB. Automatic topic creation in Kafka Connect is controlled by the `topic.creation.enable` property. The default value for the property is `true`, enabling automatic topic creation, as shown in the following example:
```
topic.creation.enable = true
```
To prevent slot growth on the source database, it will be useful to create the heartbeat table. See this guide for detailed information: [guide](/bestpractices/heartbeat).
Review the mirror configuration and click on the `Validate Mirror` button. If there are any errors, you will see them on the screen. If there are no errors, you will see a success message. Once you see the success message, click on the `Create Mirror` button to create the mirror ✨.
When dealing with tables that feature `TOAST` columns, it's essential to configure the replica identity to `FULL` to enable PeerDB to accurately capture changes to these columns.
Setting `REPLICA IDENTITY FULL` on tables that include primary keys—or when operating on PostgreSQL 16 -- typically imposes minimal overhead on the primary server.
For an in-depth analysis, refer to this [detailed blog post on the performance implications](https://xata.io/blog/replica-identity-full-performance).
# CDC Setup from Postgres to Postgres
Source: https://docs.peerdb.io/mirror/cdc-pg-pg
## Prerequisites
To perform CDC from Postgres to Postgres, you first need to create a source and destination Peer.
1. Create a Source Peer for Postgres. Follow the instructions depending on your Postgres instance:
* [RDS](/connect/postgres/rds_postgres)
* [Cloud SQL](/connect/postgres/cloudsql_postgres)
* [Azure Flexible Server](/connect/postgres/azure_flexible_server_postgres)
* [Crunchy Bridge](/connect/postgres/crunchy_bridge)
2. Create a Destination Peer for Postgres
* [RDS](/connect/postgres/rds_postgres)
* [Cloud SQL](/connect/postgres/cloudsql_postgres)
* [Azure Flexible Server](/connect/postgres/azure_flexible_server_postgres)
* [Crunchy Bridge](/connect/postgres/crunchy_bridge)
## Mirror Overview
Once PeerDB is connected to your PostgreSQL database or read replica, we will first do a full initial load of all the selected tables from your database. Then the continuous sync process will start using WAL to capture changes from the source database and apply them to the destination database.
PeerDB will try to match the data types of the source and destination tables as closely as possible. If there are any data types that we are unable to match, we will use `TEXT` as the default data type. For data type mapping reference, please refer to the [Data Type Mapping](/datatypes/datatype-matrix) page.
Since in this walk through we are focussing on CDC based replication, choose CDC as the mirror type.
Enter a unique identifier for the mirror name. This is used to identify the mirror in the PeerDB UI. Make this alpha numeric and without any special characters except underscore. Typically users use something like: `prod_pg_to_postgres_v1` or `dev_pg_to_postgres`.
Select the source and destination peers that you created in the prerequisites in the drop down.
* **Initial Snapshot**: Selecting this option will do a full initial load of all the selected tables from your database. This is useful when you are setting up the mirror for the first time. Default is enabled.
* **Sync Interval (Seconds)**: This is the interval at which PeerDB will poll the source database for changes. Default is `60` seconds. This has implication on the warehouse activity, for cost-sensitive users we recommend to keep this at a higher value (over `3600`).
* **Publication Name**: This is the name of the publication that you created in the source database. This is used to capture changes from the source database. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have already created a publication dedicated to peerdb (`peerdb_publication`), don't forget adding that in this field.
* **Replication Slot Name**: This is the name of the replication slot that you created in the source database. This is used to capture changes from the source database. If you have not created a replication slot, you can leave this blank and PeerDB will create a replication slot for you.
* **Snapshot Number of Rows Per Partition**: This is the number of rows that will be fetched in each partition during the initial snapshot. Default is `500000`. This is useful when you have a large number of rows in your tables and you want to control the number of rows fetched in each partition.
* **Snapshot Maximum Parallel Workers**: This is the number of parallel workers that will be used to fetch the initial snapshot. Default is `1`. This is useful when you have a large number of tables and you want to control the number of parallel workers used to fetch the initial snapshot. This setting is per-table.
* **Snapshot Number of Tables In Parallel**: This is the number of tables that will be fetched in parallel during the initial snapshot. Default is `4`. This is useful when you have a large number of tables and you want to control the number of tables fetched in parallel.
* **Soft Delete**: This is set to `false` by default. If you want to capture soft deletes, you can set this to `true`. This will add a `_peerdb_is_deleted` column to the destination table and set it to `true` when a row is deleted in the source table without actually deleting the row in the destination table.
Select the tables that you want to replicate from the source database to the destination database. You can use the search bar to search for the tables. You can also use the filter to filter the tables based on the schema.
Review the mirror configuration and click on the `Validate Mirror` button. If there are any errors, you will see them on the screen. If there are no errors, you will see a success message. Once you see the success message, click on the `Create Mirror` button to create the mirror ✨.
# CDC Setup from Postgres to Snowflake
Source: https://docs.peerdb.io/mirror/cdc-pg-sf
Snowflake as a destination is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
## Prerequisites
To perform CDC from Postgres to Snowflake, you first need to create a source and destination Peer.
1. Create a Source Peer for Postgres. Follow the instructions depending on your Postgres instance:
* [RDS](/connect/postgres/rds_postgres)
* [Cloud SQL](/connect/postgres/cloudsql_postgres)
* [Azure Flexible Server](/connect/postgres/azure_flexible_server_postgres)
* [Crunchy Bridge](/connect/postgres/crunchy_bridge)
2. Create a Destination Peer for Snowflake
* [Snowflake](/connect/snowflake)
## Mirror Overview
Once PeerDB is connected to your PostgreSQL database or read replica, we will first do a full initial load of all the selected tables from your database. Then the continuous sync process will start using WAL to capture changes from the source database and apply them to the destination database.
PeerDB will try to match the data types of the source and destination tables as closely as possible. If there are any data types that we are unable to match, we will use `TEXT` as the default data type. For data type mapping reference, please refer to the [Data Type Mapping](/datatypes/datatype-matrix) page.
Since in this walk through we are focussing on CDC based replication, choose CDC as the mirror type.
Enter a unique identifier for the mirror name. This is used to identify the mirror in the PeerDB UI. Make this alpha numeric and without any special characters except underscore. Typically users use something like: `prod_pg_to_snowflake_v1` or `dev_pg_to_snowflake`.
Select the source and destination peers that you created in the prerequisites in the drop down.
* **Initial Snapshot**: Selecting this option will do a full initial load of all the selected tables from your database. This is useful when you are setting up the mirror for the first time. Default is enabled.
* **Sync Interval (Seconds)**: This is the interval at which PeerDB will poll the source database for changes. Default is `60` seconds. This has implication on the warehouse activity, for cost-sensitive users we recommend to keep this at a higher value (over `3600`).
* **Publication Name**: This is the name of the publication that you created in the source database. This is used to capture changes from the source database. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have already created a publication dedicated to peerdb (`peerdb_publication`), don't forget adding that in this field.
* **Replication Slot Name**: This is the name of the replication slot that you created in the source database. This is used to capture changes from the source database. If you have not created a replication slot, you can leave this blank and PeerDB will create a replication slot for you.
* **Snapshot Number of Rows Per Partition**: This is the number of rows that will be fetched in each partition during the initial snapshot. Default is `500000`. This is useful when you have a large number of rows in your tables and you want to control the number of rows fetched in each partition.
* **Snapshot Maximum Parallel Workers**: This is the number of parallel workers that will be used to fetch the initial snapshot. Default is `1`. This is useful when you have a large number of tables and you want to control the number of parallel workers used to fetch the initial snapshot. This setting is per-table.
* **Snapshot Number of Tables In Parallel**: This is the number of tables that will be fetched in parallel during the initial snapshot. Default is `4`. This is useful when you have a large number of tables and you want to control the number of tables fetched in parallel.
* **Soft Delete**: This is set to `false` by default. If you want to capture soft deletes, you can set this to `true`. This will add a `_peerdb_is_deleted` column to the destination table and set it to `true` when a row is deleted in the source table without actually deleting the row in the destination table.
Select the tables that you want to replicate from the source database to the destination database. You can use the search bar to search for the tables. You can also use the filter to filter the tables based on the schema.
Review the mirror configuration and click on the `Validate Mirror` button. If there are any errors, you will see them on the screen. If there are no errors, you will see a success message. Once you see the success message, click on the `Create Mirror` button to create the mirror ✨.
## Design Choices
1. Check out the datatype mapping for Postgres to Snowflake CDC [here](/datatypes/datatype-matrix)
2. `VARCHAR` and `VARIANT` column values exceeding 16MB are truncated and stored as NULLs. This is because Snowflake doesn't support [VARCHAR](https://docs.snowflake.com/en/sql-reference/data-types-text#varchar) and [VARIANT](https://docs.snowflake.com/en/user-guide/data-load-considerations-prepare#semi-structured-data-size-limitations) over 16MB.
3. We use `ON_ERROR=CONTINUE` in the [COPY](https://docs.snowflake.com/en/sql-reference/sql/copy-into-table) command while loading data into Snowflake, applicable to both initial load and Change Data Capture (CDC). This setting ensures that any row that cannot be loaded into Snowflake due to an unsupported feature (e.g., [dates out of the supported range](https://docs.snowflake.com/en/sql-reference/data-types-datetime#date)) will be skipped. Such scenarios are rare, but they can occur. To check if there were any issues with a load, you can run the following query:
`SELECT * FROM information_schema.load_history WHERE STATUS='PARTIALLY_LOADED'`
# CDC Setup from Supabase to ClickHouse
Source: https://docs.peerdb.io/mirror/cdc-supabase-clickhouse
PeerDB is now natively integrated with ClickHouse Cloud!
We recently announced the Postgres CDC connector in ClickPipes, now available in Public Preview.
This connector is fully powered by PeerDB.
As a ClickHouse Cloud customer, you get a seamless, native experience for moving data from your Postgres databases to ClickHouse Cloud. Simply navigate to the **Data Sources** tab and add a Postgres source to start ingesting data.
## Prerequisites
To perform CDC from Supabase to ClickHouse, you first need to create a source and destination Peer.
1. Create a Source Peer for Supabase. Follow the instructions depending on where you are running PeerDB:
* [Supabase on PeerDB Cloud](/connect/postgres/supabase_postgres_peerdb_cloud)
* [Supabase on Self-hosted PeerDB](/connect/postgres/supabase_postgres)
2. Create a Destination Peer for ClickHouse
* [ClickHouse](/connect/clickhouse)
## Mirror Overview
Once PeerDB is connected to your , we will first do a full initial load of all the selected tables from your database. Then the continuous sync process will start using WAL to capture changes from the source database and apply them to the destination database.
PeerDB will try to match the data types of the source and destination tables as closely as possible. If there are any data types that we are unable to match, we will use `TEXT` as the default data type. For data type mapping reference, please refer to the [Data Type Mapping](/datatypes/datatype-matrix) page.
Since in this walk through we are focussing on CDC based replication, choose CDC as the mirror type.
Enter a unique identifier for the mirror name. This is used to identify the mirror in the PeerDB UI. Make this alpha numeric and without any special characters except underscore. Typically users use something like: `prod_pg_to_clickhouse_v1` or `dev_pg_to_clickhouse`.
Select the source and destination peers that you created in the prerequisites in the drop down.
* **Initial Snapshot**: Selecting this option will do a full initial load of all the selected tables from your database. This is useful when you are setting up the mirror for the first time. Default is enabled.
* **Sync Interval (Seconds)**: This is the interval at which PeerDB will poll the source database for changes. Default is `60` seconds. This has implication on the warehouse activity, for cost-sensitive users we recommend to keep this at a higher value (over `3600`).
* **Publication Name**: This is the name of the publication that you created in the source database. This is used to capture changes from the source database. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have not created a publication, you can leave this blank and PeerDB will create a publication for you. If you have already created a publication dedicated to peerdb (`peerdb_publication`), don't forget adding that in this field.
* **Replication Slot Name**: This is the name of the replication slot that you created in the source database. This is used to capture changes from the source database. If you have not created a replication slot, you can leave this blank and PeerDB will create a replication slot for you.
* **Snapshot Number of Rows Per Partition**: This is the number of rows that will be fetched in each partition during the initial snapshot. Default is `500000`. This is useful when you have a large number of rows in your tables and you want to control the number of rows fetched in each partition.
* **Snapshot Maximum Parallel Workers**: This is the number of parallel workers that will be used to fetch the initial snapshot. Default is `1`. This is useful when you have a large number of tables and you want to control the number of parallel workers used to fetch the initial snapshot. This setting is per-table.
* **Snapshot Number of Tables In Parallel**: This is the number of tables that will be fetched in parallel during the initial snapshot. Default is `4`. This is useful when you have a large number of tables and you want to control the number of tables fetched in parallel.
* **Soft Delete**: This is set to `false` by default. If you want to capture soft deletes, you can set this to `true`. This will add a `_peerdb_is_deleted` column to the destination table and set it to `true` when a row is deleted in the source table without actually deleting the row in the destination table.
Select the tables that you want to replicate from the source database to the destination database. You can use the search bar to search for the tables. You can also use the filter to filter the tables based on the schema.
Review the mirror configuration and click on the `Validate Mirror` button. If there are any errors, you will see them on the screen. If there are no errors, you will see a success message. Once you see the success message, click on the `Create Mirror` button to create the mirror ✨.
## Data Modeling on ClickHouse \[IMPORTANT]
Once you've moved data from Postgres to ClickHouse, the next obvious question is how to model your data in ClickHouse to make the most of it. Please refer to this page on [ClickHouse Data Modeling Tips for Postgres users](/bestpractices/clickhouse_datamodeling) to help you model data in ClickHouse.
[This](/bestpractices/clickhouse_datamodeling) is especially important as ClickHouse differs from Postgres, and you might encounter some surprises. This guide helps address potential pitfalls and ensures you can take full advantage of ClickHouse.
## If Ordering Key in ClickHouse is different from PRIMARY KEY in Postgres
If you are defining a Ordering Key in ClickHouse differently from the Primary Key in Postgres, please don't forget to read all the [considerations](/mirror/ordering-key-different) around it!
## Handling TOAST Columns
When replicating data from PostgreSQL to ClickHouse, it's important to understand the limitations and special considerations for TOAST (The Oversized-Attribute Storage Technique) columns. This guide will help you identify and properly handle TOAST columns in your replication process.
Please refer to this page on [Handling TOAST Columns](/bestpractices/clickhouse_toast_columns) to help you handle TOAST columns in your replication process.
# Upgrade
Source: https://docs.peerdb.io/mirror/upgrade
Usually, recreating mirrors is not necessary unless there's been breaking changes. Pausing the mirror, upgrading, and then resuming mitigates temporal non determinism.
If the mirror for some reason after an upgrade is in a bad state, then the following procedure works, avoiding the need to resync:
1. Terminate `yourmirror-peerflow` workflow in Temporal
2. Run sql on PeerDB server: `delete from flows where name = 'yourmirror';`
3. Create mirror with same name and other parameters, **but turn off initial copy**
This works because PeerDB picks up the last flushed LSN from the replication slot (which we did not drop. Drop Mirror drops the slot so we can't do that) , and our final normalize step (for PG, BQ, SF, CH destinations) has a merge command which ensures there won't be duplicates.
If you're upgrading during initial load, then what you would want to do is comment out flow-snapshot-worker in the docker compose or make sure it stays on the same earlier version. This worker is responsible for holding the CREATE REPLICATION SLOT connection open, so if it restarts then initial load fails.
# CDC batches
Source: https://docs.peerdb.io/peerdb-api/endpoints/cdc-batches
```http theme={null}
POST api/v1/mirrors/cdc/batches
```
This endpoint retrieves change data capture (CDC) batches for a specified mirror.
### Request Fields
The name of the mirror to get CDC batches for.
The maximum number of CDC batches to retrieve. Set this to 0 or lower to retrieve all batches.
Whether to sort the CDC batches in ascending order based on their IDs. Defaults to `false`.
The ID of the last CDC batch to retrieve batches before. Set to -1 to ignore this filter.
The ID of the first CDC batch to retrieve batches after. Set to -1 to ignore this filter.
### Response Fields
An array of CDC batches.
The unique identifier for the CDC batch.
The timestamp when the batch started. A batch starts only upon receiving the first change event.
The timestamp when the batch has been completed.
The number of rows in the CDC batch.
The starting Log Sequence Number (LSN) for the batch.
The ending Log Sequence Number (LSN) for the batch.
The total number of CDC batches returned.
The current page number.
```bash Get the 5 most recent CDC batches for a mirror theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/mirrors/cdc/batches \
--header 'Authorization: Basic Xp9dY3Rhc0suZiQ0Iw==' \
--header 'Content-Type: application/json' \
--data '{
"flowJobName": "mirror_production",
"limit": 5,
"beforeId": -1,
"afterId": -1,
"ascending": false
}'
```
```json theme={null}
{
"cdcBatches": [
{
"startLsn": "0",
"endLsn": "0",
"numRows": "0",
"startTime": "2025-09-01T12:31:36.932056Z",
"endTime": null,
"batchId": "168730"
},
{
"startLsn": "0",
"endLsn": "46637208645632",
"numRows": "60452",
"startTime": "2025-09-01T12:30:36.504532Z",
"endTime": "2025-09-01T12:31:38.472191Z",
"batchId": "168729"
},
{
"startLsn": "0",
"endLsn": "4663711103356",
"numRows": "59476",
"startTime": "2025-09-01T12:29:36.097869Z",
"endTime": "2025-09-01T12:30:37.925048Z",
"batchId": "168728"
},
{
"startLsn": "0",
"endLsn": "46637036715864",
"numRows": "131025",
"startTime": "2025-09-01T12:28:34.860097Z",
"endTime": "2025-09-01T12:29:38.814718Z",
"batchId": "168727"
},
{
"startLsn": "0",
"endLsn": "46636882418728",
"numRows": "238256",
"startTime": "2025-09-01T12:27:34.396289Z",
"endTime": "2025-09-01T12:28:38.964550Z",
"batchId": "168726"
}
],
"total": 168730,
"page": 1
}
```
# Change mirror state
Source: https://docs.peerdb.io/peerdb-api/endpoints/change-mirror-state
```http theme={null}
POST /api/v1/mirrors/state_change
```
This endpoint can be used for changing the state of a mirror. To be specific, it can be used for:
1. [Pausing](/features/pause-mirror) a mirror
2. Resuming a mirror
3. [Editing](/features/edit-mirror) a paused mirror
4. Dropping a mirror
### Request Fields
The name of the mirror.
The state to change the mirror to. Possible values are:
* `STATUS_PAUSED` (2) - **Pause** the mirror
* `STATUS_RUNNING` (1) - **Resume** the mirror
* `STATUS_TERMINATING` (6) - **Drop** the mirror
Resuming via editing a mirror
If you are editing a paused CDC mirror, you can include the following fields.
Editing a mirror resumes it automatically.
The sync interval of the CDC mirror in seconds.
The pull batch size of the CDC mirror
Additional tables to sync. You cannot add and remove the same table in the same request.
You can also specify column exclusion here.
The source table identifier.
The destination table identifier.
Columns to exclude from the sync.
Tables to remove from the sync. You cannot remove just a few columns.
You cannot add and remove the same table in the same request.
The source table identifier.
The destination table identifier.
### Response Fields
Whether the request was successful.
For an edit request, the response is empty if successful.
```bash Pausing theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/mirrors/state_change \
--header 'Authorization: Basic OmJkYWNrU3rhbjEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"flowJobName": "mirror_kick_off",
"requestedFlowState": "STATUS_PAUSED"
}'
```
```bash Resuming theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/mirrors/state_change \
--header 'Authorization: Basic OmJkYWNrU3rhbjEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"flowJobName": "mirror_kick_off",
"requestedFlowState": "STATUS_RUNNING"
}'
```
```bash Edit and resume theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/mirrors/state_change \
--header 'Authorization: Basic Xk5hY3VhXXXZTP0IP==' \
--header 'Content-Type: application/json' \
--data '{
"flowJobName": "mirror_kick_off",
"requestedFlowState": "STATUS_RUNNING",
"flowConfigUpdate": {
"cdcFlowConfigUpdate":{
"idle_timeout": 600,
"batch_size": 100000,
"additional_tables":[
{
"sourceTableIdentifier": "public.added_table",
"destinationTableIdentifier": "added_table_destination"
},
{
"sourceTableIdentifier": "public.added_table_2",
"destinationTableIdentifier": "added_table_destination_2",
"exclude": ["column1", "column2"]
}
]
}
}
}'
```
```bash Dropping theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/mirrors/state_change \
--header 'Authorization: Basic OmJkYWNrU3rhbjEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"flowJobName": "mirror_kick_off",
"requestedFlowState": 6
}'
```
```json Success theme={null}
{
"ok": true,
"errorMessage": ""
}
```
```json Success for edit request theme={null}
{}
```
```json Error theme={null}
{
"code": 2,
"message": "unable to get workflowID for flow job fake_mirror: no rows in result set",
"details": []
}
```
# Create mirror
Source: https://docs.peerdb.io/peerdb-api/endpoints/create-mirror
```http theme={null}
POST api/v1/flows/cdc/create
```
This endpoint is used to create a CDC mirror.
### Request Fields
Connection configuration
The name of the mirror to be created.
The name of the source peer (data store).
The name of the destination peer (data store).
Table mappings
The source table identifier.
The destination table identifier.
Columns from the source table to exclude, separated by commas.
**For Clickhouse Only And Optional**. Ordering key setting for Clickhouse target tables created by PeerDB.
Name of the column
A number indicating the rank of this column in the ordering key of ORDER BY in ReplacingMergeTree.
Whether to do an initial snapshot.
The maximum number of rows to sync in a batch.
How often the mirror syncs, in seconds.
The name of the publication to use. PeerDB will try to create a publication if not provided here.
The number of rows per partition to sync during the initial snapshot.
Default is 1 million rows.
The maximum number of parallel workers to use during the initial snapshot.
The number of tables to sync in parallel during the initial snapshot.
Whether to resync the mirror. The mirror **must be dropped** before resyncing.
Whether to do only the initial snapshot and not perform CDC.
The name of the column that indicates a soft delete.
The name of the column that indicates when the row was last synced.
### Response Fields
The ID of the parent workflow created for this mirror.
```bash Request theme={null}
curl --request POST \
--url localhost:3000/api/v1/flows/cdc/create \
--header 'Authorization: Basic OnJsYWNrd3dhbmEyMw==' \
--header 'Content-Type: application/json' \
--data '
{
"connection_configs": {
"flow_job_name": "mirror_api_kick_off",
"source_name": "rds_peer",
"destination_name": "ch_peer",
"table_mappings": [
{
"source_table_identifier": "public.users",
"destination_table_identifier": "users_api"
},
{
"source_table_identifier": "public.payments",
"destination_table_identifier": "payments_api"
},
{
"source_table_identifier": "public.optional_ordering_key",
"destination_table_identifier": "optional_ordering_key",
"columns": [
{
"sourceName": "id",
"ordering": 1
},
{
"sourceName": "created_at",
"ordering": 2
}
]
},
],
"max_batch_size": 1000,
"idle_timeout_seconds": 300,
"publication_name": "",
"do_initial_snapshot": true,
"snapshot_num_rows_per_partition": 5000,
"snapshot_max_parallel_workers": 4,
"snapshot_num_tables_in_parallel": 2,
"resync": false,
"initial_snapshot_only": false,
"soft_delete_col_name": "_peerdb_is_deleted",
"synced_at_col_name": "_peerdb_synced_at"
}
}'
```
```json Response theme={null}
{
"workflowId": "mirror_kick_off-peerflow-2d269226-9757-4d9f-8cfd-6adb1ca29c0e"
}
```
```json Error example theme={null}
{
"code": 2,
"message": "invalid mirror: mirror with name mirror_api_kick_off already exists",
"details": []
}
```
# Create a ClickHouse peer
Source: https://docs.peerdb.io/peerdb-api/endpoints/create-peer/clickhouse
```http theme={null}
POST api/v1/peers/create
```
PeerDB is now natively integrated with ClickHouse Cloud!
We recently announced the Postgres CDC connector in ClickPipes, now available in Public Preview.
This connector is fully powered by PeerDB.
As a ClickHouse Cloud customer, you get a seamless, native experience for moving data from your Postgres databases to ClickHouse Cloud. Simply navigate to the **Data Sources** tab and add a Postgres source to start ingesting data.
You can create a Clickhouse peer using this endpoint. Here is the request and response format for creating a Clickhouse peer.
Note that the Clickhouse peer uses an intermediary S3 stage under the hood for performance. The S3 fields related to this are optional, because:
* For PeerDB Cloud, the S3 bucket is managed by PeerDB
* For PeerDB OSS, a minio bucket is provided as part of the stack.
### Request Fields
Configuration of the peer to be created.
The name of the peer to be created.
The type of peer to be created. The value for Clickhouse is **8**.
Configuration for the Clickhouse peer
Host of the Clickhouse server.
Port on which the Clickhouse server is running. Ex: 9440
Make sure this is the **native TCP port**.
The user to connect to the Clickhouse server.
The password associated with the Clickhouse user.
The database to connect to.
Whether the Clickhouse server is running without TLS. Default is `false`.
Certificate to connect to the Clickhouse server.
Private key to connect to the Clickhouse server.
Root CA to connect to the Clickhouse server.
The S3 path to use for the stage. It is of the form `s3://bucket-name/path`.
The access key ID for the S3 bucket.
The secret access key for the S3 bucket.
The secret access key for the S3 bucket.
The region of the S3 bucket.
The endpoint of the S3 bucket.
Whether you wish to update a peer with this name if it already exists. Default is `false`.
### Response Fields
Whether the creation/update was successful. If yes, the value will be `CREATED`. Else it will be `FAILED`.
Error message if any
```bash Clickhouse peer theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/peers/create \
--header 'Authorization: Basic OmJsXPNrU3dhbjEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"peer": {
"name": "ch_peer_via_api",
"type": 8,
"clickhouse_config": {
"host": "localhost",
"port": 9900,
"user": "default",
"password": "clickhouse",
"database": "clickhouse",
"disable_tls": false
}
},
"allow_update":false
}'
```
```bash Clickhouse peer with cert auth theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/peers/create \
--header 'Authorization: Basic OmJsXPNrU3dhbjEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"peer": {
"name": "ch_peer_via_api",
"type": 8,
"clickhouse_config": {
"host": "localhost",
"port": 9900,
"user": "default",
"password": "clickhouse",
"database": "clickhouse",
"disable_tls": false,
"certificate":"",
"private_key":"***",
"root_ca":""
}
},
"allow_update":false
}'
```
```json Success theme={null}
{
"status": "CREATED",
"message": ""
}
```
```json Clickhouse error theme={null}
{
"status": "FAILED",
"message": "CLICKHOUSE peer ch_peer_via_api was invalidated: failed to open connection to Clickhouse peer: failed to ping to Clickhouse peer: dial tcp [::1]:9900: connect: connection refused"
}
```
# Create a Kafka peer
Source: https://docs.peerdb.io/peerdb-api/endpoints/create-peer/kafka
```http theme={null}
POST api/v1/peers/create
```
You can create a Kafka peer using this endpoint. Here is the request and response format for creating a Kafka peer.
### Request Fields
Configuration of the peer to be created.
The name of the peer to be created.
The type of peer to be created. The value for Kafka is **9**.
Configuration for the Kafka peer
Array of Kafka servers. Ex: `["localhost:9092"]`
The username to connect to the Kafka server.
The password associated with the Kafka user.
The SASL mechanism to use. Ex: `PLAIN`
Whether the Kafka server is running without TLS. Default is `false`.
The partitioner to use. Default is empty string.
Whether you wish to update a peer with this name if it already exists. Default is `false`.
### Response Fields
Whether the creation/update was successful. If yes, the value will be `CREATED`. Else it will be `FAILED`.
Error message if any
```bash Kafka peer theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/peers/create \
--header 'Authorization: Basic OmJsYWNrU3dhbpEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"peer": {
"name": "kafka_peer_via_api",
"type": 9,
"kafka_config": {
"servers": ["localhost:9092"],
"username": "kafka",
"password": "kafka",
"sasl": "PLAIN",
"disable_tls": false,
"partitioner": "RoundRobin"
}
},
"allow_update":false
}'
```
```json Success theme={null}
{
"status": "CREATED",
"message": ""
}
```
```json Kafka error theme={null}
{
"status": "FAILED",
"message": "failed to establish active connection to KAFKA peer kafka_peer_via_api: unable to dial: dial tcp [::1]:9092: connect: connection refused"
}
```
# Overview
Source: https://docs.peerdb.io/peerdb-api/endpoints/create-peer/overview
```http theme={null}
POST api/v1/peers/create
```
This endpoint is used to create a peer. Peers represent data stores between which you can move data using a mirror.
### Peers in this documentation:
1. [Postgres peer](/peerdb-api/endpoints/create-peer/postgres)
2. [Clickhouse peer](/peerdb-api/endpoints/create-peer/clickhouse)
3. [Kafka peer](/peerdb-api/endpoints/create-peer/kafka)
# Create a Postgres peer
Source: https://docs.peerdb.io/peerdb-api/endpoints/create-peer/postgres
```http theme={null}
POST api/v1/peers/create
```
Here is the request and response format for creating a Postgres peer. SSH tunneling is optional for peer creation.
### Request Fields
Configuration of the peer to be created.
The name of the peer to be created.
The type of peer to be created. The value for Postgres is **3**.
Postgres config
Host of the PG server.
Port on which the PG server is running. Ex: 5432
The user to connect to the PG server.
The password associated with the user.
The database to connect to.
Configuration for SSH tunneling
The host of the SSH server.
The port on which the SSH server is running.
The user to connect to the SSH server.
The password associated with the user.
The private key as a string to connect to the SSH server.
Whether you wish to update a peer with this name if it already exists. Default is `false`.
### Response Fields
Whether the creation/update was successful. If yes, the value will be `CREATED`. Else it will be `FAILED`.
Error message if any
```bash Postgres peer theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/peers/create \
--header 'Authorization: Basic OmJsYWNrU3dhbpEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"peer": {
"name": "pg_peer_via_api",
"type": 3,
"postgres_config": {
"host": "localhost",
"port": 5432,
"user": "postgres",
"password": "postgres",
"database": "postgres"
}
},
"allow_update":false
}'
```
```bash Postgres peer with SSH tunneling theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/peers/create \
--header 'Authorization: Basic OmJsYWNrU3dhbpEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"peer": {
"name": "pg_peer_via_api",
"type": 3,
"postgres_config": {
"host": "localhost",
"port": 5432,
"user": "postgres",
"password": "postgres",
"database": "postgres",
"ssh_config": {
"host":"1.2.3.4",
"port":22,
"user":"ubuntu",
"private_key":"***"
}
}
}
}'
```
```json Success theme={null}
{
"status": "CREATED",
"message": ""
}
```
```json Postgres error theme={null}
{
"status": "FAILED",
"message": "POSTGRES peer pg_peer_via_api was invalidated: failed to create ssh tunnel: no authentication methods provided"
}
```
# Create a Snowflake peer
Source: https://docs.peerdb.io/peerdb-api/endpoints/create-peer/snowflake
```http theme={null}
POST api/v1/peers/create
```
You can create a Snowflake peer using this endpoint. Here is the request and response format for creating a Snowflake peer.
### Request Fields
Configuration of the peer to be created.
The name of the peer to be created.
The type of peer to be created. The value for Snowflake is **1**.
Configuration for the Snowflake peer
The account ID of the Snowflake server.
The username to connect to the Snowflake server.
The private key in PEM or pk8 format to connect to the Snowflake server.
If you are providing an encrypted key, please provide the password as a separate field (listed below).
The database to connect to.
The warehouse to connect to.
The Snowflake role to connect to.
The query timeout in seconds. The default is 30 seconds.
This is optional, if the private key provided is encrypted.
Whether you wish to update a peer with this name if it already exists. Default is `false`.
### Response Fields
Whether the creation/update was successful. If yes, the value will be `CREATED`. Else it will be `FAILED`.
Error message if any
```bash Snowflake peer theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/peers/create \
--header 'Authorization: Basic OmJsXPNrU3dhbjEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"peer": {
"name": "snowflake_peer_via_api",
"type": 1,
"snowflake_config": {
"account_id": "account_id",
"username": "username",
"private_key":"***",
"database": "database",
"warehouse": "warehouse",
"role": "role",
"query_timeout": 30,
"password": "password"
}
},
"allow_update":false
}'
```
```json Success theme={null}
{
"status": "CREATED",
"message": ""
}
```
# Mirror logs
Source: https://docs.peerdb.io/peerdb-api/endpoints/mirror-logs
```http theme={null}
POST api/v1/mirrors/logs
```
This endpoint is used to get logs of a mirror (even one which has been deleted) or all mirrors.
A mirror represents a data movement pipeline between two peers.
### Request Fields
The name of the mirror to get logs for.
An empty string will return logs for all mirrors in the PeerDB instance.
The log level to filter logs by. Can be one of `ALL`, `INFO`, `WARN`, or `ERROR`. Defaults to `ALL`.
The page number to retrieve.
The number of logs to retrieve per page. If set to 0 or unset, no logs will be returned and a total count of logs will be returned.
The ID of the last log to retrieve logs before.
The ID of the first log to retrieve logs after.
### Response Fields
An array of logs. The name is misleading here - it can contain info and warns as well, not just errors.
The name of the mirror that the log belongs to.
The log message - could be an info, warning or error.
The type of error - could be `INFO`, `WARN`, or `ERROR`.
The timestamp of the log in milliseconds since epoch.
The ID of the log.
The total number of logs available.
The current page number.
```bash Get all mirror logs theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/mirrors/logs \
--header 'Authorization: Basic something==' \
--header 'Content-Type: application/json' \
--data '{
"level": "error",
"flowJobName": "",
"beforeId": -1,
"afterId": -1,
"numPerPage": 2,
"page": 0
}
'
```
```json theme={null}
{
"errors": [
{
"flowName": "mirror_development",
"errorMessage": "failed to push data to ClickHouse: table users does not exist",
"errorType": "error",
"errorTimestamp": 1748972135285,
"id": 702169
},
{
"flowName": "mirror_staging",
"errorMessage": "failed to connect to Postgres",
"errorType": "error",
"errorTimestamp": 1748972135047,
"id": 702168
}
],
"total": 63,
"page": 1
}
```
# Mirror status
Source: https://docs.peerdb.io/peerdb-api/endpoints/mirror-status
```http theme={null}
POST api/v1/mirrors/status
```
This endpoint is used to get the status of a mirror. Status of the mirror could be:
* `STATUS_SETUP`: The mirror is in setup flow, where it creates target tables and metadata tables.
* `STATUS_SNAPSHOT`: The mirror is currently performing initial load.
* `STATUS_RUNNING`: The mirror has completed initial load and is in the phase of CDC.
* `STATUS_PAUSED`: The mirror is in CDC phase and is [paused](/features/pause-mirror).
* `STATUS_PAUSING`: The mirror is in CDC phase and is in the process of pausing.
* `STATUS_TERMINATED`: The mirror has been deleted/terminated.
* `STATUS_UNKNOWN`: The mirror is not found in the catalog, or its status cannot be obtained due to some issue.
### Request Body
The request consists of the mirror name specified as `flowJobName`
and `includeFlowInfo` as a boolean, which when set, will include in its response
additional, non-status related information about the mirror
such as mirror configuration and initial load information of tables.
The name of the mirror to get the status of.
When set to true, will include in its response
additional, non-status related information about the mirror
such as mirror configuration and initial load information of tables.
### Response Fields
The name of the mirror.
Error message if any.
The current state of the mirror.
Indicates if the request was successful.
Additional flow information when `includeFlowInfo` is set to true:
Information about the mirror configuration and initial load of tables.
Mirror configuration.
The name of the mirror.
Array of table mapping objects. Each object contains the following fields.
The source table identifier. Will be of the form `schema.table`.
The destination table identifier.
Column names to exclude
Pull batch size: the maximum number of rows to pull in a single batch, if `idleTimeoutSeconds` has not been reached.
The time in seconds after which the mirror will flush pulled rows to the target data store,
if pull batch size has not already been reached.
User provided publication name for the mirror, if any.
User provided replication slot name for the mirror, if any.
Indicates if initial snapshot was enabled for this mirror.
The number of rows to sync per partition during initial snapshot.
The maximum number of parallel workers to use during initial snapshot.
The number of tables to sync in parallel during initial snapshot.
Indicates if this mirror is a resync
Indicates if this mirror was configured to only run initial load and not CDC.
Indicates if soft delete is enabled.
The name of the column used for soft delete.
The name of the column used for tracking sync time.
Lua script configured for the mirror.
The data type system of the mirror.
The source peer name.
The destination peer name.
Information about the initial load of tables.
Array of clone objects - each indicating initial load information of a table.
Each object contains the following fields.
The name of the destination table.
The time when the clone started.
The number of partitions completed.
The total number of partitions.
The number of rows synced.
The average time taken to sync each partition, in milliseconds.
The name of the clone job.
The source table.
Indicates if fetching is completed.
Indicates if consolidation (loading of stage files to target tables) is completed.
The name of the mirror.
The source peer type. Example: `"POSTGRES"`
The destination peer type. Example: `"BIGQUERY"`
```bash Request theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/mirrors/status \
--header 'Authorization: Basic OnBlZXJkYg==' \
--header 'Content-Type: application/json' \
--data '{
`flowJobName`:`testing_bq_2`,
`includeFlowInfo`:false
}'
```
```bash with includeFlowInfo set theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/mirrors/status \
--header 'Authorization: Basic OnBlZXJkYg==' \
--header 'Content-Type: application/json' \
--data '{
`flowJobName`:`testing_bq_2`,
`includeFlowInfo`:true
}'
```
```json Response theme={null}
{
"flowJobName": "testing_bq_2",
"errorMessage": "",
"currentFlowState": "STATUS_RUNNING",
"ok": true
}
```
```json with includeFlowInfo set theme={null}
{
"flowJobName": "testing_bq_2",
"cdcStatus": {
"config": {
"flowJobName": "testing_bq_2",
"tableMappings": [
{
"sourceTableIdentifier": "public.sales",
"destinationTableIdentifier": "public_sales",
"partitionKey": "",
"exclude": [] // excluded columns, comma-separated
},
],
"maxBatchSize": 1000000,
"idleTimeoutSeconds": "60",
"cdcStagingPath": "",
"publicationName": "",
"replicationSlotName": "",
"doInitialSnapshot": true,
"snapshotNumRowsPerPartition": 1000000,
"snapshotStagingPath": "",
"snapshotMaxParallelWorkers": 4,
"snapshotNumTablesInParallel": 1,
"resync": false,
"initialSnapshotOnly": false,
"softDelete": true,
"softDeleteColName": "_PEERDB_IS_DELETED",
"syncedAtColName": "_PEERDB_SYNCED_AT",
"script": "",
"system": "Q",
"sourceName": "postgres_local",
"destinationName": "bq_peer"
},
"snapshotStatus": {
"clones": [
{
"tableName": "public_sales",
"startTime": "2024-06-27T14:37:48.701204Z",
"numPartitionsCompleted": 1,
"numPartitionsTotal": 1,
"numRowsSynced": "4",
"avgTimePerPartitionMs": "11381",
"flowJobName": "clone_testing_bq_2_public_sales_dc500df7_2606_4c19_96c0_e40e0df4e5ec",
"sourceTable": "public.sales",
"fetchCompleted": true,
"consolidateCompleted": true,
"mirrorName": "testing_bq_2"
}
]
},
"cdcSyncs": [], // coming soon
"sourceType": "POSTGRES",
"destinationType": "BIGQUERY"
},
"errorMessage": "",
"currentFlowState": "STATUS_RUNNING",
"ok": true
}
```
```json Error example theme={null}
{
"flowJobName": "fake_mirror",
"errorMessage": "unable to get the workflow ID of mirror fake_mirror",
"currentFlowState": "STATUS_UNKNOWN",
"ok": false
}
```
# Peer info
Source: https://docs.peerdb.io/peerdb-api/endpoints/peer-info
```http theme={null}
GET /api/v1/peers/info/{peer_name}
```
This endpoint is used to get information about a peer.
A peer represents a data store. Sensitive information such as passwords are not returned.
### Request Fields
Describe a peer by its peer name.
### Response Fields
The description of the peer object. To see the fields of the peer object, refer to the [Create Peer](/peerdb-api/endpoints/create-peer/overview) endpoint.
This is the version of the peer. Currently returned for Postgres and ClickHouse peers.
```bash Get a peer theme={null}
curl --request GET \
--url http://localhost:3000/api/v1/peers/info/my_postgres_peer \
--header 'Authorization: Basic OmJsYWNrU3dhbjEyMw==' \
```
```json theme={null}
{
"peer": {
"name": "my_postgres_peer",
"type": "POSTGRES",
"postgresConfig": {
"host": "my_postgres_peer.rpolkfgn.us-east-1.rds.amazonaws.com",
"port": 5432,
"user": "postgres",
"password": "********",
"database": "postgres"
}
},
"version": "PostgreSQL 16.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 7.3.1 20180712 (Red Hat 7.3.1-12), 64-bit"
}
```
# Create script
Source: https://docs.peerdb.io/peerdb-api/endpoints/scripts/create-script
```http theme={null}
POST /api/v1/scripts
```
This endpoint is used to create a new script or update an existing one.
* If the script ID in the request is -1, a new script is created.
* Otherwise, the existing script with the given ID, if existing, is updated.
Scripts are disabled by default in [PeerDB Cloud](https://auth.peerdb.cloud/en/login).
It is enabled in [PeerDB OSS](https://github.com/PeerDB-io/peerdb) and [PeerDB Enterprise](https://github.com/PeerDB-io/peerdb-enterprise).
### Request Fields
Describe the new script to be created or updated.
The ID of the script. If -1, a new script is created.
The name of the script.
The language of the script.
The source code of the script.
### Response Fields
If successful, returns the ID of the created or updated script
```bash Create a new script theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/scripts \
--header 'Authorization: Basic OmJsYWNrU3dhbjEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"script":{
"id": -1,
"lang": "lua",
"name": "new_script_created",
"source": "\n-- This is a sample script\n-- Fill in the onRecord function to transform the incoming record\nlocal json = require \"json\"\n\nfunction onRecord(r)\n return json.encode(r.row)\nend"
}
}'
```
```bash Update existing script theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/scripts \
--header 'Authorization: Basic OmJsYWNrU3dhbjEyMw==' \
--header 'Content-Type: application/json' \
--data '{
"script":{
"id": 1,
"lang": "lua",
"name": "new_script_updated",
"source": "\n-- This is a sample script\n-- Fill in the onRecord function to transform the incoming record\nlocal json = require \"json\"\n\nfunction onRecord(r)\n return json.encode(r.row)\nend"
}
}'
```
```json theme={null}
{
"id": 1
}
```
# List scripts
Source: https://docs.peerdb.io/peerdb-api/endpoints/scripts/list-scripts
```http theme={null}
GET /api/v1/scripts/{id}
```
This endpoint is used to get a script by its ID. If the ID is -1, it returns all scripts.
Scripts are disabled by default in [PeerDB Cloud](https://auth.peerdb.cloud/en/login).
It is enabled in [PeerDB OSS](https://github.com/PeerDB-io/peerdb) and [PeerDB Enterprise](https://github.com/PeerDB-io/peerdb-enterprise).
### Request Fields
Describe a script by its ID. If the ID is -1, it returns all scripts.
### Response Fields
An array of scripts.
The ID of the script.
The name of the script.
The language of the script.
The source code of the script.
```bash Get all scripts theme={null}
curl --request GET \
--url http://localhost:3000/api/v1/scripts/-1 \
--header 'Authorization: Basic OmJsYWNrU7dhbjEyMw==' \
```
```bash Get a script by ID theme={null}
curl --request GET \
--url http://localhost:3000/api/v1/scripts/2 \
--header 'Authorization: Basic OmJsYWNrU7dhbjEyMw==' \
```
```json theme={null}
{
"scripts": [
{
"id": 2,
"lang": "lua",
"name": "new_script",
"source": "\n-- This is a sample script\n-- Fill in the onRecord function to transform the incoming record\nlocal json = require \"json\"\n\nfunction onRecord(r)\n return json.encode(r.row)\nend"
},
{
"id": 3,
"lang": "lua",
"name": "good_script",
"source": "\n-- This is a sample script\n-- Fill in the onRecord function to transform the incoming record\nlocal json = require \"json\"\n\nfunction onRecord(r)\n return json.encode(r.row)\nend"
},
{
"id": 4,
"lang": "lua",
"name": "bad_script",
"source": "\n-- This is a sample script\n-- Fill in the onRecord function to transform the incoming record\nlocal json = require \"json\"\n\nfunction onRecord(r)\n return json.encode(r.row)\nend"
}
]
}
```
# PeerDB API Reference
Source: https://docs.peerdb.io/peerdb-api/reference
PeerDB provides multiple API endpoints to interact with it through the UI endpoint as a proxy.
This is an ongoing effort to eventually expose all of PeerDB's functionality in the form of API endpoints for programmatic use-cases.
## Base endpoint
The base endpoint is the URL of PeerDB UI.
**PeerDB OSS**
When running PeerDB OSS on Docker, PeerDB UI is exposed at:
```
http://localhost:3000
```
**PeerDB Cloud**
When using PeerDB Cloud, the URL is provided as part of the PeerDB instance you purchase.
## Authentication
PeerDB API uses basic authentication.
The username is empty and the password is the same password used to login to PeerDB UI.
```bash cURL theme={null}
curl --request POST \
--url http://localhost:3000/api/v1/mirrors/status \
--header
'Authorization
: Basic
OnBlZXJkYg==' \
--header
'Content-Type
: application/json' \
```
```javascript Axios theme={null}
axios.post('http://localhost:3000/api/v1/mirrors/status', {}, {
headers: {
'Authorization': 'Basic OnBlZXJkYg==',
'Content-Type': 'application/json'
}
})
```
# AWS Private Link
Source: https://docs.peerdb.io/peerdb-cloud/aws-private-link
PeerDB Cloud supports AWS Private Link for secure and private connectivity between VPCs.
This allows you to connect your VPCs to PeerDB Cloud without exposing your data to the public internet.
## Setting up AWS Private Link with PeerDB Cloud
1. Create the necessary endpoint service as per preference. Some of the common ways to achieve this are (for Postgres):
* EC2 with script to fetch DNS records on schedule and update forwarding rules
* Lambda with listener to Event Bridge (CloudFormation Template available in [AWS Docs](https://aws.amazon.com/blogs/database/access-amazon-rds-across-vpcs-using-aws-privatelink-and-network-load-balancer/)
Make sure the RDS instance endpoint used in case of RDS DB Cluster/Aurora is ONLY the WRITER Endpoint and NOT the common endpoint.
2. Give access to the PeerDB's AWS ARN `arn:aws:iam::141675317444:root` (or Account ID `141675317444`) so that it can be discovered for establishing the Private Link connection
3. (Optionally) Allow network connections from PeerDB's internal CIDR range `10.0.0.0/16` to the Endpoint Service
4. Provide PeerDB Team with Endpoint Service Name (`com.amazonaws…`) and the region where the service is located
* This can be done either via contacting PeerDB Team via Slack or Email
1. PeerDB Team will setup the necessary Endpoint Interface
2. PeerDB Team will provide back the DNS name (for peer connectivity) and the Endpoint Interface ID for Accepting the Endpoint Interface request
1. Accept the Endpoint Interface Request
2. Create the peer via PeerDB UI (or ask PeerDB Team to perform a health check on the Endpoint Interface DNS from the same network as the PeerDB Cloud Instance)
## Setting up a ClickHouse Cloud Private Link with PeerDB Cloud
PeerDB cloud *natively* supports AWS Private Link for destination ClickHouse Cloud instances. This allows you to connect your ClickHouse Cloud instance to PeerDB Cloud without exposing your data to the public internet.
1. Go to your ClickHouse Cloud instance console
2. Navigate to "Settings"
3. Click on "Set up private endpoint" under "Settings" -> "Private endpoints"
4. You should see a screen like below:
5. Copy the "Service Name" and "DNS Name" from the above dialog and provide it to the PeerDB Team, (along with a helpful description of the cloud instance for reference)
1. PeerDB Team will setup the necessary Endpoint Interface
2. PeerDB Team will provide back the the `Endpoint ID`
1. Go back to the ClickHouse Cloud Console and head over to the same "Set up private endpoint" screen
2. Enter the `Endpoint ID` provided by the PeerDB Team in the "Endpoint ID" field and Description can be "PeerDB Cloud Link"
1. You can now use the DNS name provided earlier under the "Setup Endpoint Service on ClickHouse Cloud Console" step to create a peer in PeerDB Cloud.
2. For further details on how to create a ClickHouse Cloud peer, refer to the [ClickHouse Cloud Setup Guide](/connect/clickhouse/clickhouse-cloud#clickhouse-cloud-setup-guide)
# PeerDB Cloud Quickstart Guide
Source: https://docs.peerdb.io/peerdb-cloud/cloud-quickstart
Get started with PeerDB Cloud in a few simple steps.
### PeerDB Cloud
PeerDB Cloud is a fully managed service that allows you to replicate data across different data stores. It is designed to be easy to use and requires no infrastructure management. You can get started with PeerDB Cloud in a few simple steps.
Let's head over to [https://app.peerdb.cloud](https://app.peerdb.cloud) to get started.
### Sign Up
Upon landing on [PeerDB Cloud](https://app.peerdb.cloud), we will be greeted with the login page.
Since we're new, let's click on **Sign Up**. This takes us to the sign-up page. Let's fill in the details and click on **Sign Up**.
Enter the name of your organisation in the next page:
### Creating an instance
We will be taken to the PeerDB Cloud Dashboard. We can now create a PeerDB instance. Let's click on **Create Instance** to get started.
This takes us to the **New Instance** page. Let's briefly talk about the form:
* **Name**: The name of the instance. This can be to your liking.
* **Password**: The password for the instance. This is used to connect to the instance, so make sure to note it down. For this quickstart, let's assume the password to be `quickstart`.
* **Version**: The version of PeerDB to use. For this quickstart, let's select the provided version in the dropdown.
The **PeerDB Micro** instance is default and is sufficient for this quickstart. Let's click on **Continue**.
This takes us to the **Confirm** page. Let's click on **Create Instance** to create the instance.
That's it! We should now be able to see our instance in the dashboard.
The instance will take a minute to get ready. We should then, upon a page refresh, see the running instance:
Let's click on **PeerDB UI** to head over to PeerDB UI
### PeerDB UI
We will be directed to the PeerDB UI login page. The password for this instance is the one we set during the instance creation.
In our case, that is `quickstart`.
Let's fill in the password and click on **Sign in with Password**.
We have landed at the **PeerDB UI dashboard**!
Please do check out the [PeerDB UI Quickstart Guide](../quickstart/quickstart) to create peers, mirrors, and much more.
# PeerDB Cloud Security
Source: https://docs.peerdb.io/peerdb-cloud/cloud-security
Learn about how PeerDB Cloud ensures the security of your data.
Security is paramount at PeerDB, and we take our commitment to protecting customer data very seriously. To provide a secure and compliant platform, we adhere to strict protocols and employ various measures to safeguard sensitive information.
## Compliance
PeerDB is currently compliant with the following frameworks:
* **SOC 2 Type II** - PeerDB is SOC 2 Type II Compliant and [our report](https://trust.peerdb.io/resources?s=t6nuewj8c7b5p948qzhth\&name=soc-2-type-ii) is available on our [Trust Center](https://trust.peerdb.io)
* [**GDPR**](https://blog.peerdb.io/peerdb-is-gdpr-compliant)
We are currently undergoing compliance review for the following frameworks:
* **HIPAA** - Controls are being set up in place for compliance
## Data Retention
PeerDB doesn’t store any customer specific data on their end: all the data that is transferred/staged, whether local or remote (S3) is **transient**.
## Access and Isolation
### Isolation
Every customer instance on PeerDB Cloud is **fully isolated** from other instances and all cross-instance traffic is explicitly denied by default.
More details are available in the [Isolation Architecture Doc](https://trust.peerdb.io/resources?s=s4vk91c8wyd5q0aok7x4sh\&name=peer-db-cloud-customer-isolation-architecture) on our [Trust Center](https://trust.peerdb.io/).
### Access
PeerDB follows the Principle of Least Privilege wherever possible and requires **read-only access** to the source peers: no write access is needed.
Any and all internal traffic/access across instances is controlled via claim-based and role-based access-control, short-lived credentials and **security best-practices**.
## Encryption
Any data in transit is **fully encrypted**. Additionally customers can leverage SSH Tunneling to ensure that they don’t need to expose the public IP of the source peer/database.
## Additional Security Features
### IP Whitelisting
PeerDB Cloud supports IP whitelisting for secure access to your source/target peers. You can find the list of IPs to whitelist [here](/peerdb-cloud/ip-table).
### [SSH Tunneling for Secure Postgres Replication](https://blog.peerdb.io/ssh-tunneling-for-secure-postgres-replication)
We natively support SSH tunneling right from the first connection to your database. A very simple way to get started can be found [here](/connect/postgres/rds_postgres#peerdb-ssh-tunneling-guide-optional)
### AWS PrivateLink
PeerDB Cloud supports AWS PrivateLink for secure and private access to your source/target peers. This ensures that your data never leaves the AWS network and is secure from any external threats.
This is available on all PeerDB Cloud instances and can be enabled by following the [guide here](/peerdb-cloud/aws-private-link).
## Additional Documents and Compliance
[Our Trust Center](https://trust.peerdb.io/) is the best place to get an overview and to get access to more documents and compliance frameworks. Click on “Request Access” and we will grant you access shortly.
All PeerDB employees follow security programs/protocols and are trained to ensure that all customer data is securely handled and isolated. These include but are not limited to:
* Incident Response Plan
* Security Trainings
* MDM
* 2FA Enforcement for each and every access
* Timely Vulnerability Fixes and Dependency Updates
* Intrusion Detection System
* Automated Alerts and Alarms
# Trust Center
Source: https://docs.peerdb.io/peerdb-cloud/cloud-trust-center
Visit our [Trust Center](https://trust.peerdb.io) to learn more about PeerDB's security and compliance measures and get access to our compliance reports and documents.
# Public IPs For PeerDB Cloud
Source: https://docs.peerdb.io/peerdb-cloud/ip-table
Depending on the region you choose for your PeerDB Cloud instance, you will need to have the instance's public IPs be whitelisted in your peers.
Below is a list of public IPs for each region:
| Region | Public IPs |
| -------------- | ----------------------------------------------- |
| us-west-2 | `54.201.178.203, 100.21.65.249, 54.213.107.162` |
| ap-south-1 | `3.109.74.175, 3.109.177.128, 13.201.199.0` |
| ap-southeast-2 | `3.106.65.101, 54.66.63.23, 13.236.72.200` |
| us-east-1 | `107.23.34.182, 52.5.156.236, 100.27.85.50` |
| us-east-2 | `3.140.47.131, 18.224.116.167, 18.216.125.76` |
| eu-central-1 | `35.159.188.24, 3.66.142.2, 18.185.234.115` |
# PeerDB Cloud Pricing FAQ
Source: https://docs.peerdb.io/peerdb-cloud/peerdb-cloud-pricing-faq
### What is the main advantage of PeerDB's pricing model?
PeerDB offers a predictable pricing model. We charges based on the provisioned vCPUs rather than the amount of data transferred. This would ensure that your data-movement costs don't spiral out of control. You’ll clearly know your expenses beforehand, with no surprises in the future
### **Is there an extra charge for the Initial Load? Would what I provisioned be sufficient?**
PeerDB Cloud is configured for autoscaling up to 2 times the provisioned vCPUs and compute. For example, if you provision a 4 vCPU PeerDB instance, autoscaling is configured up to 8 vCPUs. Therefore, the initial load can scale up to double what you've provisioned. We do not charge for additional vCPUs as long as it is a one-off occurrence. However, if the additional usage is consistent, we will inform you and only proceed to scale up to the next tier after receiving acknowledgment from you.
### Are the recommendations for how many rows PeerDB tiers can handle completely accurate?
No, the recommendations for PeerDB tiers (required vCPUs) in relation to the number of rows moved per month are estimates. They are based on observations from our average customer. For example, a smaller number of super wide rows could require a larger tier than recommended, while a higher number of narrow rows might justify a smaller recommended tier. Workloads with multiple MIRRORs could require a larger tier than recommended. The best way to determine the ideal configuration is to test PeerDB with your workload. For further assistance, please contact our team at [contact@peerdb.io](mailto:contact@peerdb.io).
### Do PeerDB Tiers impose strict limits on the number of rows moved per month?
No, PeerDB Tiers simply correspond to the number of provisioned vCPUs for your workload. Recommendations regarding the number of rows moved per month for each tier are estimates based on the average customer. They are not strict limits.
# Quickstart Guide
Source: https://docs.peerdb.io/quickstart/quickstart
Get started with PeerDB in a few simple steps.
### Deploying PeerDB
We currently support deploying and testing PeerDB using our Docker Compose file.
Docker can be installed by referring to [these instructions](https://www.docker.com/products/docker-desktop).
The `docker compose` tool should also be present. The Postgres client tools (specifically
`psql`) are used to test the PeerDB installation.
**Run the following commands in your terminal:**
```bash theme={null}
git clone --recursive https://github.com/PeerDB-io/peerdb.git
cd peerdb
# Run docker containers: peerdb-server, postgres as catalog, temporal.
# This might take a few minutes, so get a cup of coffee! :)
./run-peerdb.sh
```
That's it! You now have PeerDB up and running on your machine, ready to query away!
### Quickstart
The following steps assume you have PeerDB running locally. We also need `psql` installed and available on your
PATH.
#### Setup
This script reuses the PeerDB internal Postgres instance to setup two databases, which we can use to create two peers. It also creates some tables on both databases to use later in the quickstart. Run the following commands in your terminal:
```bash theme={null}
curl -O https://raw.githubusercontent.com/PeerDB-io/peerdb/main/quickstart_prepare_peers.sh
chmod +x quickstart_prepare_peers.sh
./quickstart_prepare_peers.sh
```
#### Creating Peers
With PeerDB running, we can create our first peers.
Head over to `localhost:3000` on your browser. This is the PeerDB Dashboard.
Clicking on **Peers** in the sidebar will take us to the **Peers** page.
Let's click on the Create Peer button at the top right to get started.
Now, we select the data store for which we wish to create a peer. Let's select **Postgres** and click on the **Continue** button.
This takes to a form where we can fill in the details for the peer. Let's fill in the details of our PostgreSQL peer.
Fill in the **password** as `postgres`.
PeerDB validates the connection details and if everything is correct, clicking on **Validate** should show a success message.
Finally, click on **Create** to create the peer.
We now have our **source PostgreSQL peer** ready.
Let's create the **target PostgreSQL peer** by repeating the exact same steps.
Fill in the **password** as `postgres`.
Now that we have our source and target peers ready, let's move on to **creating a mirror**.
Clicking on **Mirrors** in the sidebar will take us to the **Mirrors** page.
#### Real-time CDC
To kick off Change Data Capture (CDC) based streaming from source peer to target peer, let's click on **New Mirror**.
Let's select the `CDC` box, and enter the name of the mirror and the two peers.
Scrolling down, we can see a section to a **select the table** on our source PostgreSQL peer to sync.
Let's select the table we have ready - `public.test`.
Now that we've filled in all the mirror details.
Let's click on **Validate** to check if everything is set up correctly, much like we did when creating peers!
Finally, click on **Create** to create the mirror.
Now that our CDC mirror is set up, it will automatically replicate data from the source to the target peer. Let's insert a row in the source table via PeerDB itself.
Connect to PeerDB via psql:
```bash theme={null}
psql "port=9900 host=localhost password=peerdb"
```
And now we can run the below commands.
```sql theme={null}
--- Verify that the source table has zero rows
SELECT id,c1,c2,t FROM source.public.test;
```
```sql theme={null}
--- Insert a row into the source table
INSERT INTO source.public.test(c1, c2, t) VALUES(1, 2, 'oathbringer');
```
Within a minute, the row should be replicated to the target table. Let's click the mirror link on the `Mirrors` page which we landed on after creating the mirror:
This takes to the **Mirror Overview** page. Let's click on the **Sync Status tab**, where we can see the status of the mirror and the number of rows replicated:
We can see that the mirror has successfully replicated the row from the source to the target peer. Let's verify this by querying the target table.
```sql theme={null}
--- CDC mirrors replicate data as-is, so the row should be identical.
SELECT id,c1,c2,t FROM target.public.test;
```
The output should look like this:
```bash theme={null}
peerdb=> SELECT id,c1,c2,t FROM target.public.test;
id | c1 | c2 | t
----+----+----+-------------
1 | 1 | 2 | oathbringer
(1 row)
```
The above MIRROR takes care of replicating all future DML commands (`INSERT`, `UPDATE`, `DELETE`) from source to target.
### FAQ
If you have any questions about the PeerDB setup and deployment process, don't hesitate to reach out on [Slack](https://slack.peerdb.io). We're more than happy to assist and answer any questions, including:
* What is the performance I can expect during CDC and query based replication?
* How do I know my data sync is successful?
* Can I set a specific time to start my data sync?
If there are any unanswered questions, we'd love to help you get started. Feel free to ask your questions on our community [Slack](https://slack.peerdb.io) channel.
In addition to this, if you require direct access to our team for any assistance, don't hesitate to contact us to discuss our premium support offerings.
# SQL Quickstart Guide
Source: https://docs.peerdb.io/quickstart/sql-quickstart
Get started with PeerDB in a few simple steps.
### Deploying PeerDB
We currently support deploying and testing PeerDB using our Docker Compose file.
Docker can be installed by referring to [these instructions](https://www.docker.com/products/docker-desktop).
The `docker compose` tool should also be present. The Postgres client tools (specifically
`psql`) are used to test the PeerDB installation.
1. **Run the following commands in your terminal:**
```bash theme={null}
git clone --recursive https://github.com/PeerDB-io/peerdb.git
cd peerdb
# Run docker containers: peerdb-server, postgres as catalog, temporal.
# This might take a few minutes, so get a cup of coffee! :)
docker compose up
```
2. **Connect to PeerDB:**
```bash theme={null}
psql "port=9900 host=localhost password=peerdb"
```
That's it! You now have PeerDB up and running on your machine, ready to query away!
### Quickstart
The following steps assume you have PeerDB running locally. We also need the Postgres
client tools (specifically `psql` and `pgbench`) installed and available on your
PATH.
#### Setup
This script reuses the PeerDB internal Postgres instance to setup two databases, which we can use to create two peers. It also creates some tables on both databases to use later in the quickstart. Run the following commands in your terminal:
```bash theme={null}
curl -O https://raw.githubusercontent.com/PeerDB-io/peerdb/main/quickstart_prepare_peers.sh
chmod +x quickstart_prepare_peers.sh
./quickstart_prepare_peers.sh
```
#### Creating Peers
With PeerDB running, we can create our first peers.
Connect to PeerDB via psql and run the below commands to create the `source` and `target` peers:
```bash theme={null}
psql "port=9900 host=localhost password=peerdb"
```
```sql theme={null}
CREATE PEER source FROM POSTGRES WITH
(
host = 'catalog',
port = '5432',
user = 'postgres',
password = 'postgres',
database = 'source'
);
CREATE PEER target FROM POSTGRES WITH
(
host = 'catalog',
port = '5432',
user = 'postgres',
password = 'postgres',
database = 'target'
);
```
#### Real-time CDC
Run the following command to kick off Change Data Capture (CDC) based streaming from source peer to target peer for the `test` table.
```sql theme={null}
--- CDC mirrors automatically create the destination table
CREATE MIRROR cdc_mirror FROM source TO target
WITH TABLE MAPPING (public.test:public.test)
WITH(do_initial_copy = true);
```
Now that our CDC mirror is set up, it will automatically replicate data from the source to the target peer. Let's insert a row in the source table via PeerDB itself.
```sql theme={null}
--- Verify that the source table has zero rows
SELECT id,c1,c2,t FROM source.public.test;
```
```sql theme={null}
--- Insert a row into the source table
INSERT INTO source.public.test(c1, c2, t) VALUES(1, 2, 'oathbringer');
```
Within a few seconds, the row should be replicated to the target table. Let's verify this by running the following command:
```sql theme={null}
--- CDC mirrors replicate data as-is, so the row should be identical.
SELECT id,c1,c2,t FROM target.public.test;
```
The output should look like this:
```bash theme={null}
peerdb=> SELECT id,c1,c2,t FROM target.public.test;
id | c1 | c2 | t
----+----+----+-------------
1 | 1 | 2 | oathbringer
(1 row)
```
The above MIRROR takes care of replicating all DML commands (INSERT, UPDATE, DELETE) from source to target.
#### Streaming Query from PostgreSQL
Run the following command to kick off query based streaming from source peer to target peer. You are able to mask `c1`,`c2` and `t` columns by hashing them prior to streaming them to the target.
```sql theme={null}
CREATE MIRROR qrep_mirror FROM source TO target
FOR $$
SELECT id, hashint4(c1) c1, hashint4(c2) c2, md5(t) AS t
FROM test WHERE id BETWEEN {{.start}} AND {{.end}}
$$ WITH (
watermark_table_name='public.test',
watermark_column='id',
num_rows_per_partition = 10000,
destination_table_name='public.test_transformed',
setup_watermark_table_on_destination=true,
mode='append'
);
/*'append' mode indicates that the records in the source
table are write-once and never updated.*/
```
Now our mirror is set up. You should see the results of the above SELECT query replicated on the target peer.
```sql theme={null}
SELECT id, c1 as hash_c1, c2 as hash_c2, t as hash_t FROM target.public.test_transformed;
```
The output should look like this:
```sql theme={null}
peerdb=> SELECT * FROM target.public.test_transformed;
id | hash_c1 | hash_c2 | hash_t
--+-------------+------------+----------------------------------
1 | -1905060026 | 1134484726 | 0e6014773782cbc514100d54328da18f
(1 row)
```
#### Mirrors are continuous
As you add more rows to the `test` table on the source, the above MIRRORs take care of replicating the data to both `test` and `test_transformed` table on the target.
Insert a new row on the source:
```sql theme={null}
-- insert a new row
INSERT INTO source.public.test(c1, c2, t) VALUES(1, 2, 'oauthereceiver');
-- Check data on the source
SELECT id,c1,c2,t FROM source.public.test;
```
Check the new row added to target tables
```sql theme={null}
-- After a few seconds, check the second row added to the target tables
SELECT id,c1,c2,t FROM target.public.test;
SELECT * FROM target.public.test_transformed;
```
### FAQ
If you have any questions about the PeerDB setup and deployment process, don't hesitate to reach out on [Slack](https://slack.peerdb.io). We're more than happy to assist and answer any questions, including:
* What is the performance I can expect during CDC and query based replication?
* How do I know my data sync is successful?
* Can I set a specific time to start my data sync?
If there are any unanswered questions, we'd love to help you get started. Feel free to ask your questions on our community [Slack](https://slack.peerdb.io) channel.
In addition to this, if you require direct access to our team for any assistance, don't hesitate to contact us to discuss our premium support offerings.
# PeerDB Streams for Kafka Quickstart Guide
Source: https://docs.peerdb.io/quickstart/streams-quickstart
Get started with PeerDB Streams for Kafka in a few simple steps.
### Deploying PeerDB
We currently support deploying and testing PeerDB using our Docker Compose file.
Docker can be installed by referring to [these instructions](https://www.docker.com/products/docker-desktop).
The `docker compose` tool should also be present. The Postgres client tools (specifically
`psql`) are used to test the PeerDB installation.
**Run the following commands in your terminal:**
```bash theme={null}
git clone --recursive https://github.com/PeerDB-io/peerdb.git
cd peerdb
# Run docker containers: peerdb-server, postgres as catalog, temporal.
# This might take a few minutes, so get a cup of coffee! :)
./run-peerdb.sh
```
That's it! You now have PeerDB up and running on your machine, ready to query away!
### Quickstart
The following steps assume you have PeerDB running locally. We also need `psql` installed and available on your
PATH.
## Setup
This script reuses the PeerDB internal Postgres instance to setup two databases, which we can use to create two peers. It also creates some tables on both databases to use later in the quickstart. Run the following commands in your terminal:
```bash theme={null}
curl -O https://raw.githubusercontent.com/PeerDB-io/peerdb/main/quickstart_prepare_peers.sh
chmod +x quickstart_prepare_peers.sh
./quickstart_prepare_peers.sh
```
### Creating Peers
With PeerDB running, we can create our first peers.
Head over to `localhost:3000` on your browser. This is the PeerDB Dashboard.
Clicking on **Peers** in the sidebar will take us to the **Peers** page.
#### Creating Source Postgres Peer
Let's click on the Create Peer button at the top right to get started.
Now, we select the data store for which we wish to create a peer. Let's select **Postgres** and click on the **Continue** button.
This takes to a form where we can fill in the details for the peer. Let's fill in the details of our PostgreSQL peer.
Fill in the **password** as `postgres`.
PeerDB validates the connection details and if everything is correct, clicking on **Validate** should show a success message.
Finally, click on **Create** to create the peer.
We now have our **source PostgreSQL peer** ready.
#### Creating Target Kafka Peer
Let's create the **target Kafka peer**.
First lets start a local Kafka (or Redpanda) instance.
```bash theme={null}
mkdir redpanda-setup && cd redpanda-setup
curl -O https://docs.redpanda.com/redpanda-labs/docker-compose/_attachments/single-broker/docker-compose.yml
docker compose up -d
# connect to the peerdb_network network
docker network connect peerdb_network $(docker container ls -qf "name=redpanda-0")
docker network connect peerdb_network $(docker container ls -qf "name=redpanda-console")
```
Once you go to the create peers page, select Kafka as the option.
Fill in the various fields:
* Name: `target`
* Servers: `redpanda-0:9092`
* SASL Mechanism: `Scram SHA 256`
* Partitioner: `Least Backup`
* Disable TLS: `true`
Then click the **Create Peer** button.
Clicking on **Mirrors** in the sidebar will take us to the **Mirrors** page.
#### Real-time CDC
Lets start by creating a CDC mirror. In the side-bar click on **Mirrors**, and then **CDC Mirror**.
Scrolling down, we can see a section to a **select the table** on our source PostgreSQL peer to sync.
Let's select the table we have ready - `public.test`.
Now that we've filled in all the mirror details.
Let's click on **Create Mirror**, which will validate to check if everything is set up correctly, much like we did when creating peers and then will create the mirror.
Connect to PeerDB via psql:
```bash theme={null}
psql "port=9900 host=localhost password=peerdb"
```
And now we can run the below commands.
```sql theme={null}
--- Verify that the source table has zero rows
SELECT id,c1,c2,t FROM source.public.test;
```
```sql theme={null}
--- Insert a row into the source table
INSERT INTO source.public.test(c1, c2, t) VALUES(1, 2, 'oathbringer');
```
Within a minute, the row should be replicated to the target table. Let's click the mirror link on the `Mirrors` page which we landed on after creating the mirror:
This takes to the **Mirror Overview** page. Let's click on the **Sync Status tab**, where we can see the status of the mirror and the number of rows replicated:
We can see that the mirror has successfully replicated the row from the source to the target peer. Let's verify this by querying the target topic.
Head over to [Redpanda Console](http://localhost:8080/topics), click on the `public.test` topic:
The above MIRROR takes care of replicating all future DML commands (`INSERT`, `UPDATE`, `DELETE`) from source to target.
### FAQ
If you have any questions about the PeerDB setup and deployment process, don't hesitate to reach out on [Slack](https://slack.peerdb.io). We're more than happy to assist and answer any questions, including:
* What is the performance I can expect during CDC and query based replication?
* How do I know my data sync is successful?
* Can I set a specific time to start my data sync?
If there are any unanswered questions, we'd love to help you get started. Feel free to ask your questions on our community [Slack](https://slack.peerdb.io) channel.
In addition to this, if you require direct access to our team for any assistance, don't hesitate to contact us to discuss our premium support offerings.
# Creating Mirrors
Source: https://docs.peerdb.io/sql/commands/create-mirror
Guide to creating synchronization jobs in PeerDB
PeerDB introduces CREATE MIRROR command for blazing fast syncs between Peers. This section captures different types of MIRRORs and how to kick them off.
## Command Reference
### MIRROR for CDC
This type of MIRROR streams change feed in real-time from source peer to target peer.
The table mapping section supports two syntaxes, show below, and both can be used in the same mapping.
The second syntax with the JSON-like structure is useful when you want to exclude certain columns from the sync with `exclude:[]`
Note that for BigQuery and Clickhouse mirrors, the target tables should not be schema qualified.
```sql theme={null}
CREATE MIRROR [IF NOT EXISTS]
FROM TO
WITH TABLE MAPPING
(
.:.,
.:.,
{
from: .,
to: .,
exclude: [column1, column2 ,column3...]
}
)
WITH (
do_initial_copy = , -- required
max_batch_size = ,
sync_interval = ,
publication_name = '',
replication_slot_name = '', -- applicable only when do_initial_copy is false
snapshot_num_rows_per_partition = ,
snapshot_max_parallel_workers = ,
snapshot_num_tables_in_parallel = ,
soft_delete = ,
synced_at_col_name = '',
soft_delete_col_name = ''
);
```
1. **do\_initial\_copy**: `true` if you want to include initial snapshot of tables as a part of the MIRROR, else `false`.
2. **max\_batch\_size**: Maximum number of rows to be synced in a single batch.
3. **sync\_interval**: Interval in seconds at which the mirror should sync the changes.
4. **publication\_name**: Name of the publication on the source peer. This is optional as PeerDB creates the publication it needs anyway.
By creating a publication and providing it here, however, you do not need to provide write access to the database and tables (since that's needed for PeerDB to create the publication).
5. **replication\_slot\_name**: Name of the replication slot on the source peer. Do not set this if initial load is enabled.
This is optional as PeerDB creates the slot it needs by default. A use-case for this setting is when you want to resume a change-data capture from an existing replication slot.
6. **snapshot\_num\_tables\_in\_parallel**: In the initial snapshot, number of tables to be snapshotted at in parallel.
7. **snapshot\_num\_rows\_per\_partition**: In the initial snapshot, PeerDB divides the rows of each table into partitions of these many rows, and syncs those partitions.
8. **snapshot\_max\_parallel\_workers**: In the initial snapshot, number of threads used per table. Max number of concurrent connections on source will be `snapshot_num_tables_in_parallel * snapshot_max_parallel_workers`
9. **soft\_delete**: `true` if you want to soft delete rows on the target peer when they are deleted on the source peer.
10. **synced\_at\_col\_name**: Column name to be used for tracking the last synced timestamp. Default is `_PEERDB_SYNCED_AT`.
11. **soft\_delete\_col\_name**: Column name to be used for tracking the soft delete status. Default is `_PEERDB_IS_DELETED`.
### MIRROR for Streaming Query Results
Streaming Query Replication (QRep), including XMIN-based replication, is a deprecated mirror type and no longer actively maintained. It remains fully functional and no code is currently being removed. We recommend the **MIRROR for CDC** type above as the actively-maintained mirror type for new mirrors.
This type of MIRROR periodically streams query results on the source peer to the target peer.
```sql theme={null}
CREATE MIRROR [IF NOT EXISTS] FROM
TO FOR
$$
SELECT * FROM WHERE
BETWEEN {{.start}} AND {{.end}}
$$
WITH (
destination_table_name = '',
watermark_column = '',
watermark_table_name = '',
mode = '',
unique_key_columns = '',
parallelism = ,
refresh_interval = ,
num_rows_per_partition = 100000,
initial_copy_only = ,
setup_watermark_table_on_destination = ,
);
```
The `OPTIONS` clause provides granular control when configuring the MIRROR:
1. **watermark\_column (Required)** represents a sequentially incrementing integer or timestamp column. PeerDB uses this column to keep track of the processed rows and the ones that need to be processed.
2. **watermark\_table (Required)** is the table that PeerDB iterates sequentially based on the watermark\_column. The fact table is a good candidate for the watermark\_table.
3. **mode (Required)** tells PeerDB whether it should append data to the target or perform an upsert operation (update if the row exists).
1. If your data is append-only, a sequential ID or a created\_at column can be a good watermark, and you can choose the mode **append.**
2. If your data is updated, make sure to have an "updated\_at" column for PeerDB to identify the most recent version of the row. Choose the mode **upsert** to update already existing rows on the target.
1. **unique\_key:** In the upsert mode, you need to specify a set of columns (unique\_key) that uniquely identify a row. This helps perform the upsert operation.
4. **parallelism (Optional)** represents the number of threads used to read from the source and sync to the target. This helps with workload management on the source and target.
1. If you have a powerful PostgreSQL server or if it is a read-replica, you can configure a higher parallelism value. In scenarios where you want to put less load on the source, you can choose a lower value.
5. **refresh\_interval (Optional)** helps configure the frequency (in seconds) at which the sync should run. If not specified, PeerDB attempts to sync new rows every **10** seconds.
6. **initial\_copy\_only (Optional)**: If only a one-time copy needs to be done, this can be set to true. The mirror stops after a one-time data load. Apart from specifying **append** or **upsert** modes, a new mode **overwrite** can be specified when this option is set to true. This truncates all destination tables before starting the mirror, and is functionally identical to **append** otherwise.
7. **num\_rows\_per\_parition (Required)**: PeerDB internally splits a table into partitions of a certain size which it distributes amongst the worker threads. This option allows you to tune the size of each partition based on memory or network requirements.
8. **setup\_watermark\_table\_on\_destination (Optional)**: If set to true, a table with the same schema as the watermark table is created on the destination peer. Its name will be set to **destination\_table\_name**.
9. More details on the OPTIONs can be found [here](https://github.com/PeerDB-io/peerdb/issues/139).
10. `if_not_exists`: If specified, the MIRROR will be created only if it does not exist.
#### XMIN Query Replication
XMIN Query Replication is a deprecated mirror type and no longer actively maintained. It remains fully functional and no code is currently being removed. We recommend the **MIRROR for CDC** type as the actively-maintained mirror type for new mirrors.
PeerDB supports `xmin` as watermark column. Note that DELETEs are not supported in XMIN Query Replication.
```sql theme={null}
CREATE MIRROR xmin_mirror_1 FROM pg_test_peer TO sf_test_peer FOR
$$ SELECT * FROM users $$
WITH (
destination_table_name = 'public.users',
watermark_column = 'xmin',
watermark_table_name = 'public.users',
mode = 'append', -- upsert (only updates) and overwrite are also supported
parallelism = 10,
refresh_interval = 30,
num_rows_per_partition = 100
);
```
# Creating Peers
Source: https://docs.peerdb.io/sql/commands/create-peer
Guide to creating Peers in PeerDB
PeerDB currently supports the below types of Peers. To connect a database to PeerDB, you need to create a Peer. A Peer is a connection to a database that PeerDB can query. Peers are created using the `CREATE PEER` command.
1. [BigQuery](#bigquery-peer)
2. [Snowflake](#snowflake-peer)
3. [PostgreSQL](#postgresql-peer)
4. [MySQL](#mysql-peer)
5. [CockroachDB](#cockroachdb-peer)
6. [Storage Peers - S3 and Google Cloud](#storage-peers-s3-and-gcs)
7. [Azure EventHubs](#eventhub-peer)
8. [ClickHouse](#clickhouse-peer)
## BigQuery Peer
### Create Peer using UI
Using the PeerDB UI (localhost:3000), create the Snowflake Peer. See below video as reference:
### Create Peer using connection string
```sql theme={null}
CREATE PEER bq_peer FROM BIGQUERY WITH
(
type = 'service_account',
project_id = '',
private_key_id = '',
private_key = '',
client_email = '',
client_id = '',
auth_uri = '',
token_uri = '',
auth_provider_x509_cert_url = '',
client_x509_cert_url = '',
dataset_id = ''
);
-- Query away tables in BigQuery
SELECT * FROM bq_peer.test_table;
```
### Authentication
PeerDB authenticates the creation of a BigQuery peer based on the service account. All the fields within the `CREATE PEER` command can be acquired from a service account JSON.
If you have a service account key, you can use that or [create a new one](https://cloud.google.com/iam/docs/keys-create-delete) dedicated for PeerDB.
Make sure you have the right permissions for the service account, PeerDB
requires at least read permissions for querying. For MIRROR it requires both
read and write.
### Considerations
1. **Dataset Specific:** PeerDB only supports querying tables within a dataset. Cross dataset joins are not supported yet.
2. **Supported Datatypes:** All string, numeric and timestamp based datatypes are supported for querying. Record and Struct data-types are projected as JSONB. JSON datatype in BQ is not supported yet.
3. **SQL Coverage:** Most SQL constructs in reads incl. Simple Selects, JOINs, aggregations, window functions, CTEs etc are supported. You can run both Postgres compatible and BQ compatible queries through PeerDBs interface.
4. **Error Handling:** If a query fails on the BigQuery side because of lack of auth or query coverage or timeout, PeerDB handles that error and propagates the entire message as a JSON text to the end-user. We also capture this ERROR message within PeerDB logs.
## Snowflake Peer
### Create Peer using UI
Using the PeerDB UI (localhost:3000), create the Snowflake Peer. See below video as reference:
### Create Peer using connection string
```sql theme={null}
CREATE PEER sf_peer FROM SNOWFLAKE WITH
(
account_id = '',
username = '',
private_key ='',
password = '' -- only provide when the private key is encrypted
database = '',
schema = '',
warehouse = '',
role = '',
query_timeout = ''
);
-- Query away tables in Snowflake
SELECT * FROM sf_peer..;
```
### Granting permissions
PeerDB needs to be able to create, read and write to objects in the database you provide. The following commands ensure a smooth mirror:
```sql theme={null}
GRANT ALL PRIVILEGES ON DATABASE TO ROLE ;
GRANT USAGE ON SCHEMA TO ;
GRANT ALL ON SCHEMA TO ;
```
More information can be found [here](https://docs.snowflake.com/en/user-guide/security-access-control-configure#label-security-custom-role).
### Authentication
PeerDB authenticates the creation of a Snowflake peer based key pair authentication. Encrypted private keys are also supported.
Refer to this [doc](https://docs.snowflake.com/en/user-guide/key-pair-auth#configuring-key-pair-authentication) to create key pair, assign them to the right role and help populate the above fields.
### Considerations
1. **Database Specific:** PeerDB only supports querying tables within a database. Cross database joins are not supported yet.
2. **Supported Datatypes:** All string, numeric and timestamp based datatypes are supported for querying.
3. **SQL Coverage:** Most SQL constructs in reads incl. Simple Selects, JOINs, aggregations, window functions, CTEs etc are supported. You can run both Postgres compatible and SF compatible queries through PeerDBs interface.
4. **Error Handling:** If a query fails on the Snowflake side because of lack of auth or query coverage or timeout, PeerDB handles that error and propagates the entire message as a JSON text to the end-user. We also capture this ERROR message within PeerDB logs.
## PostgreSQL Peer
### Create Peer using UI
Using the PeerDB UI (localhost:3000), create the Postgres Peer. See below video as reference:
### Create Peer using connection string
```sql theme={null}
CREATE PEER postgres_peer FROM POSTGRES WITH
(
host = '',
port = '',
user = '',
password = '',
database = ''
);
-- Query away tables in Postgres
SELECT * FROM postgres_peer..;
```
If you are connecting to a Docker Postgres instance on the same docker network as PeerDB, then the hostname will be the service name of the Postgres server and the port will be `5432`.
### Considerations
1. **Supported Datatypes:** All string, numeric and timestamp based datatypes are supported for querying. We are actively addding support for other types.
2. **Unsupported COPY command:** COPY command is not supported yet.
### SSH Tunneling Configuration (Optional)
You can connect to a PostgreSQL database through a bastion host using SSH tunneling.
Here's a [guide on setting up an SSH tunnel for PeerDB.](/connect/postgres/rds_postgres#peerdb-ssh-tunneling-guide-optional)
Then, create a PostgreSQL peer using an SSH tunnel:
```sql theme={null}
CREATE PEER ssh_postgres_peer FROM POSTGRES WITH
(
host = '',
port = 5432,
user = '',
password = '',
database = '',
ssh_config = '{
"host": "",
"port": 22,
"user": "",
"password": "",
"private_key": ""
"host_key": "host_key" -- optional
}'
);
```
Note that the input for the private key here expects a base64 encoded private key.
The host key input is optional and is for preventing MITM attacks.
## Storage Peers - S3 and GCS
### Create Peer using UI
Using the PeerDB UI (localhost:3000), create the Snowflake Peer. See below video as reference:
### Create Peer using connection string
For CDC, you would require a PostgreSQL instance to use as an external metadata store.
The CREATE PEER command for S3/GCS depends on how you set the following parameters.
```sql theme={null}
CREATE PEER storage_peer FROM S3 WITH
(
url = 's3:///', -- bucket should exist
access_key_id = '', -- or AWS equivalent
secret_access_key = '', -- or AWS equivalent
region = 'auto', -- for S3, use the region of your bucket
endpoint = 'https://storage.googleapis.com', -- or empty for S3
metadata_db = 'host= port= user= password= database='
);
```
Note that if you leave any of these parameters empty, PeerDB will use the corresponding Docker compose environment variable instead:
```yaml theme={null}
x-flow-worker-env: &flow-worker-env
...
# For GCS, these will be your HMAC keys instead
# For more information:
# https://cloud.google.com/storage/docs/authentication/managing-hmackeys
AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-}
AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-}
# For GCS, set this to "auto" without the quotes
AWS_REGION: ${AWS_REGION:-}
# For GCS, set this as: https://storage.googleapis.com
AWS_ENDPOINT: ${AWS_ENDPOINT:-}
...
```
### Considerations
1. The bucket specified in the URL must already exist.
2. Only `.avro` file format is currently supported.
3. Currently only data-movement is supported for this type of peer. Querying this peer from PeerDB's interface is not supported.
## Clickhouse Peer
You can create a Clickhouse peer using the following SQL syntax:
```sql theme={null}
CREATE PEER FROM CLICKHOUSE
WITH
(
host='',
port=,
user='',
password='',
database='',
-- disable_tls = true
);
```
* For local docker installations of Clickhouse and if you're using PeerDB OSS, the host will be `host.docker.internal`, with the port being the external port.
* The `disable_tls` parameter is optional and can be set to `true` if you are using a Clickhouse instance without TLS.
* PeerDB maintains an ephemeral internal stage for Clickhouse using a [min.io](https://min.io/) bucket.
You can configure your own bucket (S3/min.io/GCS) by passing the following optional parameters:
```sql theme={null}
CREATE PEER FROM CLICKHOUSE
WITH
(
host='',
port=,
user='',
password='',
database='',
-- (Optional) S3 stage of yours:
s3_path = 's3://',
access_key_id = '',
secret_access_key = '',
region = '',
endpoint = '' -- for GCS: https://storage.googleapis.com
);
```
## MySQL Peer
```sql theme={null}
CREATE PEER mysql_peer FROM MYSQL WITH (
host='',
port=3006,
user=''
password='',
database='',
setup='set session transaction level read only',
disable_tls=false
);
```
### Considerations
1. Currently only querying is supported for this type of peer. Mirrors are not supported.
2. `setup` is optional, but can be used to run queries when connection setup. Useful for setting transactions as read only by default, or setting catalog/database with `use catalog.database` for [StarRocks](https://www.starrocks.io)
## CockroachDB Peer
```sql theme={null}
CREATE PEER cockroachdb_peer FROM COCKROACHDB WITH
(
host = '',
port = '26257',
user = '',
password = '',
database = '',
root_ca = '',
tls_host = ''
);
```
To connect through an SSH tunnel, add an `ssh_config` option with the same JSON shape as the [PostgreSQL peer](#postgresql-peer):
```sql theme={null}
ssh_config = '{
"host": "",
"port": 22,
"user": "",
"password": "",
"private_key": ""
}'
```
**Parameters:**
| Parameter | Description | Required |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `host` | Hostname of the CockroachDB cluster. | Yes |
| `port` | SQL port of the cluster. Defaults to `26257`. | Yes |
| `user` | User PeerDB connects as. | Yes |
| `password` | Password of the user. Can be omitted for `root` connections to insecure clusters. | No |
| `database` | Database to replicate from. | Yes |
| `disable_tls` | Set to `'true'` only for insecure clusters. TLS is enabled by default, and CockroachDB Cloud requires it. | No |
| `root_ca` | Root CA certificate (PEM) used to verify the server certificate, for clusters whose certificate is not signed by a publicly trusted CA. | No |
| `tls_host` | Hostname to verify the server certificate against, if it differs from `host` (for example when connecting through a load balancer). | No |
| `skip_cert_verification` | Set to `'true'` to skip server certificate verification. Only for testing. | No |
| `client_tls` | JSON object with `certificate` and `private_key` (PEM) for certificate-based client authentication. | No |
| `ssh_config` | JSON object describing an SSH tunnel, see above. | No |
### Considerations
1. PeerDB's test suite runs against CockroachDB v24.1, v25.4 (LTS) and v26.2.
2. CDC mirrors require the cluster setting `kv.rangefeed.enabled = true` on self-hosted clusters. It is enabled by default on CockroachDB Cloud Standard and Basic clusters. See the [changefeed prerequisites](https://www.cockroachlabs.com/docs/stable/create-and-configure-changefeeds) in the CockroachDB docs.
3. Mirror validation requires an effective `gc.ttlseconds` of at least 24 hours on every replicated table.
4. See the [CockroachDB Setup Guide](/connect/cockroachdb) for user permissions, TLS setup and garbage collection guidance.
## EventHub Peer
To create an Eventhub peer, use the following SQL syntax:
```sql theme={null}
CREATE PEER eventhubs_peer_x FROM EVENTHUBS WITH (
eventhubs = '[{"subscription_id":"my-sub-id",
"resource_group":"myresource",
"namespace":"mynamespace-1",
"location":"eastus",
"partition_count":5,
"message_retention_in_days":2
},
{"subscription_id":"my-sub-id",
"resource_group":"myresource",
"namespace":"mynamespace-2",
"location":"eastus",
"partition_count":3,
"message_retention_in_days":1
}
]',
unnest_columns = [] -- can omit this field too
);
```
**Parameters:**
* `eventhubs`: A JSON array of details of namespaces. Each item should have the following fields:
* `subscription_id`: The ID of the Azure subscription.
* `resource_group`: The name of the Azure resource group.
* `namespace`: The namespace for the Eventhub.
* `location`: The location of the Eventhub namespace's resource group, e.g., eastus.
* `partition_count`: The number of partitions for the Eventhub.
* `message_retention_in_days`: The number of days the messages will be retained.
* `unnest_columns`: Specifies the columns you'd like to unnest
In order to use this peer in a self-hosted PeerDB instance, your **Azure credentials must be filled** in our PeerDB docker-compose file in the environments section of the `flow-worker` service:
```yaml theme={null}
environment:
AZURE_CLIENT_ID:
AZURE_CLIENT_SECRET:
AZURE_TENANT_ID:
```
### Considerations
1. Currently only CDC data-movement is supported for this type of peer. Querying this peer from PeerDB's interface is not supported.
# Dropping Mirrors
Source: https://docs.peerdb.io/sql/commands/drop-mirror
Guide to removing Mirrors in PeerDB
Use `DROP MIRROR` to remove a mirror configuration from PeerDB.
## Syntax
```sql theme={null}
DROP MIRROR [IF EXISTS] ;
```
## Behavior
* Removes the mirror configuration and stops any scheduled syncs for the mirror.
* If the mirror does not exist and `IF EXISTS` is omitted, the command returns an error.
## Considerations
1. Dropping a mirror will not automatically remove data from the target peer; it only stops synchronization.
# Dropping Peers
Source: https://docs.peerdb.io/sql/commands/drop-peer
Guide to removing Peers from PeerDB
Use `DROP PEER` to remove a peer configuration from PeerDB.
## Syntax
```sql theme={null}
DROP PEER [IF EXISTS] ;
```
## Behavior
* When `IF EXISTS` is provided, the command is a no-op if the peer is missing.
* Dropping a peer removes its connection metadata from PeerDB and prevents any future queries or mirrors from using it.
## Considerations
1. All mirrors referencing this peer should be [deleted first](/sql/commands/drop-mirror); dropping a peer with active mirrors will have no effect.
2. Dropping a peer does not remove any data that was previously synced to target peers.
3. For safety in production, prefer `IF EXISTS` and ensure mirrors are removed or migrated beforehand.
# Executing Raw Queries
Source: https://docs.peerdb.io/sql/commands/execute
Guide to executing raw queries against a Peer using EXECUTE
Use the EXECUTE command to send a raw SQL query directly to a configured Peer. This bypasses PeerDB's query-rewriting layer and sends the provided query text to the remote database behind the named peer.
## Syntax
```sql theme={null}
EXECUTE ();
```
Notes:
* `` must be the name of an [existing peer](/sql/commands/create-peer).
* `` is a string literal containing the SQL to run on the remote peer.
## Examples
Run a simple select on a Postgres peer:
```sql theme={null}
EXECUTE postgres_peer('SELECT id, name FROM public.users WHERE id < 10;');
```
Run a statement that creates a temporary table on the remote peer:
```sql theme={null}
EXECUTE postgres_peer('CREATE TEMP TABLE tmp_select AS SELECT id FROM public.users LIMIT 100;');
```
## Behavior
* The query text is forwarded verbatim to the remote database connection associated with the peer.
* Results are returned to the caller exactly as the remote database would return them.
## Considerations
1. The remote query runs with the credentials configured for the peer. Ensure the peer's credentials have the minimal privileges required.
2. Since the query runs directly on the remote system, it can modify data or schema. Be cautious when running DDL or DML via `EXECUTE` in production environments.
3. The query must use the dialect and capabilities of the remote database type.
# Pausing Mirrors
Source: https://docs.peerdb.io/sql/commands/pause-mirror
Guide to pausing Mirrors in PeerDB
`PAUSE MIRROR` temporarily stops a mirror from syncing. Use this to perform maintenance, inspections, or configuration changes without deleting the mirror.
1. As of today, mirrors can only be paused during CDC and not during initial load or query replication.
2. The PostgreSQL source replication slot will still exist and it will continue to grow as long the mirror is paused.
3. Pausing a mirror enables you to then add tables to the CDC mirror, along with editing the Sync Interval and Pull Batch Size.
At the moment, there is no syntax available to add tables or edit the sync interval and pull batch size using SQL commands; you need to use [the UI](/features/edit-mirror) or [API](/peerdb-api/endpoints/change-mirror-state) to perform these actions.
## Syntax
```sql theme={null}
PAUSE MIRROR [IF EXISTS] ;
```
## Behavior
* When `IF EXISTS` is provided, the command is a no-op if the mirror is missing.
* If the mirror is currently active, the command will stop future sync runs and attempt to gracefully pause any in-flight work.
* If the mirror is already paused, the command is a no-op.
## Considerations
1. Pausing preserves the mirror configuration and state so it can be resumed later with [Resume Mirror](/sql/commands/resume-mirror).
# Resuming Mirrors
Source: https://docs.peerdb.io/sql/commands/resume-mirror
Guide to resuming paused Mirrors in PeerDB
Use `RESUME MIRROR` to restart a mirror that was previously [paused](/sql/commands/pause-mirror).
## Syntax
```sql theme={null}
RESUME MIRROR [IF EXISTS] ;
```
## Behavior
* When `IF EXISTS` is provided, the command is a no-op if the mirror is missing.
* The mirror will be scheduled to continue syncing according to its configuration.
* If the mirror is already running, the command is a no-op.
# Resyncing Mirrors
Source: https://docs.peerdb.io/sql/commands/resync-mirror
Guide to resyncing Mirrors in PeerDB
PeerDB allows you to resync a Change-Data Capture (CDC) mirror. Resync is currently supported for the following target connectors:
1. Clickhouse
2. PostgreSQL
3. Snowflake
4. BigQuery
## Syntax
```sql theme={null}
RESYNC MIRROR [IF EXISTS] ;
```
## Behavior
* When `IF EXISTS` is provided, the command is a no-op if the mirror is missing.
* For more details on mirror resync, refer to the [documentation](/features/resync-mirror).
# Supported connectors
Source: https://docs.peerdb.io/sql/commands/supported-connectors
The actively-maintained destinations are **ClickHouse**, **ClickHouse Cloud**, and **Postgres**. The destinations marked *(deprecated)* below (Snowflake, ElasticSearch, Kafka including the Confluent and Redpanda variants, Azure Event Hubs, Google Pub/Sub, S3, GCS, and BigQuery) are deprecated and no longer actively maintained. They remain fully functional and no code is currently being removed. BigQuery is deprecated **only as a destination**; it remains a **supported source**.
Streaming Query Replication (QRep), including XMIN-based replication, is also a deprecated mirror type. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors.
Below table shows supported source and target connectors for [Real-time Change Data Capture](/usecases/real-time-cdc/overview) and [Streaming Query Replication](/usecases/streaming-query-replication/overview). ✅ means supported. ⚠️ means beta. 🛑 means unsupported
| Source | Target | Real-time Change Data Capture (CDC) | Streaming Query or Watermark Based Replication | Guides |
| ---------- | -------------------------------------- | ----------------------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| PostgreSQL | Snowflake *(deprecated)* | ✅ | ✅ | [CDC](/usecases/real-time-cdc/postgres-to-snowflake),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-snowflake) |
| PostgreSQL | BigQuery *(deprecated as destination)* | ✅ | ✅ | [CDC](/usecases/real-time-cdc/postgres-to-bigquery),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-bigquery) |
| PostgreSQL | PostgreSQL | ✅ | ✅ | [CDC](/usecases/real-time-cdc/postgres-to-postgres),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-postgres) |
| PostgreSQL | Clickhouse | ✅ | ✅ | [https://docs.peerdb.io/mirror/cdc-pg-clickhouse](https://docs.peerdb.io/mirror/cdc-pg-clickhouse) |
| PostgreSQL | S3 *(deprecated)* | ✅ | ✅ | [CDC](/usecases/real-time-cdc/postgres-to-cloud),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-s3) |
| PostgreSQL | GCS *(deprecated)* | ✅ | ✅ | [CDC](/usecases/real-time-cdc/postgres-to-cloud),[Streaming Query Replication](/usecases/streaming-query-replication/postgres-to-s3) |
| PostgreSQL | Azure EventHubs *(deprecated)* | ✅ | 🛑 | [CDC](/usecases/real-time-cdc/postgres-to-azure-eventhubs) |
| PostgreSQL | Kafka *(deprecated)* | ⚠️ | 🛑 | Coming soon ! |
| PostgreSQL | Google PubSub *(deprecated)* | ⚠️ | ⚠️ | Coming soon ! |
We are actively adding more sources and targets. If you need any specific connector as a source or target to your PostgreSQL database reach out to us at [contact@peerdb.io](mailto:contact@peerdb.io)
# PeerDB SQL Reference
Source: https://docs.peerdb.io/sql/reference
PeerDB provides multiple SQL commands to interact with it. This page documents them.
* [Create Peer](/sql/commands/create-peer)
* [Execute](/sql/commands/execute)
* [Drop Peer](/sql/commands/drop-peer)
* [Create Mirror](/sql/commands/create-mirror)
* [Drop Mirror](/sql/commands/drop-mirror)
* [Pause Mirror](/sql/commands/pause-mirror)
* [Resume Mirror](/sql/commands/resume-mirror)
* [Resync Mirror](/sql/commands/resync-mirror)
# Streaming Query Replication of PostgreSQL To Snowflake
Source: https://docs.peerdb.io/tutorials/realtime-streaming-of-query-results
Streaming Query Replication (QRep) is a deprecated mirror type and no longer actively maintained. It remains fully functional and no code is currently being removed. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors. Snowflake as a destination is also deprecated.
Below is a 5-minute tutorial to test [Streaming Query Replication from Postgres to Snowflake](/usecases/realtime-streaming-of-query-results)
### Step 1: CREATE Postgres and Snowflake Peers
1. [CREATE Postgres PEER](/sql/commands/create-peer#postgresql-peer)
2. [CREATE Snowflake PEER](/sql/commands/create-peer#snowflake-peer)
### Step 2: Create and populate tables on the Postgres PEER
Run the following SQL on your PostgreSQL peer to create and populate `pgbench_history` with dummy data:
```sql theme={null}
DROP TABLE IF EXISTS pgbench_history;
CREATE TABLE pgbench_history (
tid integer,
bid integer,
aid integer,
delta integer,
mtime timestamp without time zone,
filler character(22)
);
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime, filler)
SELECT
(random() * 10)::int,
(random() * 10)::int,
(random() * 100000)::int,
(random() * 10000 - 5000)::int,
now() - (random() * interval '30 days'),
lpad('', 22)
FROM generate_series(1, 10000);
CREATE INDEX pgbench_history_mtime_idx ON pgbench_history(mtime);
```
### Step 3: Create pgbench\_history table on the destination (snowflake) PEER
```sql theme={null}
CREATE TABLE pgbench_history (tid integer, bid integer,
aid integer, delta integer, mtime timestampntz, filler text);
```
### Step 4: Kick off MIRROR with 8 threads and 50000 rows per partition
```sql theme={null}
CREATE MIRROR postgres_to_snowflake_tutorial
FROM postgres_peer TO snowflake_peer FOR
$$SELECT * FROM public.pgbench_history WHERE mtime BETWEEN {{.start}} AND {{.end}}$$
WITH (
watermark_column = 'mtime',
watermark_table_name = 'pgbench_history',
mode = 'append',
parallelism = 8,
refresh_interval = 10,
num_rows_per_partition = 50000,
destination_table_name = 'public.pgbench_history'
);
```
### Step 5: Monitor the MIRROR
You can connect to `localhost:8085` to gain full visibility into the different jobs and steps that PeerDB performs under the hood to manage the MIRROR.
### Step 6: Validate the MIRROR
In 1-2 minutes the MIRROR should complete syncing data. Now validate the data on both postgres and snowflake peers. Number of rows should match
```sql theme={null}
SELECT count(*) FROM postgres_peer.pgbench_history;
SELECT count(*) FROM snowflake_peer.public.pgbench_history;
```
# Query Federation via PostgreSQL
Source: https://docs.peerdb.io/usecases/postgres-compatible-layer-for-bigquery-and-snowflake
## Postgres-Compatible Query Layer for BigQuery and Snowflake
You can use PeerDB's Postgres-compatible SQL layer to query tables in BigQuery or Snowflake. You can leverage Postgres' hundreds of integrations, including client tools like pgadmin and psql, BI tools like Grafana and Power BI, and languages such as Python and Ruby to query data in BigQuery or Snowflake.
PeerDB parses and translates the incoming SQL query to make it compatible with the appropriate Peer. It pushes down most SQL constructs, including filters, JOINs, aggregates, sorts, limits etc., to the attached Peer. This enables blazing fast performance.
You can also query tables in BigQuery or Snowflake from your existing Postgres database by connecting PeerDB as a `postgres_fdw` FOREIGN SERVER.
> You can utilize postgres\_fdw's [advance](https://www.enterprisedb.com/blog/postgresql-aggregate-push-down-postgresfdw) push-down capabilities to maximize the performance of your queries involving BigQuery and Snowflake tables. For queries where push-down is important, you can expect **100x** performance gains compared to other foreign data wrappers.
Let's go through steps to query BigQuery and Snowflake using PeerDB.
### Step 1: Add BigQuery and Snowflake Peers
Run the following commands to let PeerDB know about the existing Postgres and Snowflake Peers:
```sql theme={null}
-- Connect to PeerDB
psql "port=9900 host=localhost password=peerdb"
-- Add Postgres and BigQuery peers
CREATE PEER bigquery_peer FROM bigquery (...);
CREATE PEER snowflake_peer FROM snowflake (...);
```
Make sure to replace **`(…)`** with the appropriate connection details for both the Postgres and Snowflake instances. More details on adding PEERs are available [here](/sql/commands/create-peer).
### Step 2: Query Tables in BigQuery and Snowflake
```sql theme={null}
-- Querying table(s) in BigQuery PEER
SELECT country, count(*), sum(id), count(distinct id), avg(id), max(id), min(id)
FROM bigquery_peer.users
WHERE id = 1 AND country = 'India'
GROUP BY country
HAVING count(*) > 0
ORDER BY country DESC
LIMIT 1;
-- Querying table(s) in Snowflake PEER
SELECT count(*)
FROM snowflake_peer.PUBLIC.EVENTS e
RIGHT JOIN snowflake_peer.PUBLIC.USERS u ON u.id = e.user_id
JOIN sf_test.PUBLIC.USERS u1 ON u1.id = u.id
WHERE u1.country = 'Indonesia';
```
You can find different variations of queries that should work out of the box for [BigQuery](https://github.com/PeerDB-io/peerdb/blob/main/nexus/server/tests/sql/bq.sql) and [Snowflake](https://github.com/PeerDB-io/peerdb/blob/main/nexus/server/tests/sql/snowflake.sql) in the provided links. Currently, only SELECT commands are supported, while DML and DDL commands are not yet.
## Query BigQuery and Snowflake using `postgres_fdw`
PeerDB enables you to query BigQuery or Snowflake from your existing Postgres database using `postgres_fdw`. As PeerDB is Postgres wire-compatible, you can connect to PeerDB as a **postgres\_fdw** FOREIGN SERVER from your Postgres database and start querying tables in Peers that have been created on PeerDB.
Let's walk through the steps to query tables in BigQuery from your existing Postgres database using PeerDB.
### Step 1: Create PeerDB as a FOREIGN SERVER to your Postgres database
```sql theme={null}
-- Creating PeerDB as a Foreign Server
-- if your postgres database is not running on the same machine make sure to open up the inbound port on the vm peerdb is running.
CREATE SERVER bigquery FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '', port '9900');
-- Creating a user mapping
CREATE USER MAPPING FOR postgres SERVER bigquery OPTIONS (user 'peerdb', password 'peerdb');
```
### Step 2: Create FOREIGN TABLE on Postgres pointing to tables in BigQuery
```sql theme={null}
-- Creating a FOREIGN TABLE pointing to BigQuery via PeerDB
CREATE FOREIGN TABLE events_bigquery (
id int,
user_id int,
event_type text,
os text,
device text,
ip text,
time_spent int,
domain_name text,
payload text
) SERVER bigquery OPTIONS (schema_name 'bigquery_peer', table_name 'events');
```
### Step 3: Start querying BigQuery FOREIGN TABLE from Postgres
```sql theme={null}
SELECT count(*) FROM events_bigquery;
SELECT count(*) FROM events_bigquery WHERE country = 'USA';
SELECT * FROM events_bigquery LIMIT 5;
```
### **Step 4: Join local Postgres tables with the BigQuery FOREIGN TABLE**
```sql theme={null}
SELECT count(*) FROM events_bigquery e JOIN users u ON e.user_id = u.id;
```
### Support
If you run into any issues, join our [slack channel](https://slack.peerdb.io) and reach out to us. You can file an issue on our [gihub repository](https://github.com/peerdb-io/peerdb) or reach out to [founders@peerdb.io](mailto:founders@peerdb.io) . We will follow up!
# Overview
Source: https://docs.peerdb.io/usecases/real-time-cdc/overview
## Real-time CDC from PostgreSQL
PeerDB introduces **CREATE MIRROR for streaming changes** to enable real-time Change Data Capture (CDC) from PostgreSQL to the Target peer. Currently we support **PostgreSQL (running anywhere)**, **Azure Event Hubs**, **BigQuery** and **Snowflake** as the target Peers.
1. You just need to run a few SQL commands, and PeerDB takes care of all the heavy lifting to set up and maintain a highly performant and resilient real-time synchronization between the databases.
> SQL commands make it super easy and intuitive to develop data pipelines in your test, dev, and prod environments.
2. In our initial benchmarks, we observed over 10x performance gains compared to other tools. The average lag for a workload that generates 1000 transactions per second on PostgreSQL was around 30 seconds.
### Demo
# PostgreSQL To Azure Event Hubs
Source: https://docs.peerdb.io/usecases/real-time-cdc/postgres-to-azure-eventhubs
Azure Event Hubs as a destination is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
Let's look at how we can seamlessly perform Change-Data Capturing (CDC) from PostgreSQL to topics in Azure EventHubs.
### Scenario
Suppose you have a banking application running on PostgreSQL. There are two tables: "users" and "transactions." You want to sync these tables in real-time to Event Hubs topics. Let's see how we can make this happen within a few minutes and a few SQL commands using PeerDB.
### Prerequisites
1. Enable logical decoding in PostgreSQL. Ensure that the following settings/GUCs are properly configured:
1. wal\_level: logical
2. max\_wal\_senders: >1
3. max\_replication\_slots: 4
2. Enable replication access for a PostgreSQL user - ALTER USER pg\_user REPLICATION;
3. Ensure that both tables have primary keys. Composite primaries are also fine. If not, make sure your tables have REPLICA IDENTITY FULL.
4. If you are using PostgreSQL on the cloud, below links capture how to enable logical replication for each cloud:
1. [AWS RDS and Aurora PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Replication.Logical.html#AuroraPostgreSQL.Replication.Logical.Configure)
2. [Azure Database for PostgreSQL - Flexible Server](https://learn.microsoft.com/azure/postgresql/flexible-server/concepts-logical#pre-requisites-for-logical-replication-and-logical-decoding)
3. [GCP Cloud SQL PostgreSQL](https://cloud.google.com/sql/docs/PostgreSQL/replication/configure-logical-replication#configure-your-postgresql-instance)
### Step 1: Add PostgreSQL and Event Hubs Peers
Run the following commands to let PeerDB know about the existing PostgreSQL and Event Hubs Peers.
```sql theme={null}
-- Connect to PeerDB
psql "port=9900 host=localhost password=peerdb"
-- Add PostgreSQL and Event Hubs peers
CREATE PEER postgres_peer FROM POSTGRES (...);
CREATE PEER eventhubs_peer FROM EVENTHUBS (...);
```
Make sure to replace **`(…)`** with the appropriate connection details for both the PostgreSQL and Event Hubs instances. More details on adding Peers are available [here](/sql/commands/create-peer).
### **Step 2: Real-Time CDC from PostgreSQL to Event Hubs**
The mirror from PostgreSQL to Eventhubs is unique, in the sense that you can sync source tables **across namespaces**,
and you can **specify a column whose values will be used to route data** into the partitions of the event hub.
To facilitate real-time Change Data Capture (CDC) from PostgreSQL to Event Hubs, set up your peers and then create a mirror using the following SQL syntax:
```sql theme={null}
CREATE MIRROR IF NOT EXISTS
FROM TO
WITH TABLE MAPPING(
.:..,
... -- Repeat as required for multiple tables
)
WITH(
max_batch_size = ,
publication_name = ''
);
```
Example:
```sql theme={null}
CREATE MIRROR IF NOT EXISTS test_eh_mirror
FROM test_pg_peer TO test_eh_peer
WITH TABLE MAPPING(
schema1.table1:mynamespace1.hub1.id,
schema1.table2:mynamespace2.hub2.id
-- Add more tables as required
)
WITH(
do_initial_copy = false,
max_batch_size = 300000,
publication_name = 'test_publication'
);
```
Parameters:
* **`mirror-name`**: Desired name for the mirror.
* **`postgres-peer-name`**: Name of the PostgreSQL peer.
* **`eventhubs-peer-name`**: Name of the Event Hubs group peer.
* **`namespace-name`**: Name of the namespace in which you wish to sync to an eventhub.
* **`eventhub-name`**: Name of the eventhub in which you wish to sync the data. PeerDB creates the eventhub for you if it doesn't exist already.
* **`partition_key_column`**: Column in the source table whose values will be used to route data into the partitions of the event hub.
* **`max_batch_size`**: Maximum number of records in a batch.
* **`publication_name`**: Name of the publication.
Remember to adjust placeholder values (\<...>) with your specific details and preferences.
The example above has been abbreviated for clarity; ensure you provide all the necessary mappings and configurations in practice.
### **Step 3: Validate the Mirror**
Validate the mirror by checking if the number of messages in the topics matches the row count on the source table.
```sql theme={null}
SELECT COUNT(*) FROM postgres_peer.public.transactions;
```
### Step 4: Monitor the MIRROR
You can connect to `localhost:8085` to get full visibility into the different jobs and steps that PeerDB is taking under the covers to manage the MIRROR.
### Step 5: DROP MIRROR
To make it easy in your development and test environments, PeerDB also introduces the DROP MIRROR command. DROP MIRROR drops all the underlying objects that CREATE MIRROR generates. More details are available in this [PR](https://github.com/PeerDB-io/peerdb/pull/93).
```sql theme={null}
-- drop the mirror
DROP MIRROR real_time_cdc;
```
# PostgreSQL to BigQuery
Source: https://docs.peerdb.io/usecases/real-time-cdc/postgres-to-bigquery
BigQuery as a **destination** is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination. Note that BigQuery remains a **supported source**.
### Scenario
Suppose you have a banking application running on PostgreSQL. There are two tables: "users" and "transactions." You want to sync these tables in real-time to BigQuery for analytics purposes, such as real-time fraud detection. Let's see how we can make this happen within a few minutes and a few SQL commands using PeerDB.
### Prerequisites
1. Enable logical decoding in Postgres. Ensure that the following settings/GUCs are properly configured:
1. wal\_level: logical
2. max\_wal\_senders: >1
3. max\_replication\_slots: 4
2. Enable replication access for a PostgreSQL user - ALTER USER pg\_user REPLICATION;
3. Ensure that both tables have primary keys. Composite primaries are also fine. If not, make sure your tables have REPLICA IDENTITY FULL.
4. If you are using PostgreSQL on the cloud, below links capture how to enable logical replication for each cloud:
1. [AWS RDS and Aurora PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Replication.Logical.html#AuroraPostgreSQL.Replication.Logical.Configure)
2. [Azure Database for PostgreSQL - Flexible Server](https://learn.microsoft.com/azure/postgresql/flexible-server/concepts-logical#pre-requisites-for-logical-replication-and-logical-decoding)
3. [GCP Cloud SQL PostgreSQL](https://cloud.google.com/sql/docs/postgres/replication/configure-logical-replication#configure-your-postgresql-instance)
### Step 1: Add Postgres and BigQuery Peers
Run the following commands to let PeerDB know about the existing Postgres and BigQuery Peers.
```sql theme={null}
-- Connect to PeerDB
psql "port=9900 host=localhost password=peerdb"
-- Add Postgres and BigQuery peers
CREATE PEER postgres_peer FROM postgres (...);
CREATE PEER bigquery_peer FROM bigquery (...);
```
Make sure to replace **`(…)`** with the appropriate connection details for both the PostgreSQL and BigQuery instances. More details on adding PEERs are available [here](/sql/commands/create-peer).
### **Step 2: Real-Time CDC from PostgreSQL to BigQuery**
With the peers set up, you can create a mirror that facilitates real-time CDC from PostgreSQL to BigQuery.
#### Create MIRROR using SQL
```sql theme={null}
-- Real-time CDC from PostgreSQL to BigQuery
CREATE MIRROR real_time_cdc
FROM postgres_peer TO bigquery_peer
WITH TABLE MAPPING (public.transactions:transactions, public.users:users)
WITH (
do_initial_copy = true,
snapshot_sync_mode='avro',
snapshot_num_rows_per_partition = 500000,
snapshot_max_parallel_workers = 4,
snapshot_num_tables_in_parallel = 4,
snapshot_staging_path = '' // Needed for AVRO snapshot mode
);
```
Since no CDC sync mode has been specified above, CDC will be performed in `sql` mode.
To perform CDC via AVRO mode, you must set the following:
```
cdc_sync_mode = 'avro'
cdc_staging_path = ''
```
If you observe, **TABLE MAPPING** represents the table name mapping between the two Postgres peers. The final `WITH` clause captures if you wanted to include initial snapshot as a part of the MIRROR. If you don't include that `WITH`, peerdb assumes that you don't want to perform an initial snapshot. If just reads the slot and replays the changes to the target.
1. Data type mapping between [Postgres and BigQuery](/datatypes/datatype-matrix).
2. If you want additional types to be supported or want to alter the existing data type mapping, please reach out to us. We can aim to support that within a few days. Also, PeerDB is [fully open source](https://github.com/PeerDB-io/peerdb), so feel free to submit a PR.
> **PeerDB also supports replicating TOAST columns very efficiently**. Unlike most CDC tools, you don't need to set up REPLICA IDENTITY FULL for replicating TOAST columns. This [PR](https://github.com/PeerDB-io/peerdb/pull/111) captures the infrastructural optimizations that PeerDB takes to support TOAST columns.
#### Create MIRROR using UI
If you prefer a UI, you can easily create a mirror using the PeerDB UI (localhost:3000). Refer to the below video:
### **Step 3: Validate the Mirror**
Through the same PeerDB's Postgres-compatible SQL interface, you can quickly validate the MIRROR (real-time CDC).
```sql theme={null}
-- Validate the mirror
SELECT COUNT(*) FROM bigquery_peer.transactions;
SELECT COUNT(*) FROM postgres_peer.public.transactions;
```
### Step 4: Monitor the MIRROR
You can connect to `localhost:8085` to get full visibility into the different jobs and steps that PeerDB is taking under the covers to manage the MIRROR.
### Coming Soon
1. Support for tables without primary keys using UNIQUE index or [REPLICA IDENTITY FULL](https://www.notion.so/f0e258f310dc4231ad35b6a210f7d4b1?pvs=21) will be added in a few weeks.
2. Handling Schema Changes will be added in a few weeks.
### Support
If you run into any issues, join our [slack channel](https://slack.peerdb.io) and reach out to us. You can file an issue on our [gihub repository](https://github.com/peerdb-io/peerdb) or reach out to [founders@peerdb.io](mailto:founders@peerdb.io) . We will follow up!
# PostgreSQL To AWS S3 And Google Cloud Storage
Source: https://docs.peerdb.io/usecases/real-time-cdc/postgres-to-cloud
S3 and GCS as destinations are deprecated and no longer actively maintained. They remain fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
PeerDB support Change-Data-Capture (CDC) from PostgreSQL to S3 and GCS buckets in the form of AVRO files in the destination.
We utilise the interoperability between GCS and S3 here.
### Scenario
Suppose you have a banking application running on PostgreSQL. There are two tables: "users" and "transactions." You want to sync these tables in real-time to AVRO files in your S3 or GCS buckets which other services or clients can pick up.
### Demo
Let's look at a short video showcasing CDC from PostgreSQL to Google Cloud Storage with initial load.
### Prerequisites
#### Postgres Peer
1. Enable logical decoding in PostgreSQL. Ensure that the following settings/GUCs are properly configured:
1. wal\_level: logical
2. max\_wal\_senders: >1
3. max\_replication\_slots: 4
2. Enable replication access for a PostgreSQL user - ALTER USER pg\_user REPLICATION;
3. Ensure that both tables have primary keys. Composite primaries are also fine. If not, make sure your tables have REPLICA IDENTITY FULL.
4. If you are using PostgreSQL on the cloud, below links capture how to enable logical replication for each cloud:
1. [AWS RDS and Aurora PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Replication.Logical.html#AuroraPostgreSQL.Replication.Logical.Configure)
2. [Azure Database for PostgreSQL - Flexible Server](https://learn.microsoft.com/azure/postgresql/flexible-server/concepts-logical#pre-requisites-for-logical-replication-and-logical-decoding)
3. [GCP Cloud SQL PostgreSQL](https://cloud.google.com/sql/docs/PostgreSQL/replication/configure-logical-replication#configure-your-postgresql-instance)
#### S3 peer
1. Ensure you have an existing bucket to use.
2. For PeerDB to access the S3 Peer, you can either use an existing AWS user or create a new AWS user.
3. Create access keys for that user through [AWS Console](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey) or [AWS CLI](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey_CLIAPI) or [AWS API](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html#Using_CreateAccessKey_API)
4. For the same user, create and attach a policy as below using JSON editor. Sharing [AWS docs](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-and-attach-iam-policy.html) for reference. PeerDB requires `s3:ListAllMyBuckets`, `s3:GetObject`, `s3:PutObject`, `s3:ListBucket` and `s3:DeleteObject` on that bucket.
```json theme={null}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::",
"arn:aws:s3:::/*"
]
}
]
}
```
#### GCS peer
1. Ensure you have an existing bucket to use.
2. For GCS, you must [create a HMAC key-pair](https://cloud.google.com/storage/docs/authentication/managing-hmackeys) and use this for `ACCESS_KEY_ID` and `SECRET_ACCESS_KEY` in the Docker compose file.
### Step 1: Add PostgreSQL and S3/GCS Peers
Run the following commands to let PeerDB know about the existing PostgreSQL and S3.
```sql theme={null}
-- Connect to PeerDB
psql "port=9900 host=localhost password=peerdb"
-- Add PostgreSQL and Event Hubs peers
CREATE PEER postgres_peer FROM PostgreSQL (...);
CREATE PEER s3_peer FROM S3 (...);
-- Or, CREATE PEER gcs_peer FROM S3 (...);
```
Please refer to our CREATE PEER documentation for [storage peers](/sql/commands/create-peer#storage-peers-s3-and-gcs).
### **Step 2: Real-Time CDC from PostgreSQL to S3/GCS by creating a MIRROR**
#### Create MIRROR using UI
If you prefer a UI, you can easily create a mirror using the PeerDB UI. Refer to the below video:
#### Create MIRROR using SQL
To facilitate real-time Change Data Capture (CDC) from PostgreSQL to S3 or GCS, set up your peers and then create a mirror using the following SQL syntax:
```sql theme={null}
CREATE MIRROR IF NOT EXISTS
FROM TO
WITH TABLE MAPPING(
.:,
... -- Repeat as required for multiple tables
)
WITH(
max_batch_size = ,
publication_name = ''
);
```
Example:
```sql theme={null}
CREATE MIRROR IF NOT EXISTS test_mirror_interop
FROM test_pg_peer TO test_gcs_peer
WITH TABLE MAPPING(
schema1.table1:dest_table1,
schema1.table2:dest_table2
-- Add more tables as required
)
WITH(
max_batch_size = 300000,
publication_name = 'test_publication'
);
```
Parameters:
* **`mirror-name`**: Desired name for the mirror.
* **`postgres-peer-name`**: Name of the PostgreSQL peer.
* **`storage-peer-name`**: Name of the S3/GCS peer.
* **max\_batch\_size**: Maximum number of records in a batch.
* **publication\_name**: Name of the publication.
Remember to adjust placeholder values (\<...>) with your specific details and preferences.
The example above has been abbreviated for clarity; ensure you provide all the necessary mappings and configurations in practice.
### Step 3: Monitor the MIRROR
You can connect to `localhost:8085` to get full visibility into the different jobs and steps that PeerDB is taking under the covers to manage the MIRROR.
### Step 5: DROP MIRROR
To make it easy in your development and test environments, PeerDB also introduces the DROP MIRROR command. DROP MIRROR drops all the underlying objects that CREATE MIRROR generates. More details are available in this [PR](https://github.com/PeerDB-io/peerdb/pull/93).
```sql theme={null}
-- drop the mirror
DROP MIRROR test_mirror_interop;
```
# PostgreSQL To PostgreSQL
Source: https://docs.peerdb.io/usecases/real-time-cdc/postgres-to-postgres
Let's look at how we can seamlessly perform Change-Data Capturing (CDC) from PostgreSQL to PostgreSQL.
### Demo
This demo shows PeerDB syncing a table with 100 million rows from PostgreSQL to PostgreSQL in few minutes using parallelized initial load and change data capture.
### Scenario
Suppose you have a banking application running on PostgreSQL. There are two tables: "users" and "transactions." You want to sync these tables in real-time to another PostgreSQL server. Let's see how we can make this happen within a few minutes and a few SQL commands using PeerDB.
### Prerequisites
1. Enable logical decoding in Postgres. Ensure that the following settings/GUCs are properly configured:
1. wal\_level: logical
2. max\_wal\_senders: >1
3. max\_replication\_slots: 4
2. Enable replication access for a PostgreSQL user - ALTER USER pg\_user REPLICATION;
3. Ensure that both tables have primary keys. Composite primaries are also fine. If not, make sure your tables have REPLICA IDENTITY FULL.
4. If you are using PostgreSQL on the cloud, below links capture how to enable logical replication for each cloud:
1. [AWS RDS and Aurora PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Replication.Logical.html#AuroraPostgreSQL.Replication.Logical.Configure)
2. [Azure Database for PostgreSQL - Flexible Server](https://learn.microsoft.com/azure/postgresql/flexible-server/concepts-logical#pre-requisites-for-logical-replication-and-logical-decoding)
3. [GCP Cloud SQL PostgreSQL](https://cloud.google.com/sql/docs/postgres/replication/configure-logical-replication#configure-your-postgresql-instance)
### Step 1: Create Two PostgreSQL Peers
Run the following commands to let PeerDB know about the existingpeers.
```sql theme={null}
-- Connect to PeerDB
psql "port=9900 host=localhost password=peerdb"
-- Add Postgres and PostgreSQL peers
CREATE PEER postgres_peer_1 FROM postgres (...);
CREATE PEER postgres_peer_2 FROM postgres (...);
```
Make sure to replace **`(…)`** with the appropriate connection details for the two PostgreSQL instances. More details on adding PEERs are available [here](/sql/commands/create-peer).
### **Step 2: Real-Time CDC from PostgreSQL to PostgreSQL**
With the peers set up, you can create a mirror that facilitates real-time CDC from PostgreSQL to PostgreSQL.
```sql theme={null}
-- Real-time CDC between two Postgres peers
-- Make sure tables are schema qualified
CREATE MIRROR real_time_cdc
FROM postgres_peer_1 TO postgres_peer_2
WITH TABLE MAPPING (public.transactions:public.transactions, public.users:public.users)
WITH (
do_initial_copy = true,
snapshot_sync_mode='sql',
snapshot_num_rows_per_partition = 500000,
snapshot_max_parallel_workers = 4,
snapshot_num_tables_in_parallel = 4
);
```
If you observe, **TABLE MAPPING** represents the table name mapping between the two Postgres peers. The final `WITH` clause captures if you wanted to include initial snapshot as a part of the MIRROR. If you don't include that `WITH`, peerdb assumes that you don't want to perform an initial snapshot. If just reads the slot and replays the changes to the target.
### **Step 3: Validate the Mirror**
Through the same PeerDB's Postgres-compatible SQL interface, you can quickly validate the MIRROR (real-time CDC).
```sql theme={null}
-- Validate the mirror
SELECT COUNT(*) FROM postgres_peer_1.public.transactions;
SELECT COUNT(*) FROM postgres_peer_2.public.transactions;
```
### Step 4: Monitor the MIRROR
You can connect to `localhost:8085` to get full visibility into the different jobs and steps that PeerDB is taking under the covers to manage the MIRROR.
# PostgreSQL To Snowflake
Source: https://docs.peerdb.io/usecases/real-time-cdc/postgres-to-snowflake
Snowflake as a destination is deprecated and no longer actively maintained. It remains fully functional and no code is currently being removed. For new mirrors, we recommend ClickHouse, ClickHouse Cloud, or Postgres as the destination.
Let's look at how we can seamlessly perform Change-Data Capturing (CDC) from PostgreSQL to Snowflake.
### Scenario
Suppose you have a banking application running on PostgreSQL. There are two tables: "users" and "transactions." You want to sync these tables in real-time to Snowflake for analytics purposes, such as real-time fraud detection. Let's see how we can make this happen within a few minutes and a few SQL commands using PeerDB.
### Demo
This demo shows PeerDB syncing a table with 100 million rows from PostgreSQL to Snowflake in few minutes.
### Prerequisites
1. Enable logical decoding in Postgres. Ensure that the following settings/GUCs are properly configured:
1. wal\_level: logical
2. max\_wal\_senders: >1
3. max\_replication\_slots: 4
2. Enable replication access for a PostgreSQL user - ALTER USER pg\_user REPLICATION;
3. Ensure that both tables have primary keys. Composite primaries are also fine. If not, make sure your tables have REPLICA IDENTITY FULL.
4. If you are using PostgreSQL on the cloud, below links capture how to enable logical replication for each cloud:
1. [AWS RDS and Aurora PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.Replication.Logical.html#AuroraPostgreSQL.Replication.Logical.Configure)
2. [Azure Database for PostgreSQL - Flexible Server](https://learn.microsoft.com/azure/postgresql/flexible-server/concepts-logical#pre-requisites-for-logical-replication-and-logical-decoding)
3. [GCP Cloud SQL PostgreSQL](https://cloud.google.com/sql/docs/postgres/replication/configure-logical-replication#configure-your-postgresql-instance)
5. Ensure that permissions for the Snowflake user and database you wish to use is properly configured. More details are available [here](/sql/commands/create-peer#granting-permissions).
### Step 1: Add Postgres and Snowflake Peers
Run the following commands to let PeerDB know about the existing Postgres and Snowflake Peers.
```sql theme={null}
-- Connect to PeerDB
psql "port=9900 host=localhost password=peerdb"
-- Add Postgres and Snowflake peers
CREATE PEER postgres_peer FROM postgres (...);
CREATE PEER snowflake_peer FROM snowflake (...);
```
Make sure to replace **`(…)`** with the appropriate connection details for both the PostgreSQL and Snowflake instances. More details on adding PEERs are available [here](/sql/commands/create-peer).
### **Step 2: Real-Time CDC from PostgreSQL to Snowflake**
With the peers set up, you can create a mirror that facilitates real-time CDC from PostgreSQL to Snowflake.
#### Create MIRROR using SQL
```sql theme={null}
-- Real-time CDC from PostgreSQL to Snowflake
CREATE MIRROR real_time_cdc
FROM postgres_peer TO snowflake_peer
WITH TABLE MAPPING (public.transactions:public.transactions, public.users:public.users) -- make sure tables are schema qualified
WITH (
do_initial_copy = true,
snapshot_sync_mode='avro',
snapshot_num_rows_per_partition = 500000,
snapshot_max_parallel_workers = 4,
snapshot_num_tables_in_parallel = 4,
snapshot_staging_path = ''
);
```
Since no CDC sync mode has been specified above, CDC will be performed in `sql` mode.
To perform CDC via `AVRO mode`, you must set the following:
```
cdc_sync_mode = 'avro'
cdc_staging_path = ''
```
You must set the staging path to be an existing S3 bucket URL, or an empty string for PeerDB to stage the AVRO files internally.
If you observe, **TABLE MAPPING** represents the table name mapping between the two Postgres peers. The final `WITH` clause captures if you wanted to include initial snapshot as a part of the MIRROR. If you don't include that `WITH`, PeerDB assumes that you don't want to perform an initial snapshot. If just reads the slot and replays the changes to the target.
1. Data type mapping between [Postgres and Snowflake can be found here](/datatypes/datatype-matrix).
2. If you want additional types to be supported or want to alter the existing data type mapping, please reach out to us. We can aim to support that within a few days. Also, PeerDB is [fully open source](https://github.com/PeerDB-io/peerdb), so feel free to submit a PR.
> **PeerDB also supports replicating TOAST columns very efficiently**. Unlike most CDC tools, you don't need to set up REPLICA IDENTITY FULL for replicating TOAST columns. This [PR](https://github.com/PeerDB-io/peerdb/pull/111) captures the infrastructural optimizations that PeerDB takes to support TOAST columns.
#### Create MIRROR using UI
If you prefer a UI, you can easily create a mirror using the PeerDB UI (localhost:3000). Refer to the below video:
### **Step 3: Validate the Mirror**
Through the same PeerDB's Postgres-compatible SQL interface, you can quickly validate the MIRROR (real-time CDC).
```sql theme={null}
-- Validate the mirror
SELECT COUNT(*) FROM snowflake_peer.transactions;
SELECT COUNT(*) FROM postgres_peer.transactions;
```
### Step 4: Monitor the MIRROR
You can use the UI (localhost:3000) to monitor the status of the initial load. Refer to the below video:
You can use the UI (localhost:3000) to monitor the status of the Change Data Capture (CDC). Refer to the below video:
For deeper monitoring, you can connect to `localhost:8085` to get full visibility into the different jobs and steps that PeerDB is taking under the covers to manage the MIRROR.
### Step 5: DROP MIRROR
To make it easy in your development and test environments, PeerDB also introduces the DROP MIRROR command. DROP MIRROR drops all the underlying objects that CREATE MIRROR generates. More details are available in this [PR](https://github.com/PeerDB-io/peerdb/pull/93).
```sql theme={null}
-- drop the mirror
DROP MIRROR real_time_cdc;
```
# Overview
Source: https://docs.peerdb.io/usecases/streaming-query-replication/overview
Streaming Query Replication (QRep), including XMIN-based replication, is a deprecated mirror type and no longer actively maintained. It remains fully functional and no code is currently being removed. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors.
PeerDB introduces the **CREATE MIRROR FOR SELECT** SQL command for continuous sync of data from PostgreSQL to the desired target Peer based on any SELECT query on PostgreSQL. This command allows you to perform a pre-transform of the data on the source before syncing it to the target.
Currently we support **ClickHouse**, **PostgreSQL (running anywhere)**, **AWS S3**, **BigQuery** and **Snowflake** as the target Peers.
1. You simply run a few SQL commands, and PeerDB takes care of all the heavy lifting to set up and maintain highly performant syncs and pre-transforms across stores.
2. You can run any SELECT query that is supported by PostgreSQL for the transformation, including JOINs, function/procedure calls, GROUP BYs, and so on.
3. The SQL command provides various options such as batch size, parallelism, and refresh interval, which give you granular control when configuring the MIRROR.
> PeerDB internally implements multiple optimizations to provide the best possible performance experience. For example, it converts data to [Avro](https://github.com/PeerDB-io/peerdb/pull/96) format during transit and enables parallelism during both reading from sync and writing to target.
### Demo
This demo shows PeerDB syncing a table with 100 million rows from PostgreSQL to Snowflake in few minutes.
# PostgreSQL to BigQuery
Source: https://docs.peerdb.io/usecases/streaming-query-replication/postgres-to-bigquery
Streaming Query Replication (QRep) is a deprecated mirror type and no longer actively maintained. It remains fully functional and no code is currently being removed. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors. BigQuery as a destination is also deprecated, though BigQuery remains a supported source.
### Scenario
Let's consider a scenario where we have an events table in PostgreSQL. We want to periodically sync data from this table in PostgreSQL to BigQuery. However, we only want to sync a few columns filtered based on the country (USA) and create a single denormalized view of the data in BigQuery. Let's see how we can achieve this within a few minutes and a few SQL commands using PeerDB.
### Step 1: Add PostgreSQL and BigQuery Peers
Run the following commands to add the PostgreSQL and BigQuery Peers to PeerDB:
```sql theme={null}
-- Connect to PeerDB
psql "port=9900 host=localhost password=peerdb"
-- Add PostgreSQL and BigQuery peers
CREATE PEER postgres_peer FROM postgres (...);
CREATE PEER bigquery_peer FROM bigquery (...);
```
Make sure to replace `(…)` with the appropriate connection details for both the PostgreSQL and BigQuery instances. More details on adding peers are available [here](/sql/commands/create-peer).
### **Step 2: Set up MIRROR to Transform and Sync Data**
With the peers set up, you can create a mirror that facilitates periodic sync from PostgreSQL to BigQuery with custom transformations.
```sql theme={null}
-- Customizable ETL from PostgreSQL to BigQuery
CREATE MIRROR streaming_query_pg_to_bq FROM
postgres_peer TO bigquery_peer FOR
$$
SELECT * FROM events WHERE
updated_at BETWEEN {{.start}} AND {{.end}}
$$
WITH (
destination_table_name = 'events',
watermark_column = 'updated_at',
watermark_table_name = 'public.events',
mode = 'upsert',
unique_key_columns = 'id',
parallelism = 64,
refresh_interval = 30,
num_rows_per_partition = 50000
);
```
### **Step 3: Validate the Mirror**
Using the same PostgreSQL-compatible SQL interface of PeerDB, you can quickly validate the MIRROR.
```sql theme={null}
-- Validate the mirror
SELECT COUNT(*) FROM postgres_peer.events;
SELECT COUNT(*) FROM bigquery_peer.events;
```
### Step 4: Monitor the MIRROR
You can connect to `localhost:8085` to gain full visibility into the different jobs and steps that PeerDB performs under the hood to manage the MIRROR.
### Step 5: DROP MIRROR
To make it easy in your development and test environments, PeerDB also introduces the DROP MIRROR command. DROP MIRROR drops all the underlying objects that CREATE MIRROR generates. More details are available in this [PR](https://github.com/PeerDB-io/peerdb/pull/93).
```sql theme={null}
-- drop the mirror
DROP MIRROR ;
```
### Support
If you run into any issues, join our [slack channel](https://slack.peerdb.io) and reach out to us. You can file an issue on our [github repository](https://github.com/peerdb-io/peerdb) or reach out to [founders@peerdb.io](mailto:founders@peerdb.io) . We will follow up!
# PostgreSQL to PostgreSQL
Source: https://docs.peerdb.io/usecases/streaming-query-replication/postgres-to-postgres
Streaming Query Replication (QRep) is a deprecated mirror type and no longer actively maintained. It remains fully functional and no code is currently being removed. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors.
### Step 1: CREATE Two Postgres Peers
There is a guide available for creating a PostgreSQL peer here: [CREATE Postgres PEER](/sql/commands/create-peer#postgresql-peer)
### Step 2: Create and populate tables on the source Postgres PEER
Run the following SQL on your source PostgreSQL peer to create and populate `pgbench_history` with dummy data:
```sql theme={null}
DROP TABLE IF EXISTS pgbench_history;
CREATE TABLE pgbench_history (
tid integer,
bid integer,
aid integer,
delta integer,
mtime timestamp without time zone,
filler character(22)
);
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime, filler)
SELECT
(random() * 10)::int,
(random() * 10)::int,
(random() * 100000)::int,
(random() * 10000 - 5000)::int,
now() - (random() * interval '30 days'),
lpad('', 22)
FROM generate_series(1, 10000);
CREATE INDEX pgbench_history_mtime_idx ON pgbench_history(mtime);
```
### Step 3: Create pgbench\_history table on the destination PEER
```sql theme={null}
CREATE TABLE pgbench_history (tid integer, bid integer,
aid integer, delta integer, mtime timestampntz, filler text);
```
### Step 4: Kick off MIRROR with 8 threads and batch size of 10 seconds
```sql theme={null}
CREATE MIRROR postgres_to_postgres_tutorial
FROM postgres_peer_source TO postgres_peer_destination FOR
$$SELECT * FROM public.pgbench_history WHERE mtime BETWEEN {{.start}} AND {{.end}}$$
WITH (
watermark_column = 'mtime',
watermark_table_name = 'pgbench_history',
mode = 'append',
parallelism = 8,
refresh_interval = 10,
destination_table_name = 'public.pgbench_history',
num_rows_per_partition = 10000
);
```
### Step 5: Monitor the MIRROR
You can connect to `localhost:8085` to gain full visibility into the different jobs and steps that PeerDB performs under the hood to manage the MIRROR.
### Step 6: Validate the MIRROR
In 1-2 minutes the MIRROR should complete syncing data. Now validate the data on both postgres peers. Number of rows should match on both sides.
```sql theme={null}
SELECT count(*) FROM postgres_peer_1.pgbench_history;
SELECT count(*) FROM postgres_peer_2.pgbench_history;
```
### Step 5: DROP MIRROR
To make it easy in your development and test environments, PeerDB also introduces the DROP MIRROR command. DROP MIRROR drops all the underlying objects that CREATE MIRROR generates. More details are available in this [PR](https://github.com/PeerDB-io/peerdb/pull/93).
```sql theme={null}
-- drop the mirror
DROP MIRROR ;
```
# PostgreSQL to S3
Source: https://docs.peerdb.io/usecases/streaming-query-replication/postgres-to-s3
Streaming Query Replication (QRep) is a deprecated mirror type and no longer actively maintained. It remains fully functional and no code is currently being removed. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors. S3 as a destination is also deprecated.
PeerDB can stream your PostgreSQL data to your S3 bucket in the form of `.avro` files. Please **fill in your AWS credentials** in [PeerDB's docker-compose file](https://github.com/PeerDB-io/peerdb/blob/e9fe3e03e242abc37a7526d7132c1f7232e00e5f/docker-compose.yml#L89-L91C36) before running it.
### Step 1: CREATE Postgres and S3 Peers
1. [CREATE Postgres PEER](/sql/commands/create-peer#postgresql-peer). Make sure it satisfies the prerequisites required for our mirror.
2. [CREATE S3 PEER](/sql/commands/create-peer#s3-peer)
### Step 2: Create and populate tables on the Postgres PEER
Below script helps creates and populate `peerdb_demo` with 10 rows on your PostgreSQL peer.
```sh theme={null}
curl https://gist.github.com/Amogh-Bharadwaj/64d7f6cb22e35b766e6a09b05479b201/raw --output setup.sh
chmod +x setup.sh
# "postgres://user:password@hostname:5432/dbname"
# is the connection string of your PostgreSQL peer.
./setup.sh "postgres://user:password@hostname:5432/dbname"
rm setup.sh
```
### Step 3: Kick off Streaming Query Replication
```sql theme={null}
CREATE MIRROR postgres_to_s3_tutorial
FROM postgres_peer TO s3_peer FOR
$$SELECT * FROM peerdb_demo WHERE id BETWEEN {{.start}} AND {{.end}}$$
WITH (
watermark_column = 'id',
watermark_table_name = 'peerdb_demo',
mode = 'append',
parallelism = 10,
refresh_interval = 10,
destination_table_name = 'peerdb_demo',
num_rows_per_partition = 2
);
```
### Step 4: Monitor the MIRROR
You can connect to `localhost:8085` to gain full visibility into the different jobs and steps that PeerDB performs under the hood to manage the MIRROR.
### Step 5: Validate the MIRROR
In a few seconds the MIRROR should complete syncing data. Now validate the data on both postgres and S3 peers. The number of `.avro` files in the bucket should be equal to the number of partitions (total rows in your source table divided by `num_rows_per_partition`). In this case, there should be exactly `5` files.
```sql theme={null}
select (count(*)/2) as no_of_avro_files from postgres_peer.peerdb_demo;
```
```shell theme={null}
aws ls --recursive | wc -l
```
### Step 5: DROP MIRROR
To make it easy in your development and test environments, PeerDB also introduces the DROP MIRROR command. DROP MIRROR drops all the underlying objects that CREATE MIRROR generates. More details are available in this [PR](https://github.com/PeerDB-io/peerdb/pull/93).
```sql theme={null}
-- drop the mirror
DROP MIRROR ;
```
# PostgreSQL to Snowflake
Source: https://docs.peerdb.io/usecases/streaming-query-replication/postgres-to-snowflake
Streaming Query Replication (QRep) is a deprecated mirror type and no longer actively maintained. It remains fully functional and no code is currently being removed. We recommend [CDC (Change Data Capture)](/usecases/real-time-cdc/overview) as the actively-maintained mirror type for new mirrors. Snowflake as a destination is also deprecated.
### Scenario
Let's consider a scenario where we have an "events" table and a "users" table in PostgreSQL. We want to periodically sync data from these two tables in PostgreSQL to Snowflake. However, we only want to sync a few columns filtered based on the country (USA) and create a single denormalized view of the data in Snowflake. Let's see how we can achieve this within a few minutes and a few SQL commands using PeerDB.
### Demo
This demo shows PeerDB syncing a table with 100 million rows from PostgreSQL to Snowflake in few minutes.
### Step 1: Add PostgreSQL and Snowflake Peers
Run the following commands to add the PostgreSQL and Snowflake Peers to PeerDB:
```sql theme={null}
-- Connect to PeerDB
psql "port=9900 host=localhost password=peerdb"
-- Add PostgreSQL and Snowflake peers
CREATE PEER postgres_peer FROM postgres (...);
CREATE PEER snowflake_peer FROM snowflake (...);
```
Ensure that [permissions for the Snowflake](/sql/commands/create-peer#granting-permissions) user and database you wish to use is properly configured.
Make sure to replace `(…)` with the appropriate connection details for both the PostgreSQL and Snowflake instances. More details on adding peers are available [here](/sql/commands/create-peer).
### **Step 2: Set up MIRROR to Transform and Sync Data**
With the peers set up, you can create a mirror that facilitates periodic sync from PostgreSQL to Snowflake with custom transformations.
```sql theme={null}
-- Customizable ETL from PostgreSQL to Snowflake
CREATE MIRROR streaming_query_pg_to_sf FROM
postgres_peer TO snowflake_peer FOR
$$
SELECT * FROM events WHERE
updated_at BETWEEN {{.start}} AND {{.end}}
$$
WITH (
destination_table_name = 'public.events',
watermark_column = 'updated_at',
watermark_table_name = 'public.events',
mode = 'upsert',
unique_key_columns = 'id',
parallelism = 64,
refresh_interval = 30,
num_rows_per_partition = 50000
);
```
1. In the SELECT query, we address the scenario by choosing only a few columns, enriching some columns using the JOIN operation, and filtering based on the country.
2. The OPTIONS clause provides granular control when configuring the MIRROR:
1. **watermark\_column (Required)** represents a sequentially incrementing integer or timestamp column. PeerDB uses this column to keep track of the processed rows and the ones that need to be processed.
2. **watermark\_table (Required)** is the table that PeerDB iterates sequentially based on the watermark\_column. The fact table is a good candidate for the watermark\_table.
3. **mode (Required)** tells PeerDB whether it should append data to the target or perform an upsert operation (update if the row exists).
1. If your data is append-only, a sequential ID or a created\_at column can be a good watermark, and you can choose the mode **append\_only.**
2. If your data is updated, make sure to have an "updated\_at" column for PeerDB to identify the most recent version of the row. Choose the mode **upsert** to update already existing rows on the target.
1. **unique\_key:** In the upsert mode, you need to specify a set of columns (unique\_key) that uniquely identify a row. This helps perform the upsert operation.
4. **parallelism (Optional)** represents the number of threads used to read from the source and sync to the target. This helps with workload management on the source and target.
1. If you have a powerful PostgreSQL server or if it is a read-replica, you can configure a higher parallelism value. In scenarios where you want to put less load on the source, you can choose a lower value.
5. **refresh\_interval (Optional)** helps configure the frequency (in minutes) at which the sync should run. If not specified, PeerDB syncs the data continuously without pauses.\\
6. More details on the OPTIONs can be found [here](https://github.com/PeerDB-io/peerdb/issues/139).
3. `updated_at BETWEEN {{.start}} AND {{.end}}` in the SELECT statement provides input to PeerDB on which part(s) of the query should be scoped by the watermark column for the rows to be synced.
### **Step 3: Validate the Mirror**
Using the same PostgreSQL-compatible SQL interface of PeerDB, you can quickly validate the MIRROR.
```sql theme={null}
-- Validate the mirror
SELECT COUNT(*) FROM snowflake_peer.events;
```
### Step 4: Monitor the MIRROR
You can connect to `localhost:8085` to gain full visibility into the different jobs and steps that PeerDB performs under the hood to manage the MIRROR.
### Support
If you run into any issues, join our [slack channel](https://slack.peerdb.io) and reach out to us. You can file an issue on our [github repository](https://github.com/peerdb-io/peerdb) or reach out to [founders@peerdb.io](mailto:founders@peerdb.io) . We will follow up!
# Why choose PeerDB over other tools?
Source: https://docs.peerdb.io/why-peerdb
At [**PeerDB**](http://peerdb.io/), our mission is to create a Postgres-first data-movement platform that provides the world's best experience for replicating data from Postgres to Data Warehouses, Queues and Storage. Our laser focus on Postgres helps us surpass other data-movement tools (Fivetran, AirByte, DMS, Debezium etc.) in speed, features and usability.
## Performance
### 2x to 16x faster large data loads
When you are moving larger datasets (10s of GB to a few TB) from Postgres to any supported targets, PeerDB can be 2x to 16x faster than other tools. This helps faster initial loads in [WAL-based replication](https://docs.peerdb.io/usecases/real-time-cdc/overview) and faster [Query or Watermark based replication](https://docs.peerdb.io/usecases/streaming-query-replication/overview). Below are the throughput limits you can expect:
**With PeerDB**, 10MBPS to 80MBPS
**Most other tools** cap at 5-6MBPS
This [blog](https://blog.peerdb.io/benchmarking-postgres-replication-peerdb-vs-airbyte) captures official benchmarks that we published recently.
### Change Data Capture (CDC) with 5s to 60s lag on target
Our infrastructure is designed for real-time streaming from Postgres. If your application is latency sensitive you can configure refresh intervals as low as a few seconds. The below table captures the latency you can expect for an average use case
| Tool | Source | Target | Throughput | Lag/Latency |
| -------------------------------------- | -------- | ----------------------------------- | ---------- | -------------------------------------------------------------------------------- |
| PeerDB | Postgres | Data Warehouses and Storage | 5K TPS | 30s-1min |
| PeerDB | Postgres | Queues | 5K TPS | 1s-5s |
| Other tools such as Fivetran, DMS etc. | Postgres | Data Warehouses, Queues and Storage | 5K TPS | At least 5mins. A few tools degrade over time and lag can grow to multiple hours |
## Postgres native features
PeerDB has comprehensive support for multiple Postgres native features that are lacking in other tools. Below are a few examples:
1. **Support of advanced data types** - PeerDB supports natively replicating advanced data types incl. ARRAYs, JSON/JSONB, HSTORE, ENUMs, Geospatial etc from Postgres. Most other tools either don't support a few of these types or default to the TEXT/STRING column on the target.
2. **Comprehensive support of Partitioned Tables -** PeerDB has comprehensive support for [replicating partitioned tables](https://blog.peerdb.io/real-time-change-data-capture-for-postgres-partitioned-tables). We handle various scenarios like adding new partitions, dropping partitions, adding or dropping columns, and ensuring compatibility with different Postgres versions. It was a common concern from our customers that other data movement tools either lacked features or were not reliable in handling partitioned tables.
3. **Efficient replication TOAST (large) columns** - Other tools require you to set `REPLICA IDENTITY FULL` on your tables to reliably stream TOAST columns. This can affect the source Postgres database by increasing the resource (compute and IO) utilization. [Postgres](https://www.postgresql.org/docs/current/logical-replication-publication.html) also recommends this approach as a last fallback option. With PeerDB, we implemented a [caching mechanism](https://github.com/PeerDB-io/peerdb/pull/111) which eliminates the need of setting `REPLICA IDENTITY FULL` to replicate TOAST columns. This avoids additional load on the source, making it significantly safer than the former approach.
## Usability- Simple UI or a Powerful SQL Layer
Along with a simple UI to create PEERs and kick off MIRRORs, PeerDB provides a Postgres compatible SQL layer for data movement. This makes the life of data engineers much easier. They can develop pipelines using a framework they are familiar with, without needing to deal with custom UIs and REST APIs. They can use Postgres' 100s of integrations to build and manage data movement.
None of the other tools provide a Postgres compatible SQL layer to manage data movement.
Compared to Debezium, PeerDB is significantly [simpler to set up and manage](https://news.ycombinator.com/item?id=36910908). More on this topic coming soon!
## Save Costs, up to 80% cost reduction
By implementing the below optimizations/strategies, we are able to cut up to 80% of costs for customers:
1. **State of art engineering:** Our engineering focus revolves around cost efficiency and hardware optimization. You can go through [our architecture](https://docs.peerdb.io/architecture) and [engineering blog](https://blog.peerdb.io/) for a deep dive into our design tradeoffs to build the most optimal data movement solution for Postgres.
2. **Predictable pricing:** Our pricing is based on provisioned vCPUs rather than the amount of data transferred. Based on the volume of data you move, we will come up with the number of vCPUs needed for your use case. You will know that in advance and can scale up and down based on what you wish. With this approach of pricing, you'll clearly know your expenses beforehand, with no surprises in the future!
3. **PeerDB CostControl:** PeerDB already has mechanisms in place to reduce activity and costs on your Data Warehouse.
1. If there is no activity on Postgres, PeerDB has in-built mechanisms to pause the replication and incur zero load on the Warehouse.
2. You can configure the refresh interval and batch size based on how frequently you want PeerDB to query the Data Warehouse. For example, to save costs you can configure a larger refresh interval / batch size.
3. We are actively working on other mechanisms to further reduce the costs of your Data Warehouse. More on this soon!