Mohan
08/19/2026, 9:50 AMRocky
08/19/2026, 9:50 AMsql
CREATE MATERIALIZED VIEW my_mv
REFRESH ASYNC EVERY (INTERVAL 1 DAY)
AS
SELECT ... -- your logic
* Partitioned Refresh: If your base table is large, MVs support partition-level incremental refresh. If only one day of data changes in the base table, StarRocks can refresh only that specific partition in the MV, saving significant resources.
* Query Rewrite: Even if most queries don't use this logic, the StarRocks optimizer can automatically rewrite queries to use the MV if it detects a match, which improves performance transparently.
* Zero Maintenance: You don't need to manually maintain the target table schema or the loading pipeline.
2. Task (Insert into Table)
This involves creating a standard table and using the SUBMIT TASK command to schedule an INSERT or INSERT OVERWRITE job.
* Manual Control: Use this only if you have highly custom ETL requirements that an MV cannot satisfy (e.g., complex multi-step procedural logic).
* No Intelligence: The system treats it as a standard table. There is no automatic query rewrite, and you must manually ensure the target table schema stays in sync with your logic.
* Manual Partitioning: You would have to manually write the logic to handle daily partition management (e.g., dropping/overwriting specific partitions).
Comparison Summary
Feature | Asynchronous MV | Task + Table
Ease of Use | High (Define once) | Low (Manual table + task)
Maintenance | Automatic | Manual
Incremental Updates | Supported (Partition-level) | Manual (Need custom SQL)
Query Rewrite | Yes | No
Transparency | High (Managed by DB) | Low (Managed by user)
Recommendation:
Use an Asynchronous Materialized View with a REFRESH ASYNC EVERY (INTERVAL 1 DAY) strategy. It reduces your operational overhead and allows StarRocks to optimize the refresh process (especially if you use PARTITION BY to match your base table's partitioning).
References
• sql-reference/sql-statements/loading_unloading/ETL/SUBMIT_TASK.md
• loading/InsertInto.md
• sql-reference/sql-statements/loading_unloading/pipe/CREATE_PIPE.mdMohan
08/19/2026, 10:28 AMRocky
08/19/2026, 10:29 AMORDER BY is likely Partition Pruning.
In StarRocks, when you partition a table by created_on, every query that doesn't filter by created_on must scan every single partition in the table. While your ORDER BY (activated_on) creates a sort key (prefix index) that helps within each partition, the system still has to open and check the metadata/indexes for every partition, which is where the bottleneck occurs.
Here are the best ways to make filters on the mutable activated_on column much faster:
1. Use the Primary Key Table Model (Recommended)
If your table uses the Primary Key model, you actually can partition by activated_on even if it is mutable.
* How it works: When you update activated_on for a row in a Primary Key table, StarRocks internally performs a "Delete + Insert" to move the row to the correct partition.
* Benefit: This allows for Partition Pruning. If you query WHERE activated_on = '2023-10-01', StarRocks will only look at the one relevant partition instead of scanning the entire table.
2. Move activated_on to the Leading Position of the Sort Key
Ensure that activated_on is the first column in your ORDER BY clause.
* Why: StarRocks builds a Prefix Index on the first 36 bytes of the sort key. If your sort key is (created_on, activated_on), a query on activated_on alone cannot use the prefix index.
* Action: Change your table definition to ORDER BY (activated_on, ...).
3. Add a Bloom Filter Index
For a DATE or DATETIME column with high cardinality (many distinct dates), a Bloom Filter index is very effective for equality (=) or IN queries.
* Action:
sql
ALTER TABLE your_table SET ("bloom_filter_columns" = "activated_on");
* Benefit: It allows the storage engine to skip data blocks (segments) that definitely do not contain the target date without reading them from disk.
4. Create an Asynchronous Materialized View (MV)
If you cannot change the base table schema, create an Asynchronous MV that is physically organized for these specific queries.
* Strategy: Create the MV and partition it by activated_on.
* Query Rewrite: StarRocks can automatically route queries directed at the base table to this MV.
* Note: Since there is no direct mapping between created_on and activated_on, the MV might require a full refresh or a defined schedule rather than a partition-aligned incremental refresh.
Summary Comparison
Optimization | Type | Best For | Effort
Primary Key Partitioning | Physical | Perfect pruning; handles updates | High (Re-create table)
Leading Sort Key | Indexing | Range and point queries | Medium (Re-create or Alter)
Bloom Filter | Indexing | Equality (=) and IN queries | Low (Alter table)
Materialized View | Secondary | Precomputing results | Medium (Create MV)
Rocky's Advice: If you are on a Primary Key model, re-partitioning by activated_on is the most "future-proof" fix. If you need a quick win without a migration, adding a Bloom Filter is the fastest path.
References
• table_design/table_types/primary_key_table.md
• knowledge/usage/best-practice.md
• table_design/indexes/Bloom_filter_index.md
References
• faq/Others.md
• loading/Load_to_Primary_Key_tables.md
• sql-reference/sql-statements/table_bucket_part_index/UPDATE.md
• table_design/table_types/primary_key_table.mdMohan
08/19/2026, 10:35 AMRocky
08/19/2026, 10:35 AMPRIMARY KEY definition.
* If your MySQL PK is id, but you want to partition by activated_on in StarRocks, your StarRocks PK must be (id, activated_on).
2. What happens when activated_on changes?
Because activated_on is part of the primary key, changing its value creates a new unique identifier from the database's perspective.
* Result: If a row has id=1 and activated_on='2023-10-01', and you "update" it to activated_on='2023-11-01', StarRocks sees this as a brand new record.
* Duplicates: You will indeed end up with two records in your table: one in the October partition and one in the November partition.
Why does this happen?
StarRocks' Primary Key model uses a "Delete+Insert" strategy. It can only "Delete" the old record if the incoming record has the exact same primary key. Since the date (partition key) has changed, the primary keys don't match, so the old record is never marked for deletion.
How to handle this?
If you must partition by a mutable column like activated_on while keeping id unique, you have a few options:
Option A: Manual Delete + Insert
When a record's activated_on date changes, your loading process must:
1. Explicitly Delete the old record (using the old id + activated_on combination).
2. Insert the new record.
This ensures only one version of the id exists across all partitions.
Option B: Partition by a Non-Mutable Column (Recommended)
If possible, continue to partition by created_on (which is immutable) and use other methods to speed up activated_on queries:
* Sort Key: Put activated_on first in your ORDER BY clause.
* Bloom Filter: Add a Bloom Filter index on activated_on.
* Secondary Index (Bitmap): If the cardinality isn't extremely high, a Bitmap index can also help.
Option C: Use a Materialized View for Queries
Keep your base table partitioned by created_on, but create an Asynchronous Materialized View that is partitioned by activated_on. StarRocks will handle the data movement within the MV, and your queries can run against the MV for high performance.
Summary
You are correct: if the partition key is part of the PK and it changes, StarRocks will add a new record rather than updating the old one. If you need id to be globally unique across partitions while activated_on changes, you must manage the deletion of the "old" primary key yourself.
References
• table_design/table_types/primary_key_table.md
• loading/Load_to_Primary_Key_tables.md
• sql-reference/sql-statements/table_bucket_part_index/CREATE_TABLE.md
References
• faq/operation_maintenance_faq.md
• table_design/data_distribution/expression_partitioning.md
• sql-reference/sql-statements/table_bucket_part_index/ALTER_TABLE.md
• loading/Load_to_Primary_Key_tables.mdMohan
08/19/2026, 1:06 PMRocky
08/19/2026, 1:07 PMBUCKETS keyword.
Since StarRocks v2.5.7, automatic bucketing is supported. Here is how you can apply it:
1. Set Table Default to Automatic
To change the table's distribution definition so that StarRocks automatically calculates the bucket count for new partitions, run:
sql
ALTER TABLE <table_name> DISTRIBUTED BY HASH(<columns>);
Note: If you run this command without specifying specific partitions, StarRocks will also re-bucket your existing partitions to match the newly calculated automatic count.
2. Handling Dynamic Partitioning
If your table uses Dynamic Partitioning (where partitions are created automatically based on time), the property dynamic_partition.buckets will override the table's general setting. To allow StarRocks to decide automatically for these partitions, you should update the property:
sql
ALTER TABLE <table_name> SET ("dynamic_partition.buckets" = "0");
Setting this value to 0 (in newer versions) or removing the fixed number allows the dynamic partition scheduler to fall back to the table's automatic distribution logic.
3. Adding New Partitions Manually
When manually adding a partition, simply omit the BUCKETS clause:
sql
ALTER TABLE <table_name> ADD PARTITION <partition_name>
VALUES LESS THAN ("2023-10-01")
DISTRIBUTED BY HASH(<columns>); -- No 'BUCKETS <num>' here
Key Considerations
* FE Configuration: Ensure the FE parameter enable_auto_tablet_distribution is set to true (it is true by default since v2.5.7).
* Data Volume: StarRocks calculates the bucket count based on your cluster size and the amount of data already in the table. If a single partition is expected to exceed 100 GB, it is still recommended to manually specify the bucket count for better performance.
* Version Check: If you are on a version earlier than 2.5.7, automatic bucketing is not supported, and a fixed number must be provided.
References
• table_design/data_distribution/Data_distribution.md
• administration/management/FE_configuration.md
• sql-reference/sql-statements/table_bucket_part_index/ALTER_TABLE.md
References
• table_design/data_distribution/Data_distribution.md
• administration/management/FE_configuration.md
• table_design/data_distribution/dynamic_partitioning.mdMohan
08/19/2026, 1:09 PMRocky
08/19/2026, 1:09 PMDEFAULT keyword for the DISTRIBUTED BY clause. This allows you to update the table's distribution metadata for future partitions without modifying existing ones.
To switch the table's default to "Automatic Bucketing":
sql
ALTER TABLE <table_name> DISTRIBUTED BY HASH(<columns>) DEFAULT;
*Note: By omitting the BUCKETS <num> part and using DEFAULT, you signal to StarRocks that all newly created partitions should use automatic bucketing, while existing partitions remain untouched.*
──────────
Option 2: For tables using Dynamic Partitioning
If your table uses the dynamic_partition properties (automatically creating partitions based on time), you can simply update the dynamic partition properties.
Update the property to 0 (or omit it if allowed in your version) to let the system take over:
sql
ALTER TABLE <table_name> SET ("dynamic_partition.buckets" = "0");
In many versions, setting this to 0 or removing the specific numeric value forces the dynamic partition scheduler to use the automatic bucketing logic for all future partitions it creates.
──────────
Option 3: Manual Partition Creation
If you manually add partitions using ALTER TABLE ... ADD PARTITION, you can transition to automatic bucketing immediately for that specific partition by simply omitting the BUCKETS keyword in your command:
sql
ALTER TABLE <table_name> ADD PARTITION p_new
VALUES LESS THAN ("2024-01-01")
DISTRIBUTED BY HASH(<columns>); -- Do NOT specify BUCKETS here
StarRocks will automatically calculate the optimal bucket count for p_new based on your cluster size and disk state, while your older partitions (p_old, etc.) will keep their original bucket counts.
Summary of Requirements
* FE Config: Ensure the FE configuration enable_auto_tablet_distribution is set to true (this is the default since v2.5.7).
* Constraint: If you use the standard ALTER TABLE <table_name> DISTRIBUTED BY HASH(...) without the DEFAULT keyword (on older versions), StarRocks will attempt to re-bucket the entire table, which involves a data rewrite. Always use the DEFAULT keyword or apply the change to specific new partitions if you wish to avoid this.
References
• sql-reference/sql-statements/table_bucket_part_index/ALTER_TABLE.md
• table_design/data_distribution/Data_distribution.md
• table_design/data_distribution/dynamic_partitioning.md
References
• table_design/data_distribution/dynamic_partitioning.mdMohan
08/20/2026, 6:32 AMRocky
08/20/2026, 6:33 AMactivated_on) is part of the PK:
* No Deduplication: Merging partitions will not deduplicate rows. A record with id=1, activated_on='2023-10-01' and a record with id=1, activated_on='2023-10-02' are considered different primary keys. Merging the partitions just moves them into the same physical folder; it does not merge the records themselves.
* If you want to reduce data size by removing "old" versions of an ID when a new one appears, you would need to change your table design (as discussed in our previous conversation).
How to do it:
You can use the expression partition merge syntax (available in StarRocks 3.4+):
sql
ALTER TABLE your_table
PARTITION BY date_trunc('month', activated_on)
WHERE activated_on BETWEEN '2023-10-01' AND '2023-10-31';
Summary: You will see a reduction in "physical" size due to better compression and fewer files, but the number of "logical" rows will remain the same.
References
• table_design/data_distribution/expression_partitioning.md
• administration/management/compaction.md
• best_practices/partitioning.md
• knowledge/admin_and_operation/shared_data_compaction.md
References
• knowledge/admin_and_operation/shared_data_compaction.md
• administration/management/compaction.md
• best_practices/partitioning.md
• best_practices/query_tuning/schema_tuning.md
• faq/shared_data_faq.mdMohan
08/20/2026, 6:36 AMRocky
08/20/2026, 6:36 AMtablet_max_versions (BE Config):
* Default: 1000
* Description: This is the maximum number of rowsets (versions) a tablet can have. If a tablet reaches this limit, new write requests (including INSERT, STREAM LOAD, etc.) will fail with a "too many versions" error.
* How to change: Modify be.conf and restart the BE, or use the HTTP API for a hot update:
bash
curl -X POST http://<be_ip>:<be_http_port>/api/update_config?tablet_max_versions=2000
2. Primary Key Table Specifics
If you are using the Primary Key model, there is a specific limit for "pending" versions (data that is committed but not yet applied to the primary key index).
* tablet_max_pending_versions (BE Config):
* Default: 1000
* Description: Controls how many versions can wait in the "apply" queue for Primary Key tablets. If this is exceeded, writes will fail.
3. Controlling Versions via Compaction
You don't typically "set" a number of versions to keep (like a history); rather, StarRocks Compaction automatically merges small versions into larger ones to keep the count low and performance high.
If you find version counts are too high, you can tune the compaction speed:
* cumulative_compaction_num_threads_per_disk: Increase this to allow more concurrent compaction tasks.
* base_compaction_num_threads_per_disk: Increase this for merging larger files into the base version.
4. How to Monitor Version Count
To see how many versions your tablets currently have, you can use the following commands:
* View by Partition:
sql
SHOW PROC '/dbs/<db_name>/<table_name>/partitions';
Look at the VisibleVersion column. Note that the actual number of files (rowsets) might be higher than the version number if compaction is lagging.
* View Specific Tablet Details:
sql
SHOW TABLET <tablet_id>;
This will provide a URL to the BE's debug page, where you can see the exact number of rowsets and their versions.
Summary Recommendation
* Do not set tablet_max_versions too low (e.g., < 100), as this will cause frequent ingestion failures during high-concurrency loads.
* If you see "too many versions" errors: Usually, the solution is not to increase the limit, but to slow down the frequency of small loads (group your data into larger batches) or increase compaction resources.
References
• administration/management/BE_configuration.md
• administration/management/compaction.md
• knowledge/admin_and_operation/shared_data_compaction.md
References
• administration/management/BE_configuration.md
• knowledge/admin_and_operation/shared_data_compaction.md
• administration/management/compaction.md
• faq/Deploy_faq.md
• using_starrocks/async_mv/feature-support-asynchronous-materialized-views.mdRocky
08/20/2026, 6:36 AMMohan
08/20/2026, 7:31 AMRocky
08/20/2026, 7:31 AMALTER TABLE ... PARTITION BY command to merge partitions (e.g., from days to months), StarRocks handles it with specific concurrency rules:
1. Ingestion Priority (Loading vs. Alter)
StarRocks gives priority to load jobs. If an ingestion task (like STREAM LOAD or INSERT INTO) is active and trying to write data to the partitions involved in the merge, the ALTER TABLE task will fail with a conflict error rather than blocking the ingestion.
2. DML Restrictions
The official documentation states that parallel execution of merging and DML/Schema Change operations is not supported.
* DML includes INSERT, DELETE, and UPDATE.
* If you attempt to run a merge on a table while heavy DML is occurring on the same partitions, you will likely encounter errors.
3. Avoiding Conflicts (Best Practices)
To merge partitions without issues during active ingestion:
* Merge Historical Data Only: Only merge partitions for time ranges where you are no longer actively loading data. For example, if today is 2024-04-05, it is safe to merge daily partitions for 2024-03 into a monthly partition, as long as no late-arriving data is being written to March.
* Check `SHOW ALTER TABLE COLUMN`: You can monitor the progress of the merge. Since merging is essentially a "Schema Change" type operation, it creates new tablets and moves data.
* Timing: Schedule the merge command during low-traffic windows if your ingestion covers a wide range of historical dates (e.g., constant updates to old records).
Summary of What Happens:
* If you merge "Old" partitions while loading "New" data: No issue. The merge and ingestion are touching different partitions/tablets.
* If you merge "Old" partitions while loading "Old" data: The ALTER TABLE merge task will likely fail to ensure data integrity for the ingestion job.
References
• table_design/data_distribution/expression_partitioning.md
• faq/Others.md
• sql-reference/sql-statements/table_bucket_part_index/ALTER_TABLE.md
References
• table_design/data_distribution/expression_partitioning.md
• faq/Others.mdMohan
08/20/2026, 9:52 AMRocky
08/20/2026, 9:52 AMWHERE date = '2022-05-01'), a monthly partition means StarRocks has to open a 300GB partition instead of an 8GB one.
_ _However*, because StarRocks uses Columnar Storage and Zone Maps (min/max indexes on every data block), it can still skip most of the data inside the monthly partition very efficiently. The performance hit is usually negligible for historical data.
Recommendation
* Merge partitions for data older than 6 months.
* Target Tablet Size: Aim for 10GB per tablet for these historical monthly partitions.
* Bucketing: If your current table has a fixed bucket count (e.g., 10), and you use StarRocks 3.4+, you can use the expression partitioning feature to merge and potentially adjust the distribution if needed (though typically you'd keep the bucket count consistent for simplicity unless it's creating massive tablets).
How to execute (Example for 3.4+):
sql
ALTER TABLE your_pk_table
PARTITION BY date_trunc('month', activated_on)
WHERE activated_on < '2024-01-01';
Summary: Do it. The reduction in metadata overhead for 7,000+ tablets will significantly improve your cluster's overall health, and the storage savings are a nice bonus.
References
• best_practices/partitioning.md
• table_design/data_distribution/Data_distribution.md
• best_practices/primarykey_table.md
• table_design/data_distribution/expression_partitioning.md
References
• table_design/table_types/primary_key_table.md
• best_practices/primarykey_table.mdMohan
08/20/2026, 10:54 AMRocky
08/20/2026, 10:55 AMALTER TABLE ... PARTITION BY date_trunc('month', ...) command doesn't just move data; it redefines the partitioning rule for that specific time range in the table's metadata.
2. Routing: When a record with an old date (e.g., 2022-05-15) is ingested, the StarRocks Frontend (FE) checks the existing partition layout. Since the daily partitions for 2022-05 no longer exist and have been replaced by a single monthly partition, the FE routes the data to that monthly partition.
3. No New Daily Partitions: StarRocks will not automatically recreate a daily partition for that old record. It strictly follows the partition boundaries currently defined in the system.
4. Automatic Creation (for future data): New data for future dates will continue to use the table's default granularity (daily) until you manually run the merge command for those newer ranges.
Example Scenario:
* Initial State: Table is partitioned by day. You have daily partitions for Jan 2023.
* Action: You run ALTER TABLE ... PARTITION BY date_trunc('month', date_col) WHERE date_col BETWEEN '2023-01-01' AND '2023-01-31'.
* Result: All 31 daily partitions are gone, replaced by one partition named something like p202301.
* Update: An update arrives for 2023-01-15.
* Outcome: The record is updated inside the p202301 monthly partition. No daily partition is created.
Why this is good for Primary Key tables:
For a Primary Key table, this is ideal because the "Upsert" logic happens at the tablet level. By merging into monthly partitions, you reduce the number of tablets that the system needs to track for historical updates, which keeps the Primary Key index metadata leaner and more efficient.
References
• table_design/data_distribution/expression_partitioning.md
• best_practices/partitioning.md
References
• table_design/data_distribution/expression_partitioning.md
• best_practices/partitioning.md
References
• table_design/data_distribution/expression_partitioning.md