Online DDL
Online DDL
The engine classifies ALTER TABLE into three tiers with different costs.
Instant
These complete without rebuilding data. MariaDB rewrites the table metadata and the change takes effect immediately:
- Adding columns after all existing ones, when every existing column keeps its null bit
- Renaming a column or index
- Changing a column default
- Changing table-level options such as
COMPRESSION,BLOOM_FPR, orTOMBSTONE_DENSITY_TRIGGER
When table options change, the engine applies the new configuration to every live column family, the
data CF and each secondary-index CF, through tidesdb_cf_update_runtime_config() with
persist_to_disk=1. The change takes effect for new work, new SSTables and new memtable activity,
while existing SSTables keep their original settings and are read correctly. Cached share-level
options such as isolation level, TTL, and encryption settings are updated in memory too. The
exception is turning ENCRYPTED on or off, or changing ENCRYPTION_KEY_ID on an encrypted table,
which changes how every stored row is encoded, so the engine refuses it inplace (“TidesDB rewrites
every row on an encryption change, which needs a table copy”) and MariaDB runs it as a copy.
A stored row carries its null bitmap and then every field in table order, with only the field count
in its header and nothing naming the columns, so an old row decodes by position. Appending columns
is therefore instant, and an old row reads each appended column as its DEFAULT, including a
nullable column with a non-NULL default. Any change that moves an existing column or its null bit
takes a table copy instead. That covers DROP COLUMN, ADD COLUMN ... FIRST or AFTER, any column
reorder, adding the first variable-length column such as a VARCHAR to a table of only fixed-length
columns (the server then lays out the null bits one position later), adding a STORED generated
column, and adding a BIT column, which keeps part of its value in the null bitmap. An explicit
ALGORITHM=INSTANT on any of these is refused with the reason “TidesDB reads old rows by column
position, so only appending columns is instant”.
ALTER TABLE events ADD COLUMN priority INT NOT NULL DEFAULT 0, ALGORITHM=INSTANT;ALTER TABLE events ALTER COLUMN data SET DEFAULT 'none', ALGORITHM=INSTANT;ALTER TABLE events CHANGE kind event_kind VARCHAR(50), ALGORITHM=INSTANT;ALTER TABLE events COMPRESSION='ZSTD', ALGORITHM=INSTANT;Inplace
Adding or dropping a non-FULLTEXT, non-SPATIAL secondary index runs inplace. The engine creates a
new column family for the index, then scans the table to populate its entries. Adding an index runs
under a shared lock (HA_ALTER_INPLACE_SHARED_LOCK), so reads continue while writes wait for the
build. The new index is filled from a table scan and the engine keeps no log of concurrent writes to
replay, so LOCK=NONE is refused with the reason “TidesDB fills a new index from a table scan and
keeps no log of concurrent writes”. Dropping an index needs no lock.
Adding a UNIQUE index checks for duplicates during the scan, ignoring rows whose indexed value is
NULL in any part, and aborts with ER_DUP_ENTRY if any are found. If any row’s index put or batch
commit fails the whole ALTER rolls back and drops the new column family rather than shipping a
partial index. The population runs at READ COMMITTED and commits every 100 rows to keep the
transaction’s write buffer bounded, checking for KILL at the same interval.
ALTER TABLE events ADD INDEX idx_ts (ts), ALGORITHM=INPLACE;ALTER TABLE events DROP INDEX idx_ts, ALGORITHM=INPLACE;ALTER TABLE events ADD INDEX idx_kind (event_kind), DROP INDEX idx_ts, ALGORITHM=INPLACE;ADD FULLTEXT and ADD SPATIAL are not eligible for ALGORITHM=INPLACE, because the FTS tokenizer
and the spatial Hilbert-curve writer only run inside write_row and cannot be driven from a
row-by-row scan of an existing table. check_if_supported_inplace_alter returns
HA_ALTER_INPLACE_NOT_SUPPORTED for these with a reason, so MariaDB falls back to ALGORITHM=COPY,
which routes every existing row through write_row and back-fills the index correctly. An explicit
ALGORITHM=INPLACE on one of these is rejected with the reason.
Copy
Changing a column type, altering the primary key, dropping or reordering columns, adding a column anywhere but at the end, and changing encryption all need a full table copy:
ALTER TABLE events MODIFY COLUMN data MEDIUMTEXT;ALTER TABLE events DROP PRIMARY KEY, ADD PRIMARY KEY (id, ts);ALTER TABLE events DROP COLUMN priority;ALTER TABLE events ADD COLUMN source INT AFTER id;The engine reports these as not supported inplace, so an explicit ALGORITHM=INPLACE or
ALGORITHM=INSTANT fails with an error and a slow copy never happens where an instant change was
expected.