What can ALTER TABLE do, and what does each operation cost?
ALTER TABLE changes the structure of an existing table: add a column, drop a column, rename a column, change a column's type, add or drop a constraint, add or drop an index. The operations and their costs vary enormously, and the difference matters on a large table.
CREATE TABLE tickets (
id INTEGER PRIMARY KEY,
title VARCHAR(160) NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'open'
);
INSERT INTO tickets (id, title) VALUES (1, 'Login page times out');
-- Add a column with a default.
ALTER TABLE tickets ADD COLUMN priority INTEGER NOT NULL DEFAULT 1;
-- Add a nullable column with no default.
ALTER TABLE tickets ADD COLUMN assignee_id INTEGER;
-- Rename a column.
ALTER TABLE tickets RENAME COLUMN title TO subject;
-- Drop a column.
ALTER TABLE tickets DROP COLUMN assignee_id;
SELECT id, subject, status, priority FROM tickets ORDER BY id;One row comes back: ticket 1 with subject 'Login page times out', status 'open' and priority 1. Every one of the four alterations succeeded, and the table still holds its data.
The costs are the interesting part. Adding a column with a constant default is cheap on every modern engine, because the value is stored in the table's metadata rather than written into each row — that is how SQLite, PostgreSQL 11 and later, and MySQL 8 handle it. Adding a column with a volatile default, or changing a column's type, is a different matter: on some engines it rewrites every row and takes an exclusive lock for the duration. Dropping a column is metadata-only on most engines, but the space is not reclaimed until the table is vacuumed. Renaming a column is metadata-only everywhere, which is why it is the cheapest structural change there is.
SQLite's own limits are worth knowing since it is the engine these examples use. It supports ADD COLUMN, RENAME COLUMN, RENAME TABLE and DROP COLUMN from version 3.35.0 onwards, but it does not support ALTER COLUMN to change a column's type, and it does not support adding a table-level constraint after the fact — the constraint has to be in the CREATE TABLE statement. SQLite also will not let you drop a column that is indexed or referenced by a foreign key or a view.