Skip to Content
We are live but in Staging 🎉

UPDATE

UPDATE shapes. The planner picks a strategy based on whether the predicate matches the table’s merge_keys. Keyed predicates route through the write log; non-keyed predicates bypass it (WAL-bypass risk — two safe patterns documented below). For the RPC contract and full enum reference, see the Execute hub.

Keyed updates

PK-matched predicates → write-log route → compactor MERGE on next drain. Safe under concurrent writes; visible immediately under freshness=STRONG.

KEYED_UPDATE — point UPDATE on PK

UPDATE events SET event_type = 'click_pricing' WHERE id = 1 AND user_id = 'u-101';

Response: strategy: WRITE_STRATEGY_KEYED_UPDATE, rowsWritten: "1", pendingDrain: true.

KEYED_RANGE — UPDATE … WHERE pk IN (range)

UPDATE events SET event_type = 'archived' WHERE id BETWEEN 1000 AND 2000 AND user_id = 'u-101';

K3 enumerates the affected keys via SELECT pk FROM events WHERE ... then writes one log entry per key.

Response: strategy: WRITE_STRATEGY_KEYED_RANGE. If the range resolved to zero keys, noop: true.

KEYED_FROM_SUBQUERY — UPDATE … WHERE pk IN (SELECT …)

-- Mark all events for inactive users UPDATE events SET event_type = 'archived' WHERE (id, user_id) IN ( SELECT e.id, e.user_id FROM events e JOIN users u ON e.user_id = u.id WHERE u.status = 'inactive' );

Response: strategy: WRITE_STRATEGY_KEYED_FROM_SUBQUERY.

Non-keyed updates — ⚠️ WAL-bypass

NON_KEYED_UPDATE

Predicate doesn’t match merge_keys → planner routes directly to Delta, bypasses write log.

-- WHERE column is NOT in merge_keys=[id, user_id] UPDATE events SET event_type = 'archived' WHERE occurred_at < TIMESTAMP '2025-01-01 00:00:00';

Response includes a warning:

{ "write": { "rowsWritten": "12000", "strategy": "WRITE_STRATEGY_NON_KEYED_UPDATE", "pendingDrain": false, "targetTable": "events", "warnings": [ "Routed to warehouse only; bypasses write log. Risk: un-drained log entries for affected rows may overwrite this change on next drain." ] } }

Two safe patterns before running non-keyed writes on tables that take concurrent keyed writes:

  1. Run Compact first to fully drain the log:

    # Drain until truncated=false, then update directly dodil k3 table compact events --bucket kb-prod # Then issue the non-keyed UPDATE
  2. Or materialize the affected PKs into a subquery so the planner picks KEYED_FROM_SUBQUERY instead:

    UPDATE events SET event_type = 'archived' WHERE (id, user_id) IN ( SELECT id, user_id FROM events WHERE occurred_at < TIMESTAMP '2025-01-01 00:00:00' );

See also