CREATE SOURCE: SQL Server (Legacy Syntax)
View as MarkdownCREATE SOURCE connects Materialize to an external system you want to read data from, and provides details about how to decode and interpret that data.
Materialize supports SQL Server (2016+) as a real-time data source. To connect to a
SQL Server database, you first need to tweak its configuration to enable Change Data
Capture
and SNAPSHOT transaction isolation
for the database that you would like to replicate. Then create a connection
in Materialize that specifies access and authentication parameters.
Syntax
CREATE SOURCE [IF NOT EXISTS] <src_name>
[IN CLUSTER <cluster_name>]
FROM SQL SERVER CONNECTION <connection_name>
[ ( EXCLUDE COLUMNS (<col1> [, ...]) ) ]
[ ( TEXT COLUMNS (<col1> [, ...]) ) ]
<FOR ALL TABLES | FOR TABLES ( <table1> [AS <subsrc_name>] [, ...] )>
[WITH ( <with_option> [, ...] )]
| Syntax element | Description | ||||||
|---|---|---|---|---|---|---|---|
<src_name>
|
The name for the source. | ||||||
| IF NOT EXISTS | Optional. If specified, do not throw an error if a source with the same name already exists. Instead, issue a notice and skip the source creation. | ||||||
IN CLUSTER <cluster_name>
|
Optional. The cluster to maintain this source. | ||||||
CONNECTION <connection_name>
|
The name of the SQL Server connection to use in the source. For details on creating connections, check the CREATE CONNECTION documentation page.
|
||||||
EXCLUDE COLUMNS ( <col1> [, …] )
|
Optional. Exclude specific columns that cannot be decoded or should not be included in the subsources created in Materialize. | ||||||
TEXT COLUMNS ( <col1> [, …] )
|
Optional. If specified, decode data from the specified columns in the subsource(s) as text for the listed column(s), such as for unsupported data types.
|
||||||
FOR <table_schema_specification>
|
Specifies which tables to create subsources for. The following
|
||||||
WITH (<with_option> [, …])
|
Optional. The following
|
Creating a source
Materialize ingests the CDC stream for all (or a specific set of) tables in your upstream SQL Server database that have Change Data Capture enabled.
CREATE SOURCE mz_source
FROM SQL SERVER CONNECTION sql_server_connection
FOR ALL TABLES;
When you define a source, Materialize will automatically:
-
Create a subsource for each capture instance upstream, and perform an initial, snapshot-based sync of the associated tables before it starts ingesting change events.
SHOW SOURCES;name | type | cluster | ----------------------+------------+------------ mz_source | sql-server | mz_source_progress | progress | table_1 | subsource | table_2 | subsource | -
Incrementally update any materialized or indexed views that depend on the source as change events stream in, as a result of
INSERT,UPDATEandDELETEoperations in the upstream SQL Server database.
SQL Server schemas
CREATE SOURCE will attempt to create each upstream table in the same schema as
the source. This may lead to naming collisions if, for example, you are
replicating schema1.table_1 and schema2.table_1. Use the FOR TABLES
clause to provide aliases for each upstream table, in such cases, or to specify
an alternative destination schema in Materialize.
CREATE SOURCE mz_source
FROM SQL SERVER CONNECTION sql_server_connection
FOR TABLES (schema1.table_1 AS s1_table_1, schema2.table_1 AS s2_table_1);
Monitoring source progress
By default, SQL Server sources expose progress metadata as a subsource that you
can use to monitor source ingestion progress. The name of the progress
subsource can be specified when creating a source using the EXPOSE PROGRESS AS clause; otherwise, it will be named <src_name>_progress.
The following metadata is available for each source as a progress subsource:
| Field | Type | Details |
|---|---|---|
lsn |
bytea |
The upper-bound Log Sequence Number replicated thus far into Materialize. |
And can be queried using:
SELECT lsn
FROM <src_name>_progress;
The reported lsn should increase as Materialize consumes new CDC events
from the upstream SQL Server database. For more details on monitoring source
ingestion progress and debugging related issues, see Troubleshooting.
Known limitations
Supported types
Materialize natively supports the following SQL Server types:
tinyintsmallintintbigintrealdouble precisionfloatbitdecimalnumericmoneysmallmoneycharncharvarcharvarchar(max)nvarcharnvarchar(max)sysnamebinaryvarbinaryjsondatetimesmalldatetimedatetimedatetime2datetimeoffsetuniqueidentifier
char and nchar columns
To preserve values exactly as SQL Server returns them, char and nchar columns
are replicated as text rather than fixed-length. SQL Server and Materialize
measure fixed-length character types differently, so replicating as text avoids
truncation and padding mismatches.
To replicate tables that contain the following unsupported data types, you can
use either the TEXT COLUMNS or the EXCLUDE COLUMNS option:
| Unsupported type | Supported option(s) |
|---|---|
text |
TEXT COLUMNS (exposed as varchar) or EXCLUDE COLUMNS |
ntext |
TEXT COLUMNS (exposed as nvarchar) or EXCLUDE COLUMNS |
image |
EXCLUDE COLUMNS |
varbinary(max) |
EXCLUDE COLUMNS |
Timestamp Rounding
The time, datetime2, and datetimeoffset types in SQL Server have a default
scale of 7 decimal places, or in other words a accuracy of 100 nanoseconds. But
the corresponding types in Materialize only support a scale of 6 decimal places.
If a column in SQL Server has a higher scale than what Materialize can support, it
will be rounded up to the largest scale possible.
-- In SQL Server
CREATE TABLE my_timestamps (a datetime2(7));
INSERT INTO my_timestamps VALUES
('2000-12-31 23:59:59.99999'),
('2000-12-31 23:59:59.999999'),
('2000-12-31 23:59:59.9999999');
-- Replicated into Materialize
SELECT * FROM my_timestamps;
'2000-12-31 23:59:59.999990'
'2000-12-31 23:59:59.999999'
'2001-01-01 00:00:00'
Snapshot latency for inactive databases
When a new Source is created, Materialize performs a snapshotting operation to sync the data. However, for a new SQL Server source, if none of the replicating tables are receiving write queries, snapshotting may take up to an additional 5 minutes to complete. The 5 minute interval is due to a hardcoded interval in the SQL Server Change Data Capture (CDC) implementation which only notifies CDC consumers every 5 minutes when no changes are made to replicating tables.
See Monitoring freshness status
Capture Instance Selection
When a new source is created, Materialize selects a capture instance for each
table. SQL Server permits at most two capture instances per table, which are
listed in the
sys.cdc_change_tables
system table. For each table, Materialize picks the capture instance with the
most recent create_date.
If two capture instances for a table share the same timestamp (unlikely given the millisecond resolution), Materialize selects the capture_instance with the lexicographically larger name.
Modifying an existing source
When you add a new subsource to an existing source (ALTER SOURCE ... ADD SUBSOURCE ...), Materialize starts the snapshotting
process for the new subsource. During this snapshotting, the data ingestion for
the existing subsources for the same source is temporarily blocked. As such, if
possible, you can resize the cluster to speed up the snapshotting process and
once the process finishes, resize the cluster for steady-state.
Handling upstream operations
This section describes how changes to upstream tables that Materialize ingests affect the corresponding Materialize tables.
Adding a column
When you add a new column to your upstream table, Materialize continues to ingest only the existing columns.
To incorporate the new column:
-
If using the new
CREATE SOURCEandCREATE TABLE FROM SOURCEsyntax, create a new table from the source. See Handle upstream column addition. -
If using the legacy
CREATE SOURCE ... FOR ...syntax that creates subsources, useDROP SOURCEto drop the affected subsource, and then add the table back to the source usingALTER SOURCE ... ADD SUBSOURCE. The re-added subsource includes the new column.
Dropping a column
Dropping columns that Materialize does not ingest (for example, columns added after the source was created, or columns that are excluded) is supported. As these columns were never ingested, you can drop them without issue.
If your Materialize source ingests a column, dropping that column from your upstream table puts the affected table into an error state.
-
If using the new
CREATE SOURCEandCREATE TABLE FROM SOURCEsyntax, you can safely drop a column by first ignoring it in Materialize. See Handle upstream column drop. -
If using legacy
CREATE SOURCE ... FOR ...syntax, useDROP SOURCEto drop the affected subsource, and then add the table back to the source usingALTER SOURCE ... ADD SUBSOURCE.
Changing constraints
Materialize ignores foreign key and CHECK constraint changes. You can add or
drop them without affecting ingestion.
Adding a UNIQUE constraint does not affect ingestion. Dropping a UNIQUE
constraint puts the affected table into an error state.
SQL Server does not allow dropping a PRIMARY KEY from a table while change data
capture is enabled on it. A primary key that existed when Materialize began
ingesting the table therefore cannot be dropped upstream.
Adding or removing a NOT NULL constraint on an ingested column requires an
upstream ALTER COLUMN, which puts the affected table into an error state. See
Changing a column’s data type.
Changing a column’s data type
Any upstream ALTER COLUMN on an ingested column puts the affected Materialize
table into an error state. This covers every ALTER COLUMN operation, not just
data-type changes. Changing a column’s collation, sparseness, masking, or
nullability all error the table the same way. Ingestion for that table stops,
and you must drop and recreate the table in Materialize to resume ingestion.
Renaming a column
Renaming a column that Materialize ingests puts the affected table into an error state. Ingestion for that table stops, and you must drop and recreate the table in Materialize to resume ingestion.
Removing a capture instance
SQL Server allows up to two capture instances to exist for a table at once. Materialize ingests from one of them.
Removing the capture instance that Materialize is using puts the affected table into an error state. Removing a capture instance that Materialize is not using does not affect ingestion.
Table-level operations
The following upstream operations put the affected table into an error state. Ingestion for that table stops, and you must drop and recreate the affected table in Materialize to resume:
- Dropping a table (
DROP TABLE). - Renaming a table or moving it to a different schema.
Examples
SNAPSHOT transaction isolation in the upstream database.
Creating a connection
A connection describes how to connect and authenticate to an external system you want Materialize to read data from.
Once created, a connection is reusable across multiple CREATE SOURCE
statements. For more details on creating connections, check the
CREATE CONNECTION documentation page.
CREATE SECRET sqlserver_pass AS '<SQL_SERVER_PASSWORD>';
CREATE CONNECTION sqlserver_connection TO SQL SERVER (
HOST 'instance.foo000.us-west-1.rds.amazonaws.com',
PORT 1433,
USER 'materialize',
PASSWORD SECRET sqlserver_pass,
DATABASE '<DATABASE_NAME>'
);
If your SQL Server instance is not exposed to the public internet, you can tunnel the connection through and SSH bastion host.
CREATE CONNECTION ssh_connection TO SSH TUNNEL (
HOST 'bastion-host',
PORT 22,
USER 'materialize',
DATABASE '<DATABASE_NAME>'
);
CREATE CONNECTION sqlserver_connection TO SQL SERVER (
HOST 'instance.foo000.us-west-1.rds.amazonaws.com',
SSH TUNNEL ssh_connection,
DATABASE '<DATABASE_NAME>'
);
For step-by-step instructions on creating SSH tunnel connections and configuring an SSH bastion server to accept connections from Materialize, check this guide.
Creating a source
You must enable Change Data Capture. See the setup instructions for Azure SQL Database or self-hosted SQL Server.
Once CDC is enabled for all of the relevant tables, you can create a SOURCE in
Materialize to begin replicating data!
Create subsources for all tables in SQL Server
CREATE SOURCE mz_source
FROM SQL SERVER CONNECTION sqlserver_connection
FOR ALL TABLES;
Create subsources for specific tables in SQL Server
CREATE SOURCE mz_source
FROM SQL SERVER CONNECTION sqlserver_connection
FOR TABLES (mydb.table_1, mydb.table_2 AS alias_table_2);
Handling unsupported types
If you’re replicating tables that use data types unsupported
by SQL Server’s CDC feature, use the EXCLUDE COLUMNS option to exclude them from
replication. This option expects the upstream fully-qualified names of the
replicated table and column (i.e. as defined in your SQL Server database).
CREATE SOURCE mz_source
FROM SQL SERVER CONNECTION sqlserver_connection (
EXCLUDE COLUMNS (mydb.table_1.column_of_unsupported_type)
)
FOR ALL TABLES;
Handling errors and schema changes
To handle upstream schema changes or errored subsources, use
the DROP SOURCE syntax to drop the affected
subsource, and then ALTER SOURCE...ADD SUBSOURCE to add
the subsource back to the source.
-- List all subsources in mz_source
SHOW SUBSOURCES ON mz_source;
-- Get rid of an outdated or errored subsource
DROP SOURCE table_1;
-- Start ingesting the table with the updated schema or fix
ALTER SOURCE mz_source ADD SUBSOURCE table_1;