history preserving data models
By traviscj
- 2 minutes read - 270 wordsStart with a super simple data model:
CREATE TABLE kv (
id BIGINT(22) NOT NULL AUTO_INCREMENT,
k VARCHAR(255) NOT NULL,
v LONGBLOB NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY u_k (`k`)
) Engine=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
Suppose we want to audit “changes” to this data model.
Approach 1: kv_log
add data model like
CREATE TABLE `kv_log` (
id BIGINT(22) NOT NULL AUTO_INCREMENT,
changed_at TIMESTAMP NOT NULL,
k VARCHAR(255) NOT NULL,
old_v LONGBLOB NOT NULL,
new_v LONGBLOB NOT NULL,
)
current value query: unchanged
log query:
SELECT *
FROM kv_log
WHERE k = :key;
- PRO: straightforward
- PRO: separation of concerns
- CON: might forget to write
kv_log
record when updating records via aROLL
plan, or even
Approach 2: kv_events
replace kv
with
CREATE TABLE `kv_events` (
id BIGINT(22) NOT NULL AUTO_INCREMENT,
update_type ENUM("INSERT", "UPDATE", "DELETE") NOT NULL,
changed_at TIMESTAMP NOT NULL,
k VARCHAR(255) NOT NULL,
v LONGBLOB NOT NULL,
PRIMARY KEY (`id`),
KEY k__key__created_at (`k`, `created_at`)
)
current value query
(NOTE: this is a bit incorrect as it stands, because the most recent record might be a DELETE
…)
SELECT *
FROM kv_events
WHERE k = :key
ORDER BY changed_at DESC
LIMIT 1;
log query:
SELECT *
FROM kv_events
WHERE k = :key;
Approach 3: kv2
replace kv
with:
CREATE TABLE kv2 (
id BIGINT(22) NOT NULL AUTO_INCREMENT,
effective_at TIMESTAMP NOT NULL,
effective_until TIMESTAMP,
active TINYINT(1),
k VARCHAR(255) NOT NULL,
v LONGBLOB NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u_k` (`k`, `active`)
) Engine=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin
current value query:
SELECT *
FROM kv2
WHERE active = 1
AND k = :key;
log query:
SELECT *
FROM kv2
WHERE k = :key;