What you will learn

The goal is to support one access pattern: retrieve events for a tenant. A relational table layout should not be copied blindly into Cassandra, where the primary key determines data distribution and query shape.

Before you begin

Use a quiesced Oracle lab table with synthetic tenant IDs, integer event IDs, and text messages. Prepare cqlsh and a Cassandra lab keyspace. Export through an approved SQL client with CSV quoting enabled; client-specific export switches vary.

1. Define the target query

SELECT tenant_id,event_id,message FROM tutorial_events ORDER BY tenant_id,event_id;

The intended Cassandra query is all events for one tenant. Check that tenants have bounded partition sizes; a single unbounded tenant becomes a hot partition. Preserve decimal precision and date semantics explicitly if you extend the example.

2. Create the target layout

CREATE TABLE tutorial.events (tenant_id text, event_id int, message text, PRIMARY KEY (tenant_id,event_id));

The first key component identifies the partition; event_id orders rows inside it. Check uniqueness of that pair in the Oracle result before loading.

3. Export and import the sample

Export the three named columns as UTF-8 CSV with a header into a private file on the cqlsh host. Inspect quoted commas and null values, then load:

COPY tutorial.events (tenant_id,event_id,message) FROM '/srv/migration/oracle-events.csv' WITH HEADER=TRUE;

4. Validate the actual access pattern

SELECT * FROM tutorial.events WHERE tenant_id='demo';

Compare the entire demo partition with the corresponding Oracle query. For larger migrations, use a measured bulk-loader workflow and a separate design for writes arriving during the copy.

Example output

The following is an illustrative, normalized lab result, not output captured from a live customer system. Your versions, addresses, timings, and row counts will differ.

Illustrative comparison for one tenant:
Source key            Target key           Result
(demo, 1)             (demo, 1)             message matches
(demo, 2)             (demo, 2)             message matches
Unexpected target keys: 0

Create two synthetic source rows to reproduce this comparison. The composite key is compared as a pair; matching only event_id can hide a wrong tenant mapping.

Verify the result

The target returns the same event IDs and messages for the sampled tenants. Confirm null and empty-string decisions, character encoding, and partition sizes. A matching global count does not prove the partition design is suitable.

Troubleshooting

If Cassandra rejects a query without its partition key, revisit the access pattern instead of adding ALLOW FILTERING indiscriminately. If rows overwrite one another, the selected primary key is not unique enough.

Recovery and next steps

Keep Oracle authoritative until the target model and application queries pass. Replay only a defined immutable export into a disposable target during rehearsal; a bulk import is not change-data capture.

References