Skip to content
In this guide

Guide · Doing

Design a schema change

Read this when you need a new table, column or foreign key and want to see the SQL, and the locks it takes, before anything touches the database. Design mode is Pro, works on all four engines, and runs nothing until the change has passed its checks and a dry run.

Start a design

  1. Press ⇧⌘E on macOS or Ctrl+Shift+E on Windows, and pick commerce.
  2. Click Design changes in the diagram's toolbar.
  3. Click New design for commerce.

Earlier designs are listed under Saved designs, each with Delete design, which asks first and changes nothing in the database. The workbench shows the canvas, an inspector and the SQL pane, and saves as you work: the toolbar says Saved.

On Free, saved designs open read-only: "Saved designs open read-only on Free. Upgrade to keep designing."

The ER diagram of the commerce schema stepping into design mode: a new table is added under orders, named, and linked to it by dragging a column.

The figure adds a reviews table and links it to orders, as the next sections do.

Add a table

  1. Press T. The toolbar's New table button does the same, and so does double-clicking empty canvas.
  2. Type reviews and press Enter.

The new table gets a primary key in the style the New table key menu beside the button names: bigint identity key or uuid key on PostgreSQL.

Add a column

  1. Right-click the reviews table and click Add column.
  2. Name it rating.
  3. Set its Type in the inspector, for example smallint.
  4. Tick Required (NOT NULL).

The inspector also holds Default and Identity, and the toggles Primary key and Unique. A Default is one expression. 0, 1, a NOT NULL outside brackets, an unclosed quote or an unbalanced bracket is reported as a blocker, so a default can never smuggle a second clause into the ALTER TABLE. Defaults read from the live database are left as they are.

  1. Drag the dot at the end of the id row in orders onto reviews.
  2. In the New link popover, choose Many-to-one. One-to-one and Many-to-many are the other choices.
  3. Set On delete to Cascade, so a deleted order takes its reviews with it.
  4. Click Done.

The other On delete choices are No action, Restrict, Set null and Set default. Undo link takes the link back.

Read the inspector

With nothing selected, the inspector describes the whole design. Changes, Blockers and Warnings count what you've done and what's wrong with it. A blocker stops the apply. A warning asks you to confirm it during review. Issues lists both, or says "No problems in the design." Suggestions holds what Seqora noticed but won't insist on. A column named customer_id with no foreign key, in a schema where customers has a key of the same type, is suggested as a link. A Link button draws it.

Select a link to change its On delete and On update.

Read the SQL pane

The SQL pane updates with every edit and tags each statement that will hurt. On PostgreSQL:

Tag What the statement does Example
Deletes data Drops a table or a column. Dropping orders.channel
Rewrites table Rewrites every row. A new column with a volatile default or an identity
Scans table Reads every row to check it. A NOT NULL column, an index, a foreign key on an existing table
Blocks reads and writes Takes an ACCESS EXCLUSIVE lock. Most ALTER TABLE statements
Blocks writes Takes a SHARE or SHARE ROW EXCLUSIVE lock. CREATE INDEX, a new foreign key to an existing table

Read the tags together. A statement on commerce.orders tagged both Scans table and Blocks reads and writes holds its lock for as long as reading 12,000,000 rows takes, and every query on orders waits behind it.

Selection only narrows the pane to the selected table. Copy SQL copies the script.

Review and apply

  1. Click Review and apply. The review opens on Checks, the first of Checks → Dry run → Apply, under the eyebrow Review changes.
  2. Read the checks: read-only queries for empty values, duplicates, orphan rows and dependent objects, under Must fix, Check before applying and Passed and notes.
  3. Tick I understand on each warning you accept.
  4. Click Dry run.
  5. Click the apply button. It names the count, as in Apply 2 statements.

If the schema changed after you started, the checks say "The live schema changed since this design started". Click Rebase onto the live schema to replay your edits on the current one.

Data checks skip tables over 5,000,000 rows, and say which: "Data checks were skipped on large tables (commerce.orders) so the review doesn't scan millions of rows. The dry run still tests every statement." Check them anyway includes them.

What the dry run and the apply do depends on the engine:

Engine Dry run Apply
PostgreSQL Runs every statement in a transaction and rolls it back, with lock_timeout at 5 seconds and statement_timeout at 120 seconds. One transaction, with SET LOCAL lock_timeout at 10 seconds and no statement timeout.
SQLite Runs every statement in a transaction and rolls it back. One transaction, with foreign-key enforcement off until the end, then checked.
MySQL, MariaDB Replays every statement on empty copies of the tables in a scratch database, then drops it. Each statement commits on its own. Seqora stops at the first failure.

On a production connection, which Connect defines, the apply step asks you to type the database name first: "This is a production connection. Type commerce to apply." On a locked connection the checks run and the dry run waits: "This connection is locked against writes", with an Unlock connection button.

When it's done you see Changes applied, and the catalog and diagram refresh. Save as .sql writes the script to your SQL folder, ready to commit as a migration. The design stays as a record that can't be edited.

Caveats

  • A PostgreSQL dry run executes the real statements before rolling back, so it takes the same locks for as long as they run. Dry-run a change to a busy table when it is quiet.
  • On MySQL and MariaDB, if a statement fails during apply, the ones before it stay applied. Refresh the schema and rebase the design before trying again.
  • The MySQL dry run needs CREATE on seqora_scratch_% databases. Without it Seqora checks only the syntax, and says "Only the syntax was checked".
  • Seqora only applies statements the designer generated. There is no field for hand-written DDL. Run that from Run, cancel, and transactions.
  • Expression and partial indexes and generated columns are kept as they are.
  • The tag examples above are PostgreSQL's. Each engine's DDL generator sets its own tags, so the same drawing can carry different ones on MySQL, MariaDB or SQLite.

Last checked against Seqora 0.3.2, PostgreSQL 17 on .

Found a bug, missing a feature, or just curious? Write to me. Every email lands in my own inbox, not a ticket queue.