For the complete documentation index, see llms.txt. This page is also available as Markdown.

Schema Migration

Examples of using Sling to migrate database schema attributes along with data

Schema migration (v1.5.7) is a powerful feature that allows Sling to replicate not just data, but also important schema attributes like primary keys, foreign keys, indexes, default values, nullable constraints, auto-increment columns, and column/table descriptions from source to target databases.

Schema migration is controlled via the SLING_SCHEMA_MIGRATION environment variable and is disabled by default.

Overview

When migrating databases, preserving schema attributes is often critical for maintaining data integrity and application compatibility. Sling's schema migration feature extracts extended metadata from source tables and applies the corresponding constraints and properties to target tables.

Supported Attributes

Attribute
Description
Example

primary_key

Primary key constraints

id INT PRIMARY KEY

foreign_key

Foreign key relationships

REFERENCES customers(id)

indexes

Non-primary key indexes

CREATE INDEX idx_name ON table(col)

auto_increment

Identity/auto-increment columns

IDENTITY(1,1) or SERIAL

nullable

NOT NULL constraints

email VARCHAR(255) NOT NULL

default_value

Column default values

DEFAULT CURRENT_TIMESTAMP

description

Column and table comments

COMMENT ON COLUMN...

Supported Databases

Schema migration works between any combination of these databases. The level of support varies by database—see the compatibility matrix below for details.

Full Support

  • PostgreSQL

  • MySQL / MariaDB

  • SQL Server / Azure SQL

  • Oracle

  • Redshift

  • Databricks

Partial Support

  • Snowflake (no indexes)

  • BigQuery (no auto-increment, no default values, no indexes)

  • SQLite (no descriptions)

  • DuckDB (no auto-increment, no default values)

  • ClickHouse (primary key, nullable, description only)

Database Compatibility Matrix

The following matrix shows which schema attributes are supported for each database:

Database
Auto-Increment
Primary Key
Foreign Key
Default Value
Nullable
Indexes
Description

PostgreSQL

MySQL / MariaDB

✓¹

SQL Server / Azure SQL

Oracle

✓²

Redshift

✓³

✓³

—⁴

Databricks

✓⁵

✓⁶

✓⁶

—⁷

Snowflake

✓⁸

✓⁸

BigQuery

✓⁹

✓⁹

SQLite

✓¹⁰

✓¹¹

DuckDB

ClickHouse

✓¹²

Legend: ✓ = Supported | — = Not supported

Notes:

  1. MySQL/MariaDB: Foreign keys require InnoDB engine; MyISAM ignores FK constraints

  2. Oracle: Supports ON DELETE actions but not ON UPDATE actions for foreign keys

  3. Redshift: Primary keys and foreign keys are informational only (not enforced)

  4. Redshift: Does not support traditional indexes; use SORTKEY/DISTKEY instead

  5. Databricks: Auto-increment only supports BIGINT column type

  6. Databricks: Primary keys and foreign keys are informational only (not enforced); only NOT NULL is enforced

  7. Databricks: Does not support traditional indexes; use Z-ordering instead

  8. Snowflake: Primary keys and foreign keys are not enforced in standard tables (metadata only); only NOT NULL is enforced

  9. BigQuery: Primary keys and foreign keys use NOT ENFORCED syntax (metadata only for query optimization)

  10. SQLite: Auto-increment only works with INTEGER PRIMARY KEY columns

  11. SQLite: Foreign keys require PRAGMA foreign_keys = ON per connection (disabled by default)

  12. ClickHouse: Primary key defines sort order and sparse index; does not enforce uniqueness

Constraint Enforcement Matrix

Database
PK Enforced
FK Enforced
NOT NULL Enforced
Default Enforced

PostgreSQL

✓ Yes

✓ Yes

✓ Yes

✓ Yes

MySQL / MariaDB

✓ Yes

✓ Yes (InnoDB)

✓ Yes

✓ Yes

SQL Server

✓ Yes

✓ Yes

✓ Yes

✓ Yes

Oracle

✓ Yes

✓ Yes

✓ Yes

✓ Yes

Redshift

✗ No

✗ No

✓ Yes

✓ Yes

Databricks

✗ No

✗ No

✓ Yes

✓ Yes

Snowflake

✗ No

✗ No

✓ Yes

✓ Yes

BigQuery

✗ No

✗ No

✓ Yes

Partial

SQLite

✓ Yes

✓ Yes*

✓ Yes

✓ Yes

DuckDB

✓ Yes

✓ Yes

✓ Yes

✓ Yes

ClickHouse

✗ No

N/A

✗ No

✓ Yes

Legend: ✓ Yes = Enforced at runtime | ✗ No = Metadata only (not enforced) | * = Requires configuration

SQLite Note: Foreign key enforcement requires PRAGMA foreign_keys = ON to be set on each database connection. This is disabled by default for backwards compatibility.

Analytical Databases: Redshift, Snowflake, BigQuery, and Databricks are optimized for analytical workloads. They accept constraint definitions for documentation and query optimization hints, but do not enforce them at runtime. Data integrity must be validated upstream in ETL pipelines.

What You Can Use for Each Database

All features supported and enforced. PostgreSQL is fully compatible with schema migration.

Attribute
Supported
Enforced

Primary Key

✓ Yes

Foreign Key

✓ Yes

Auto-increment

✓ Yes

Default Value

✓ Yes

NOT NULL

✓ Yes

Indexes

Functional

Description

Metadata

  • Auto-increment uses GENERATED BY DEFAULT AS IDENTITY

  • Full foreign key support with ON DELETE and ON UPDATE actions

  • Column/table comments via COMMENT ON syntax

All features supported and enforced (with InnoDB engine).

Attribute
Supported
Enforced

Primary Key

✓ Yes

Foreign Key

✓ Yes (InnoDB only)

Auto-increment

✓ Yes

Default Value

✓ Yes

NOT NULL

✓ Yes

Indexes

Functional

Description

Metadata

  • Auto-increment uses AUTO_INCREMENT keyword

  • Foreign keys require InnoDB engine (MyISAM ignores FK constraints)

  • Comments via COMMENT clause

All features supported and enforced. SQL Server and Azure SQL are fully compatible.

Attribute
Supported
Enforced

Primary Key

✓ Yes

Foreign Key

✓ Yes

Auto-increment

✓ Yes

Default Value

✓ Yes

NOT NULL

✓ Yes

Indexes

Functional

Description

Metadata

  • Auto-increment uses IDENTITY(seed, increment) syntax

  • Foreign keys can be disabled with NOCHECK if needed

  • Descriptions via Extended Properties (MS_Description)

All features supported and enforced with one limitation.

Attribute
Supported
Enforced

Primary Key

✓ Yes

Foreign Key

✓ Yes (ON DELETE only)

Auto-increment

✓ Yes

Default Value

✓ Yes

NOT NULL

✓ Yes

Indexes

Functional

Description

Metadata

  • Auto-increment uses GENERATED BY DEFAULT AS IDENTITY

  • Foreign keys support ON DELETE actions but not ON UPDATE (Oracle limitation)

  • Comments via COMMENT ON COLUMN / COMMENT ON TABLE

DDL supported but constraints not enforced. Snowflake is an analytical database.

Attribute
Supported
Enforced

Primary Key

✗ No (metadata only)

Foreign Key

✗ No (metadata only)

Auto-increment

✓ Yes

Default Value

✓ Yes

NOT NULL

✓ Yes

Indexes

N/A

Description

Metadata

  • Auto-increment uses AUTOINCREMENT START ... INCREMENT ...

  • Primary keys and foreign keys are not enforced — they exist for documentation and query optimization only

  • Only NOT NULL constraints are enforced in standard tables

  • Indexes are not applicable (Snowflake uses clustering keys instead)

Limited support. BigQuery constraints are metadata only.

Attribute
Supported
Enforced

Primary Key

✗ No (NOT ENFORCED)

Foreign Key

✗ No (NOT ENFORCED)

Auto-increment

N/A

Default Value

N/A

NOT NULL

✓ Yes

Indexes

N/A

Description

Metadata

  • Primary keys and foreign keys use NOT ENFORCED syntax (query optimization hints only)

  • Column descriptions via ALTER TABLE ... SET OPTIONS

  • No identity columns—use application-generated IDs or GENERATE_UUID()

DDL supported but PK/FK not enforced. Redshift is an analytical data warehouse.

Attribute
Supported
Enforced

Primary Key

✗ No (informational)

Foreign Key

✗ No (informational)

Auto-increment

✓ Yes

Default Value

✓ Yes

NOT NULL

✓ Yes

Indexes

N/A

Description

Metadata

  • Auto-increment uses IDENTITY(seed, increment)

  • Primary keys and foreign keys are informational only — used as query optimizer hints, not enforced

  • Does not support traditional indexes; use SORTKEY and DISTKEY for performance

  • Comments via COMMENT ON syntax

Most features supported. Foreign keys require explicit enabling.

Attribute
Supported
Enforced

Primary Key

✓ Yes

Foreign Key

✓ Yes (when enabled)

Auto-increment

✓ Yes

Default Value

✓ Yes

NOT NULL

✓ Yes

Indexes

Functional

Description

N/A

  • Auto-increment only works with INTEGER PRIMARY KEY columns

  • Foreign keys require PRAGMA foreign_keys = ON per connection (disabled by default)

  • No native column/table comment support

Partial support but constraints are enforced. DuckDB enforces integrity unlike most analytical DBs.

Attribute
Supported
Enforced

Primary Key

✓ Yes

Foreign Key

✓ Yes

Auto-increment

N/A

Default Value

N/A

NOT NULL

✓ Yes

Indexes

Functional

Description

Metadata

  • No native identity columns—use sequences with DEFAULT nextval('seq')

  • Foreign keys are enforced (unlike Snowflake, BigQuery, Redshift)

  • Indexes are fully supported via duckdb_indexes() metadata

  • Column descriptions via COMMENT ON syntax

DDL supported but PK/FK not enforced. Databricks uses Delta Lake.

Attribute
Supported
Enforced

Primary Key

✗ No (informational)

Foreign Key

✗ No (informational)

Auto-increment

✓ Yes

Default Value

✓ Yes

NOT NULL

✓ Yes

Indexes

N/A

Description

Metadata

  • Auto-increment uses GENERATED BY DEFAULT AS IDENTITY (BIGINT only)

  • Note: When Databricks is used as a source, identity column detection is limited (Databricks doesn't expose identity metadata via information_schema)

  • Primary keys and foreign keys are informational only — used for query optimization

  • Only NOT NULL and CHECK constraints are enforced

  • Does not support traditional indexes; use Z-ordering for performance

Limited support. ClickHouse is optimized for OLAP, not constraint enforcement.

Attribute
Supported
Enforced

Primary Key

✗ No (sort order only)

Foreign Key

N/A

Auto-increment

N/A

Default Value

✓ Yes

NOT NULL

✗ No

Indexes

N/A

Description

Metadata

  • Primary key defines sort order and sparse index — does not enforce uniqueness

  • No foreign key support

  • No auto-increment columns (use generateSerialID() in v25.1+)

  • NOT NULL is not enforced; use Nullable(T) wrapper to allow NULLs

  • Uses data-skipping indexes (MinMax, Bloom) instead of traditional indexes

Enabling Schema Migration

Set the SLING_SCHEMA_MIGRATION environment variable to enable specific attributes:

Available Options

Value
Description

all

Enable all schema migration attributes

primary_key

Migrate primary key constraints

foreign_key

Migrate foreign key relationships

indexes

Migrate indexes (non-PK)

auto_increment

Migrate identity/auto-increment columns

nullable

Migrate NOT NULL constraints

default_value

Migrate column default values

description

Migrate column and table comments

Basic Example

Migrate all schema attributes from SQL Server to PostgreSQL:

Foreign Key Migration

When migrating foreign keys, Sling automatically handles table ordering to ensure parent tables are created before child tables that reference them.

Automatic Table Ordering

Sling performs topological sorting based on foreign key dependencies. Even if you list tables in the wrong order, they will be processed correctly:

Sling will automatically reorder streams to: customersordersorder_items

Handling Circular Dependencies

If circular foreign key dependencies are detected, Sling will report an error. Options to resolve:

  1. Remove one table from the replication

  2. Disable foreign key migration

  3. Handle FK creation manually via hooks

Auto-Increment / Identity Columns

Sling migrates auto-increment columns with their seed and increment values:

Database-Specific Behavior

Source
Target
Result

SQL Server IDENTITY(1,1)

PostgreSQL

GENERATED BY DEFAULT AS IDENTITY

PostgreSQL SERIAL

MySQL

AUTO_INCREMENT

Oracle GENERATED AS IDENTITY

SQL Server

IDENTITY(seed, incr)

Default Values

Sling translates default value expressions between databases:

Default Value Translation

Expression
SQL Server
PostgreSQL
MySQL
Oracle

Current timestamp

GETDATE()

CURRENT_TIMESTAMP

CURRENT_TIMESTAMP

SYSDATE

UTC timestamp

GETUTCDATE()

CURRENT_TIMESTAMP AT TIME ZONE 'UTC'

UTC_TIMESTAMP()

SYS_EXTRACT_UTC(SYSTIMESTAMP)

UUID

NEWID()

gen_random_uuid()

UUID()

SYS_GUID()

Boolean true

1

true

1

1

Boolean false

0

false

0

0

Column & Table Descriptions

Migrate comments and descriptions to preserve documentation:

This will migrate:

  • Column comments (e.g., COMMENT ON COLUMN products.price IS 'Product retail price')

  • Table comments (e.g., COMMENT ON TABLE products IS 'Product catalog')

Indexes

Migrate non-primary key indexes to preserve query performance:

This migrates regular indexes, unique indexes, and composite indexes.

Index names are automatically generated in the target database to avoid conflicts. The format is idx_{table}_{columns}.

Complete E-Commerce Migration Example

A comprehensive example migrating an e-commerce schema with all relationships:

Selective Attribute Migration

Enable only specific attributes based on your needs:

Data Integrity Focus

Performance Focus

Documentation Preservation

Using with Pipelines

Schema migration can also be used within pipelines:

Incremental Mode Considerations

Schema migration attributes are applied during table creation. When using incremental mode:

  • First run: Table is created with all schema attributes

  • Subsequent runs: Only data is upserted; schema is not modified

Troubleshooting

Missing Foreign Key Dependencies

Error: missing foreign key dependencies: 'orders' depends on 'customers' (not in stream list)

Solution: Add the missing referenced table to your streams:

Circular Dependency Detected

Error: circular foreign key dependency detected involving: table_a, table_b

Solution: Either disable FK migration or handle FKs manually with hooks:

Unsupported Default Expression

If a default expression cannot be translated, Sling will pass it through as-is with a debug warning. You may need to manually adjust the default in the target database.

Identity Column Conflicts

When using auto_increment migration, Sling uses GENERATED BY DEFAULT AS IDENTITY (PostgreSQL/Oracle) to allow explicit value inserts during data migration while still supporting auto-generation for new inserts.

Best Practices

  1. Test First: Run schema migration on a test environment before production

  2. Start Selective: Begin with primary_key only, then add more attributes

  3. Include All Dependencies: Ensure all FK-referenced tables are in the replication

  4. Use Full-Refresh: Schema attributes are best applied with full-refresh mode initially

  5. Review Generated Schema: After migration, review the target schema for any needed adjustments

  6. Consider Indexes Separately: Large tables may benefit from creating indexes after data load via hooks

See Also

Last updated

Was this helpful?