Create Columnstore Table
Columnstore tables provide significant compression and query performance benefits for analytical queries while maintaining full PostgreSQL compatibility.
Today, all columnstore tables must be created as a replica of an existing PostgreSQL table:
- Writes → PostgreSQL rowstore table
- Analytics → pg_mooncake columnstore table
transactions analytics
│ │ ▲ ▲
▼ ▼ │ │
┌────────────────┐ ┌─────┴───┴──────┐
│ │ │ │
│ ├──────┤ │
│ Postgres ├──────┤ Postgres with │
│ Primary ├──────┤ 🥮 │
│ ├──────┤ │
│ │ │ │
└────────────────┘ └────────────────┘
RDS,Supabase,
GCP, Azure, Neon
Soon (Q4 2025), we will support creating a stand-alone columnstore table, where you can insert/upsert data directly. This is helpful for event stream / logging workloads.
Quick Start
Create a columnstore table from an existing rowstore table:
CALL mooncake.create_table('trades_analytics', 'trades');
Write and Read Patterns
Write Operations - All writes go to the original rowstore table:
INSERT INTO trades (symbol, quantity, price) VALUES ('AAPL', 100, 150.00);
UPDATE trades SET status = 'filled' WHERE trade_id = 1001;
DELETE FROM trades WHERE trade_id = 1002;
Read Operations - Choose the right table for your query:
-- Transactional reads from rowstore (OLTP queries)
SELECT * FROM trades WHERE trade_id = 1001;
-- Analytical reads from columnstore (OLAP queries)
SELECT
symbol,
SUM(quantity * price) as total_volume
FROM trades_analytics -- Use the columnstore replica
WHERE trade_date >= '2024-01-01'
GROUP BY symbol;
The columnstore table will always read the latest transactions from the rowstore table.
Schema Change Propagation
Schema changes made to the rowstore table are automatically propagated to the columnstore table. This includes:
- ADD COLUMN - New columns are automatically added to the columnstore table
- DROP COLUMN - Columns are removed from the columnstore table
-- Example: Adding a new column to the rowstore
ALTER TABLE trades ADD COLUMN trade_status VARCHAR(20);
-- The columnstore table automatically reflects this change
SELECT symbol, quantity, price, trade_status
FROM trades_analytics -- New column is available immediately
WHERE trade_date >= '2024-01-01';
Creating Columnstore Tables
Within your Primary Deployment
When pg_mooncake is installed on the same PostgreSQL instance:
CALL mooncake.create_table('trades_analytics', 'trades');
The original trades
table remains your primary table for writes. The trades_analytics
columnstore table is automatically synchronized for analytical queries.
As a separate analytics instance
Deploy pg_mooncake on a dedicated analytics instance:
CALL mooncake.create_table(
'trades_analytics',
'trades',
source_uri => 'postgresql://analytics_user:password@prod-db.example.com:5432/myapp'
);
Your production trades
table remains unchanged. This provides workload isolation and zero production impact.
URI Configuration
The source URI follows standard PostgreSQL connection string format:
postgresql://[username]:[password]@[hostname]:[port]/[database]
Examples:
-- AWS RDS connection
'postgresql://replicator:secure123@myapp.abc123.us-east-1.rds.amazonaws.com:5432/production'
-- Local development
'postgresql://dev_user:dev_pass@localhost:5432/myapp_dev'
-- Neon connection
'postgresql://user:pass@ep-cool-darkness-123456.us-east-1.aws.neon.tech/neondb'
Setting Up Replication Users
pg_mooncake automatically creates the required replication user and grants necessary permissions. No manual user setup is required.
PostgreSQL Configuration for Replication
Configure these parameters on the source instance:
# Enable logical replication
wal_level = logical
Restart required after changing wal_level
.
Cloud Provider Setup
See cloud provider specific setup guides: