Derry Holt
08/19/2026, 9:04 AMRocky
08/19/2026, 9:04 AMpartition_refresh_number
The property partition_refresh_number (defaulting to 1 in versions 3.3+) controls how many partitions are refreshed in a single internal batch.
* If this value is set (e.g., 10), and 20 partitions are stale, StarRocks will take the 10 oldest stale partitions, refresh them, and then move on to the next 10.
* The goal of this sequential "old-to-new" processing is to ensure that the materialized view reaches a consistent state across the timeline, starting from the past.
3. Manual Overrides
You can change this behavior by manually specifying which partitions to refresh. For example:
sql
REFRESH MATERIALIZED VIEW my_mv
PARTITION START ("2023-01-01") END ("2023-01-02");
By manually targeting a specific range, you can force a newer batch to refresh regardless of the state of older batches. However, in the absence of manual intervention, the system's automated scheduler favors the older data first.
Summary
If an older batch has already been materialized once but becomes stale again (due to base table changes), it will be queued for rematerialization ahead of newer stale batches because of StarRocks' "least recent to most recent" scheduling logic." most-stale-first / chronological-ascending" scheduling strategy.
References
• using_starrocks/async_mv/use_cases/create_partitioned_materialized_view.md
• using_starrocks/async_mv/Materialized_view.md
• sql-reference/sql-statements/materialized_view/REFRESH_MATERIALIZED_VIEW.mdDerry Holt
08/19/2026, 9:08 AMRocky
08/19/2026, 9:08 AMUPDATE statements on the gold table. Instead, you treat the "delete event" as a stream of data that updates only the is_deleted flag.
1. Table Design
Ensure your gold table is a Primary Key table and includes a soft-delete flag (e.g., is_deleted).
sql
CREATE TABLE gold_table (
record_id BIGINT NOT NULL,
data_field_1 VARCHAR(100),
data_field_2 INT,
is_deleted BOOLEAN DEFAULT FALSE,
updated_at DATETIME
)
ENGINE=OLAP
PRIMARY KEY(record_id)
DISTRIBUTED BY HASH(record_id);
2. The Soft Delete Strategy: Partial Update
When a "delete" event arrives in your JSON stream (e.g., {"id": 123, "event_type": "DELETE"}), you can perform a Partial Update via Stream Load or Routine Load. This allows you to update the is_deleted column without providing values for all the other columns (data_field_1, etc.).
How to implement it:
* Property: Set "partial_update" = "true".
* Column Mapping: Map the ID from the JSON to your Primary Key and set is_deleted = true.
Example using Routine Load (Kafka):
If your Kafka JSON looks like {"id": 123, "op": "del"}, you can create a routine load that specifically targets the soft-delete flag:
sql
CREATE ROUTINE LOAD soft_delete_job ON gold_table
COLUMNS(record_id, is_deleted = 1) -- Hardcode is_deleted to 1
PROPERTIES (
"format" = "json",
"jsonpaths" = "[\"$.id\"]", -- Only extract the ID
"partial_update" = "true" -- Crucial: tells StarRocks not to overwrite other columns with NULL
)
FROM KAFKA ( ... );
3. Handling Different Event Types in One Stream
If your JSON stream contains both INSERT and DELETE events, you can use conditional column mapping to set the is_deleted flag dynamically:
sql
-- In Stream Load or Routine Load headers/properties
"columns": "tmp_id, tmp_op, record_id = tmp_id, is_deleted = if(tmp_op = 'del', 1, 0)"
Why this is the "Best Approach":
1. Performance: StarRocks PK tables use a "Delete+Insert" strategy internally. A partial update is highly optimized and avoids the heavy overhead of standard SQL UPDATE commands.
2. Simplicity: You don't need a separate "reaper" process or complex logic to find and update rows. The ingestion pipeline handles it as standard data flow.
3. Data Integrity: By using PK tables, you ensure that even if a "Delete" event arrives slightly out of order with an "Update" event, you can use a version column (via the __version property) to ensure the final state is correct.
Querying
Since the records still exist in the table, you should create a view on top of your gold table to simplify downstream consumption:
sql
CREATE VIEW active_gold_table AS
SELECT * FROM gold_table WHERE is_deleted = FALSE;
*Note: If you ever need to perform a hard delete instead, you can include the __op column in your load and set it to 1 (for Delete), which will physically remove the record from the PK table's index.*
References
• loading/Load_to_Primary_Key_tables.md
• loading/StreamLoad.md
• loading/Flink-connector-starrocks.mdDerry Holt
08/19/2026, 9:10 AMRocky
08/19/2026, 9:10 AMis_deleted flag in your payload and headers.
* Header: Set partial_update: true.
* Columns: Specify only the columns you are providing.
bash
curl --location-trusted -u root: \
-H "partial_update: true" \
-H "columns: record_id, is_deleted=1" \
-T delete_events.json -XPUT \
http://<fe_host>:<fe_http_port>/api/db/gold_table/_stream_load
_In this case, only the is_deleted column is updated; all other existing data for that record_id remains untouched._
──────────
2. Bronze-to-Gold Movement (INSERT INTO ... SELECT)
If you first land your delete events into a "Bronze" table and then want to move them to the "Gold" Primary Key table, you can use a standard INSERT statement.
Requirement: This requires StarRocks v3.3.1 or newer.
Starting from v3.3.1, if you specify a column list that is a subset of the table's columns, StarRocks automatically performs a Partial Update instead of a full overwrite.
sql
-- Assuming bronze_deletes contains the IDs of records to be soft-deleted
INSERT INTO gold_table (record_id, is_deleted)
SELECT record_id, 1 FROM bronze_deletes;
Key configuration for this to work:
* Target Table: Must be a Primary Key table.
* Session Variable: Ensure enable_insert_partial_update is set to true (it is true by default in supported versions).
* Column List: You must explicitly list the columns in the INSERT INTO clause. If you omit the column list, StarRocks will assume a "Full Upsert" and fill missing columns with NULL or default values.
Summary of Versions
* Stream Load (HTTP): Supported for many versions (2.5+).
* INSERT INTO SELECT: Supported for partial updates since v3.3.1.
If you are on a version earlier than 3.3.1 and need to move data between tables for partial updates, you would typically use the UPDATE statement, but INSERT INTO ... SELECT is significantly more performant for batch updates.
References
• loading/InsertInto.md
• loading/StreamLoad.md
• sql-reference/System_variable.md (see enable_insert_partial_update)
References
• loading/InsertInto.md
• sql-reference/sql-statements/loading_unloading/INSERT.md
• release_notes/release-3.1.mdDerry Holt
08/19/2026, 10:52 AMRocky
08/19/2026, 10:52 AMINSERT INTO, but there is a key distinction depending on whether your "Materializer" is a scheduled script/task or a StarRocks Asynchronous Materialized View (MV).
1. If your "Materializer" is a Task (e.g., Airflow, Cron)
This is the most flexible approach for soft deletes. You can run an INSERT INTO ... SELECT that specifically targets only the primary key and the is_deleted flag.
* Version Requirement: StarRocks v3.3.1+.
* How it works: When you provide a column list that is a subset of the target Primary Key table's columns, StarRocks performs a Partial Update. It does not matter if the source is a UNION of multiple views; StarRocks simply takes the resulting rows and applies them.
Example Materializer Query:
sql
-- This query only updates 'is_deleted'.
-- Existing values in 'data_field_1', etc., are preserved.
INSERT INTO gold_dim_table (record_id, is_deleted)
SELECT record_id, 1
FROM unioned_ingest_view
WHERE event_type = 'DELETE';
2. If your "Materializer" is an Asynchronous MV
If your Gold table is actually defined as a CREATE MATERIALIZED VIEW, the behavior is different.
* MVs do not support Partial Updates: A Materialized View is designed to reflect the full state of its source query. When an MV refreshes, it re-calculates the rows and overwrites the existing data (usually at the partition level).
* The Problem: If your MV source query only selects record_id and is_deleted, the MV will treat the other columns as NULL or default values and overwrite your existing "Gold" data.
* The Solution: If you use an MV for the Gold layer, the is_deleted logic must be part of the main MV definition that includes all columns. The MV would then "materialize" the soft-delete status alongside the data.
Which should you use?
* Use INSERT INTO ... SELECT (Partial Update): If your ingest stream only contains the "Delete Event" (the ID) and you want to flip a switch on a record that already exists in Gold without re-processing all its original fields. This is highly efficient for "late-arriving" deletes.
* Use Asynchronous MV: If your Gold table is intended to be a fully managed, declarative representation of your raw data. In this case, your unioned_ingest_view should probably use a JOIN or a Window Function (like row_number()) to determine the final state (active vs. deleted) for every record, and the MV will materialise that entire state.
Recommendation for your setup:
Given you are using a UNION of views to "materialize" into Gold, you are likely treating Gold as a persistent table. In this case, manually triggered INSERT INTO ... SELECT (or using a Task object in StarRocks 3.4+) is the best way to utilize the Partial Update feature to mark records as soft-deleted.
Pro-tip: Ensure the session variable enable_insert_partial_update is set to true (it is the default in v3.3.20+, v3.4.9+, and v3.5.8+).
References
• sql-reference/System_variable.md (Search for enable_insert_partial_update)
• loading/InsertInto.md
• sql-reference/sql-statements/loading_unloading/INSERT.md
References
• using_starrocks/async_mv/use_cases/create_partitioned_materialized_view.md
• using_starrocks/async_mv/use_cases/data_modeling_with_materialized_views.md