Phoenix favicon

Apache Phoenix

Features

TTL

Phoenix TTL flavors (time-based, view, conditional) and the IS_STRICT_TTL property that controls visibility of expired rows.

Phoenix supports per-row time-to-live (TTL) so that rows can be expired and removed without an application-issued DELETE. There are three flavors, and one orthogonal table property — IS_STRICT_TTL — that controls how aggressively expired rows are hidden from reads.

Time-based TTL

Set a numeric value (in seconds) on the TTL table property at CREATE TABLE time to age every row out a fixed duration after its cell timestamp:

CREATE TABLE events (...) TTL = 604800;   -- 7 days
ALTER TABLE events SET TTL = 2592000;     -- bump to 30 days
ALTER TABLE events SET TTL = NONE;        -- remove TTL

Rows older than the TTL are removed by Phoenix compaction during HBase region compactions. Time-based TTL is the right choice when retention is a flat duration that applies uniformly to every row in the table.

View TTL

Each view over a shared base table can set its own retention window, so different tenants or use cases can age data out independently without splitting the underlying table. See View TTL for the full feature.

Conditional TTL

Express row expiration as a SQL boolean expression evaluated against the row's own column values, instead of a fixed duration. A row is considered expired the moment the expression evaluates to TRUE for that row. See Conditional TTL for the full feature.

Strict vs Relaxed TTL

IS_STRICT_TTL is a table property that controls how strictly expired rows are hidden from reads. It applies to every flavor of TTL above — time-based, view, and conditional. The default is true (strict).

ModeBehavior
Strict (IS_STRICT_TTL = true, default)Expired rows are filtered out on every read path — they're invisible to queries the moment they expire.
Relaxed (IS_STRICT_TTL = false)Expired rows remain visible to readers until major compaction physically removes them. Similar to DynamoDB's TTL expiry behavior.

The trade-off:

  • Strict gives you a strong "expired = invisible" guarantee. It's the right choice when retention is a correctness or compliance concern.
  • Relaxed has a cheaper write path. The largest gain is with Conditional TTL: under strict mode, every mutation reads the current row state to evaluate the TTL expression, which adds latency. Relaxed mode skips that pre-read.
-- Strict (default).
CREATE TABLE strict_events (...) TTL = 604800;

-- Relaxed: cheaper write path, eventual visibility of expired rows.
CREATE TABLE relaxed_events (...) TTL = 604800, IS_STRICT_TTL = false;

You can also switch a table between modes:

ALTER TABLE events SET IS_STRICT_TTL = false;

Start with the default. Switch to relaxed only when the cheaper write path is the right trade-off for your workload and eventual visibility of expired rows is acceptable for your readers.

Edit on GitHub

On this page