<@U0A71G31CDV> I'd like to setup a regular backup ...
# questions-and-troubleshooting
g
@Rocky I'd like to setup a regular backup of my starrocks clusters. I have a few of them, in Shared-nothing deployment, in a K8S cluster (so with data disks attached). From the documentation, I can see that I won't be able to use "snapshots" since they are shared-data only. What would be the best way to perform regular backups for the cluster?
r
For a Shared-nothing deployment (even on Kubernetes), the standard and most reliable way to perform regular backups is by using the built-in
BACKUP
and
RESTORE
SQL commands. Contrary to your finding, these commands are specifically designed for Shared-nothing clusters. The "Cluster Snapshot" feature you saw in the docs is a newer, separate mechanism designed specifically for the Shared-data architecture (v3.5+). Here is the best practice for setting up regular backups in your environment: 1. Create a Remote Repository First, you must define a remote storage location (S3, MinIO, GCS, or HDFS) where StarRocks will upload the data snapshots. Since you are in K8S, using an S3-compatible object store (like MinIO or AWS S3) is recommended.
Copy code
sql
CREATE REPOSITORY `s3_backup_repo`
WITH BROKER 
ON LOCATION "<s3a://my-backup-bucket/starrocks_backups>"
PROPERTIES (
    "aws.s3.access_key" = "your_access_key",
    "aws.s3.secret_key" = "your_secret_key",
    "aws.s3.region" = "us-east-1",
    "aws.s3.endpoint" = "<https://s3.amazonaws.com>"
);
Note: Use
s3a://
protocol for S3/MinIO/GCS.
2. Perform the Backup You can back up an entire database or specific tables. The
BACKUP
command is asynchronous.
Copy code
sql
-- Backup an entire database
BACKUP DATABASE my_db 
SNAPSHOT snapshot_20231027 
TO s3_backup_repo;

-- Or backup specific tables
BACKUP DATABASE my_db 
SNAPSHOT snapshot_tables_20231027 
TO s3_backup_repo 
ON (table1, table2);
3. Automate via Kubernetes CronJob Since StarRocks does not have a built-in backup scheduler, you should use a Kubernetes CronJob. This job runs a container with a MySQL client that connects to your StarRocks FE and executes the backup command. Example CronJob Logic: 1. Generate a unique snapshot name (e.g.,
backup_$(date +%Y%m%d)
). 2. Connect to the FE and run the
BACKUP
command. 3. (Optional) Run a script to check
SHOW BACKUP
until the state is
FINISHED
. Simple CronJob Snippet:
Copy code
yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: starrocks-backup
spec:
  schedule: "0 2 * * *" # Every day at 2 AM
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: backup-client
            image: mysql:8.0
            command:
            - /bin/sh
            - -c
            - |
              SNAPSHOT_NAME="backup_$(date +%Y%m%d)"
              mysql -h starrocks-fe -P 9030 -u root -e "BACKUP DATABASE my_db SNAPSHOT $SNAPSHOT_NAME TO s3_backup_repo;"
          restartPolicy: OnFailure
4. Key Considerations * Consistency: The
BACKUP
command provides an application-level consistent snapshot across all BE nodes. Avoid using disk-level (EBS/PVC) snapshots, as they are difficult to coordinate across a distributed cluster and may lead to data corruption upon restore. * Incremental Backups: StarRocks native
BACKUP
is a full backup. If your tables are partitioned by time, you can simulate incremental backups by only backing up the latest partitions (e.g.,
ON (table1 PARTITION (p20231027))
). * Privileges: Ensure the user running the backup has the
REPOSITORY
and
EXPORT
privileges. * Monitoring: Use
SHOW BACKUP FROM my_db;
to check the progress and status of your jobs. For more complex requirements (like automated rotation or metadata tracking), there is a community-supported tool called
starrocks-backup-and-restore
available on GitHub/PyPI that wraps these SQL commands into a CLI. Referencesadministration/management/Backup_and_restore.mdquick_start/helm.md
g
Thanks @Rocky, do you know if Azure Blobstore is supported for these REPOSITORIES?
r
Yes, Azure Blob Storage is supported for StarRocks
BACKUP
and
RESTORE
repositories (from version 3.0 onwards). While the primary
CREATE REPOSITORY
documentation often emphasizes S3 and HDFS, the Azure integration is fully supported. For Shared-nothing clusters, StarRocks typically uses the Hadoop-compatible protocols (
wasbs://
for Blob Storage or
abfss://
for ADLS Gen2) to communicate with Azure. Example: Create a Repository on Azure Blob Storage You can create the repository using the following syntax. Note that the
WITH BROKER
keyword is required by the syntax for cloud storage repositories, even if you are not using a separate StarRocks Broker process.
Copy code
sql
CREATE REPOSITORY `azure_backup_repo`
WITH BROKER 
ON LOCATION "wasbs://<container_name>@<storage_account_name>.<http://blob.core.windows.net/backups|blob.core.windows.net/backups>"
PROPERTIES (
    "azure.blob.storage_account" = "your_storage_account_name",
    "azure.blob.shared_key" = "your_storage_account_shared_key",
    "azure.blob.endpoint" = "<https://your_storage_account_name.blob.core.windows.net>"
);
Key Parameters for Azure * Protocol: Use
wasbs://
for Azure Blob Storage (HTTPS) or
abfss://
for Azure Data Lake Storage Gen2 (HTTPS). * Authentication: * For Shared Key: Use
azure.blob.storage_account
and
azure.blob.shared_key
. * For SAS Token: Use
azure.blob.storage_account
,
azure.blob.container
, and
azure.blob.sas_token
. * Endpoint: The
azure.blob.endpoint
is generally required to point the request to the correct Azure region/account (e.g.,
https://<account>.<http://blob.core.windows.net|blob.core.windows.net>
). Important Notes for K8S Deployments * Network Access: Ensure your Kubernetes BE (Backend) nodes have outbound network access to the Azure Storage endpoint. * Hierarchical Namespace: If you are using ADLS Gen2, the StarRocks documentation notes that for certain backup/restore operations, the hierarchical namespace should ideally be disabled on the storage account for best compatibility with the
wasb
driver, though
abfs
is supported for newer versions. * Check Status: After creating the repository, you can verify it exists with
SHOW REPOSITORIES;
. If you encounter errors during the first backup, check the BE log (
<http://be.INFO|be.INFO>
) for detailed credential or connection errors from the underlying Hadoop Azure connector. For the actual backup automation, you would still use the Kubernetes CronJob approach mentioned previously, simply referencing this Azure-backed repository. Referencessql-reference/sql-statements/backup_restore/CREATE_REPOSITORY.mdsql-reference/sql-statements/cluster-management/storage_volume/CREATE_STORAGE_VOLUME.mddata_source/catalog/unified_catalog.mdsql-reference/sql-statements/loading_unloading/BROKER_LOAD.md
In StarRocks, using a partial update (specifying every column in the header) is more expensive than a standard full row UPSERT (Insert/Stream Load without the partial update flag). If you have the data for all columns, you should always use a standard load rather than forcing a partial update. Here is why: 1. Internal Mechanism Difference * Standard UPSERT (Full Row): StarRocks Primary Key tables use a delete-and-insert mechanism. When you perform a standard load, StarRocks uses the Primary Key index to find the old row's location, marks it as deleted, and writes the new row data. This is a write-optimized path. * Partial Update (Row Mode): When you set
partial_update=true
, StarRocks enters a read-on-write flow. Even if you provide all columns in your CSV/JSON, the engine’s internal state machine is configured to "merge" data. It must verify the existence of the row and potentially perform additional checks or row reconstructions that the standard insert path skips. 2. Performance Overhead Specifying all columns in a partial update header introduces unnecessary costs: * CPU/Memory: The partial update logic invokes a specialized merge process in the Backend (BE). Forcing this logic for a full row adds computation cycles that the native "full insert" path doesn't require. * Optimization Bypass: StarRocks has highly optimized paths for standard loading (like vectorized writes). Partial updates, especially in older versions or specific configurations, may not hit the same level of optimization as a standard full-row write. 3. Summary of Best Practices Scenario | Recommended Method | Performance Note You have data for every column | Standard
STREAM LOAD
or
INSERT
| Fastest. Uses the native PK delete-and-insert path. You only have 1-2 columns out of many |
STREAM LOAD
with
partial_update=true
| Efficient because it avoids sending/processing massive amounts of unchanged data. Batch updating 10% of columns across 1M+ rows |
partial_update_mode=column
| Best for mass updates. It only writes to the specific column files being changed. The Verdict: If you have the data for the whole row, do not use the
partial_update
flag. It adds "under the hood" overhead for a merge operation that isn't actually necessary. Referencesfaq/Sql_faq.mdsql-reference/sql-statements/table_bucket_part_index/UPDATE.mdloading/Load_to_Primary_Key_tables.mdfaq/Others.mdknowledge/usage/best-practice.mdloading/Spark-connector-starrocks.md
Yes, StarRocks does default omitted columns to their specified default values, but the exact behavior depends on whether you are doing a standard load or a "Partial Update" on a Primary Key table. 1. Standard
INSERT
(SQL)
When using the standard
INSERT INTO
statement, if you omit a column from the column list, StarRocks will automatically use the
DEFAULT
value defined in the schema.
Copy code
sql
-- Schema: age INT DEFAULT '18'
INSERT INTO users (name) VALUES ('Rocky'); 
-- Result: name='Rocky', age=18
2. Standard
STREAM LOAD
/
ROUTINE LOAD
For standard loading (where you are replacing or inserting entire rows): * Columns omitted from the
COLUMNS
header:
If you don't list a column in the
columns
property of your load command, StarRocks fills that column with its default value defined in the
CREATE TABLE
statement. * Missing fields in data: If a field is present in your column mapping but missing in the actual data row (e.g., a CSV line has fewer columns than specified), StarRocks will attempt to fill it with
NULL
. If the column is
NOT NULL
and has a
DEFAULT
, it will use the default. 3. Primary Key Tables (The "Upsert" exception) If you are using a Primary Key table, the behavior depends on whether the row already exists: * If the row is NEW (Insert): Omitted columns will be populated with their default values (e.g.,
0
,
NULL
, or your custom string). * If the row EXISTS (Update): * Standard Load: If you perform a standard stream load (no partial update flag), the omitted columns will be overwritten with their default values. * Partial Update (
partial_update: true
):
Omitted columns will retain their existing values in the database. They are not reset to defaults. 4. Special Case:
REPLACE_IF_NOT_NULL
(Aggregate Tables)
In Aggregate Key tables, you can define a column with the
REPLACE_IF_NOT_NULL
aggregation type. * If the incoming data for that column is
NULL
(or omitted during certain load types), StarRocks will keep the original value already stored in the cluster instead of overwriting it with
NULL
or a default. Summary Table Operation Type | Omitted Column Behavior SQL
INSERT
| Uses
DEFAULT
value. Standard Stream Load | Uses
DEFAULT
value (overwrites existing data if PK matches). PK Partial Update | Retains existing value (does not use default). Auto-increment | Generates a new ID if omitted. Important Note: If a column is defined as
NOT NULL
and has no
DEFAULT
value, omitting it during a load will cause the row to be filtered out as a "quality error"quality fail (unless it is a Partial Update on-conflict update scenario). Referencessql-reference/sql-statements/table_bucket_part_index/CREATE_TABLE.mdsql-reference/sql-statements/loading_unloading/INSERT.mdloading/InsertInto.mdsql-reference/sql-statements/table_bucket_part_index/auto_increment.md
Yes, within a single Stream Load transaction, StarRocks follows a "last row wins" behavior for rows with the same Primary Key. If your data source (e.g., a CSV or JSON file) contains multiple objects with the same Primary Key, they are processed in the order they appear in the file. The final state of the row in the database will match the last occurrence of that key in the load batch. Key Behaviors to Note: 1. Sequential Processing: Inside a single load, StarRocks applies updates sequentially. If your file has: * Row 1:
id=101, status='A'
* Row 100:
id=101, status='B'
* Result: The final value in the table will be
status='B'
. 2. Partial Updates: If you are using
partial_update: true
and have multiple rows for the same PK in one load: * The rows will be merged one after another onto the base row. * This is useful for "accumulating" updates in a single batch, where each subsequent row in the file updates specific fields of the same PK. 3. Handling "Out-of-Order" Data (Conditional Update): If you cannot guarantee that the "last" row in your file is the "newest" (e.g., due to upstream system offsets), you should use the Conditional Update feature. By specifying a version or timestamp column (e.g.,
-H "merge_condition: version_col"
), StarRocks will only apply an update if the incoming row's version is greater than or equal to the version currently stored. 4. Performance Tip: While "last row wins" works, having a very large number of duplicate keys within a single load batch can slightly increase processing overhead (as the index is updated multiple times for that key). If possible, deduplicating your data before the Stream Load is a best practice, though not required for correctness. Summary: For a single stream load, the order of rows in the input data determines the final state, effectively making the last write the "write" (the last row in the file) the winner. Referencesloading/Load_to_Primary_Key_tables.mdfaq/Sql_faq.mdloading/StreamLoad.mdfaq/Others.mdsql-reference/sql-statements/table_bucket_part_index/UPDATE.mdloading/Flink-connector-starrocks.mdloading/Loading_intro.mdadministration/Query_management.mdsql-reference/sql-statements/loading_unloading/INSERT.mdunloading/Export_queries_to_files.mdsql-reference/sql-statements/data-definition/ALTER_TABLE.mdloading/InsertInto.mdsql-reference/sql-statements/data-manipulation/DELETE.mdloading/RoutineLoad.mdloading/Load_to_Aggregate_tables.mdintroduction/StarRocks_intro.mdloading/Spark-connector-starrocks.mdloading/ETL_in_StarRocks.mdloading/HDFS_load.md
sql-reference/sql-statements/table_bucket_part_index/auto_increment.mdsql-reference/sql-statements/cluster-management/storage_volume/CREATE_STORAGE_VOLUME.mdsql-reference/sql-statements/data-definition/CREATE_VIEW.mdsql-reference/sql-statements/loading_unloading/SUBMIT_TASK.mdsql-reference/sql-statements/loading_unloading/BROKER_LOAD.mdsql-reference/sql-statements/loading_unloading/EXPORT.mdadministration/Management_commands.mdadministration/configuration/FE_configuration_items.mdloading/SparkLoad.mdusing_starrocks/Primary_key_table.mdadministration/Replica_Management.mdadministration/Cluster_administration.mdloading/Data_compression_for_loading.mdusing_starrocks/Async_MV.mdtable_design/Sort_key.mdloading/Loading_Troubleshooting.mdfaq/Environment_FAQ.mdusing_starrocks/query_acceleration_with_auto_refresh_mv/Sync_MV.mdtable_design/data_types/Array.mdloading/Stream_Load_transaction_interface.mdloading/BrokerLoad.mdunloading/Unload_to_S3.mdsql-reference/sql-statements/loading_unloading/PAUSE_ROUTINE_LOAD.mdsql-reference/sql-statements/data-definition/TRUNCATE_TABLE.mdloading/Json_loading.mdunloading/Unload_to_HDFS.mdadministration/Resource_group.mdsql-reference/sql-statements/loading_unloading/CANCEL_LOAD.mdsql-reference/sql-statements/loading_unloading/CREATE_ROUTINE_LOAD.mdsql-reference/sql-statements/account-management/SET_PASSWORD.mdsql-reference/sql-statements/backup_restore/RESTORE.mdloading/Mysql_load.md
using_starrocks/Implicit_cast.mdsql-reference/sql-statements/data-definition/CREATE_TABLE_LIKE.mdsql-reference/sql-statements/backup_restore/BACKUP.mdsql-reference/sql-statements/backup_restore/CREATE_REPOSITORY.mdloading/S3_load.mdloading/Kafka-connector-starrocks.mdsql-reference/sql-statements/account-management/SET_ROLE.mdloading/Kettle-connector-starrocks.mdadministration/Monitor_and_Alert.mdadministration/configuration/BE_configuration_items.mddata_source/Catalog_overview.mdusing_starrocks/External_table.mdloading/Data_Transformation.mdsql-reference/sql-statements/data-definition/DROP_TABLE.mdsql-reference/sql-statements/account-management/CREATE_USER.mdloading/S3_Routine_Load.mdsql-reference/sql-statements/loading_unloading/RESUME_ROUTINE_LOAD.mdloading/Load_to_Duplicate_Key_tables.mdsql-reference/sql-statements/loading_unloading/ALTER_ROUTINE_LOAD.mdsql-reference/sql-statements/loading_unloading/STOP_ROUTINE_LOAD.mdadministration/Statistics.mdloading/Stream_Load_through_Apache_APISIX.mdsql-reference/sql-statements/loading_unloading/UPDATE_TASK.mdtable_design/Table_types.mdadministration/System_variable.mdusing_starrocks/Materialized_view.mdtable_design/Data_model.mdtable_design/Indexes.mdtable_design/data_distribution/Data_distribution.mddata_source/catalog/unified_catalog.mdloading/loading_from_aws_s3.mdtable_design/Partitioning.mdloading/Load_from_Iceberg.mdusing_starrocks/Colocate_join.md
sql-reference/sql-statements/data-definition/CREATE_INDEX.mdsql-reference/sql-statements/data-definition/DROP_INDEX.mdadministration/Configuration.mdloading/Best_practice_for_Routine_Load.mdloading/Stream_load_through_Node.js.mdloading/Stream_load_through_Python.mdfaq/Loading_faq.mdsql-reference/sql-statements/loading_unloading/DROP_TASK.mdsql-reference/sql-statements/account-management/GRANT.mdsql-reference/sql-statements/account-management/REVOKE.mdsql-reference/sql-statements/data-definition/CREATE_DATABASE.mdsql-reference/sql-statements/data-definition/DROP_DATABASE.mdloading/Duduplicate_with_primary_key.mdloading/loading_from_azure_blob_storage.mdloading/loading_from_google_cloud_storage.mdsql-reference/sql-statements/loading_unloading/LOAD.mdusing_starrocks/Table_design.mdusing_starrocks/Data_loading.mddata_source/catalog/hive_catalog.mdsql-reference/sql-statements/data-definition/ALTER_DATABASE.mdsql-reference/sql-statements/account-management/CREATE_ROLE.mdsql-reference/sql-statements/account-management/DROP_USER.mdsql-reference/sql-statements/account-management/DROP_ROLE.mdsql-reference/sql-statements/data-query/SELECT.mdtable_design/data_types/Map.mdtable_design/data_types/Struct.mddata_source/catalog/iceberg_catalog.mddata_source/catalog/hudi_catalog.mddata_source/catalog/deltalake_catalog.mddata_source/catalog/paimon_catalog.mddata_source/catalog/jdbc_catalog.mddata_source/catalog/elasticsearch_catalog.md
loading/Load_from_Hudi.mdsql-reference/sql-statements/data-definition/ALTER_VIEW.mdsql-reference/sql-statements/data-definition/DROP_VIEW.mdusing_starrocks/Views.mdadministration/User_privilege.mdsql-reference/sql-statements/data-manipulation/TRUNCATE_PARTITION.mdintroduction/Overview.mdusing_starrocks/Query_acceleration_with_auto_refresh_mv/Query_acceleration_with_auto_refresh_mv.mdusing_starrocks/Continuous_data_loading.mdtable_design/data_types/Data_types.mdusing_starrocks/Cost_based_optimizer.mdusing_starrocks/Query_analysis.mdusing_starrocks/Query_external_data.mdusing_starrocks/data_security/Data_masking.mdadministration/Data_compression.mdadministration/Backup_and_restore.mdsql-reference/sql-statements/loading_unloading/SHOW_ROUTINE_LOAD.mdsql-reference/sql-statements/data-query/EXPLAIN.mdintroduction/Features.mdusing_starrocks/query_acceleration_with_auto_refresh_mv/Optimize_asynchronous_materialized_views.mdusing_starrocks/query_acceleration_with_auto_refresh_mv/Automated_Materialized_View_Rewrite.mdsql-reference/sql-statements/data-definition/CREATE_RESOURCE.mdsql-reference/sql-statements/data-definition/DROP_RESOURCE.mdsql-reference/sql-statements/data-definition/ALTER_RESOURCE.mdsql-reference/sql-statements/loading_unloading/SHOW_LOAD.mdsql-reference/sql-statements/loading_unloading/SHOW_ROUTINE_LOAD_TASK.mdsql-reference/sql-statements/data-query/SHOW_EXPORT.mdsql-reference/sql-statements/data-query/CANCEL_EXPORT.mdsql-reference/sql-statements/data-query/SHOW_DATA.md
sql-reference/sql-statements/data-query/SHOW_DATABASES.mdsql-reference/sql-statements/data-query/SHOW_TABLES.mdsql-reference/sql-statements/data-query/SHOW_CREATE_TABLE.mdsql-reference/sql-statements/data-query/DESCRIBE.mdsql-reference/sql-statements/cluster-management/storage_volume/ALTER_STORAGE_VOLUME.mdsql-reference/sql-statements/cluster-management/storage_volume/DROP_STORAGE_VOLUME.mdsql-reference/sql-statements/cluster-management/storage_volume/SET_DEFAULT_STORAGE_VOLUME.mdsql-reference/sql-statements/cluster-management/storage_volume/DESC_STORAGE_VOLUME.mdsql-reference/sql-statements/cluster-management/storage_volume/SHOW_STORAGE_VOLUMES.mdloading/Cloud_Configuration.mdloading/Authenticate_to_AWS_S3.mdloading/Authenticate_to_Google_GCS.mdloading/Authenticate_to_Azure_Storage.mdusing_starrocks/Internal_table.mdintroduction/Core_concepts.mdsql-reference/sql-statements/backup_restore/SHOW_BACKUP.mdsql-reference/sql-statements/backup_restore/SHOW_RESTORE.mdsql-reference/sql-statements/backup_restore/SHOW_SNAPSHOT.mdsql-reference/sql-statements/backup_restore/SHOW_REPOSITORIES.mdsql-reference/sql-statements/backup_restore/DROP_REPOSITORY.mdintroduction/Workflow.mdknowledge/usage/primary-key-partial-update.mdloading/Flink-connector-starrocks-faq.mdknowledge/usage/starrocks-stream-load-best-practice.mdusing_starrocks/query_acceleration_with_auto_refresh_mv/Show_materialized_views.mdusing_starrocks/query_acceleration_with_auto_refresh_mv/Maintain_materialized_views.md
using_starrocks/query_acceleration_with_auto_refresh_mv/Query_acceleration_with_asynchronous_materialized_views.mdsql-reference/sql-statements/data-definition/CREATE_MATERIALIZED_VIEW.mdsql-reference/sql-statements/data-definition/ALTER_MATERIALIZED_VIEW.mdsql-reference/sql-statements/data-definition/DROP_MATERIALIZED_VIEW.mdsql-reference/sql-statements/data-definition/REFRESH_MATERIALIZED_VIEW.mdsql-reference/sql-statements/data-definition/CANCEL_REFRESH_MATERIALIZED_VIEW.mdusing_starrocks/Query_External_Data/Query_Hive.mdusing_starrocks/Query_External_Data/Query_Iceberg.mdusing_starrocks/Query_External_Data/Query_Hudi.mdusing_starrocks/Query_External_Data/Query_Delta_Lake.mdusing_starrocks/Query_External_Data/Query_Paimon.mdusing_starrocks/Query_External_Data/Query_JDBC.mdusing_starrocks/Query_External_Data/Query_Elasticsearch.mdusing_starrocks/Query_External_Data/External_catalog.mdsql-reference/sql-statements/data-definition/CREATE_CATALOG.mdsql-reference/sql-statements/data-definition/DROP_CATALOG.mdsql-reference/sql-statements/data-definition/SHOW_CATALOGS.mdsql-reference/sql-statements/data-definition/SET_CATALOG.mdsql-reference/sql-statements/data-definition/SHOW_CREATE_CATALOG.mdsql-reference/sql-statements/data-definition/ALTER_CATALOG.mdsql-reference/sql-statements/data-query/SHOW_CREATE_MATERIALIZED_VIEW.mdsql-reference/sql-statements/loading_unloading/SHOW_TASKS.mdsql-reference/sql-statements/loading_unloading/SHOW_TASK_RUNS.mdsql-reference/sql-statements/loading_unloading/CANCEL_TASK_RUN.md
using_starrocks/query_acceleration_with_auto_refresh_mv/Data_freshness.mdusing_starrocks/query_acceleration_with_auto_refresh_mv/MV_flattening.mdloading/Load_from_Iceberg_Catalog.mdloading/Load_from_Paimon.mdloading/Load_from_JDBC.mdloading/Load_from_Elasticsearch.mdloading/Loading_Data_from_External_Catalogs.mdintroduction/Log_Management.mdintroduction/Security.mdintroduction/Best_Practices.mdintroduction/FAQ.mdadministration/Maintenance.mdadministration/Security.mdadministration/Resource_Management.mdsql-reference/sql-statements/cluster-management/SHOW_COMPUTE_NODES.mdsql-reference/sql-statements/cluster-management/SHOW_BACKENDS.mdsql-reference/sql-statements/cluster-management/SHOW_FRONTENDS.mdsql-reference/sql-statements/cluster-management/SHOW_BROKER.mdsql-reference/sql-statements/cluster-management/SHOW_PROCESSLIST.mdsql-reference/sql-statements/cluster-management/ADMIN_SHOW_CONFIG.mdsql-reference/sql-statements/cluster-management/ADMIN_SET_CONFIG.mdsql-reference/sql-statements/cluster-management/SHOW_VARIABLES.mdsql-reference/sql-statements/cluster-management/SET_VARIABLE.mdsql-reference/sql-statements/cluster-management/SHOW_STATUS.mdsql-reference/sql-statements/cluster-management/SHOW_RESOURCES.mdsql-reference/sql-statements/cluster-management/SHOW_RESOURCE_GROUPS.mdsql-reference/sql-statements/cluster-management/CREATE_RESOURCE_GROUP.mdsql-reference/sql-statements/cluster-management/ALTER_RESOURCE_GROUP.md
sql-reference/sql-statements/cluster-management/DROP_RESOURCE_GROUP.mdsql-reference/sql-statements/cluster-management/SHOW_PLUGINS.mdsql-reference/sql-statements/cluster-management/INSTALL_PLUGIN.mdsql-reference/sql-statements/cluster-management/UNINSTALL_PLUGIN.mdsql-reference/sql-statements/cluster-management/SHOW_PARTITIONS.mdsql-reference/sql-statements/cluster-management/SHOW_DYNAMIC_PARTITION_TABLES.mdsql-reference/sql-statements/cluster-management/SHOW_TABLE_STATUS.mdsql-reference/sql-statements/cluster-management/SHOW_INDEX.mdsql-reference/sql-statements/cluster-management/SHOW_COLUMN.mdsql-reference/sql-statements/cluster-management/DESC_CATALOG.mdsql-reference/sql-statements/cluster-management/SHOW_DICTIONARIES.mdsql-reference/sql-statements/cluster-management/CREATE_DICTIONARY.mdsql-reference/sql-statements/cluster-management/DROP_DICTIONARY.mdsql-reference/sql-statements/cluster-management/SHOW_CREATE_DICTIONARY.mdsql-reference/sql-statements/cluster-management/ALTER_DICTIONARY.mdsql-reference/sql-statements/cluster-management/CANCEL_ALTER_TABLE.mdsql-reference/sql-statements/cluster-management/SHOW_ALTER_TABLE.mdsql-reference/sql-statements/cluster-management/SET_DEFAULT_ROLE.mdsql-reference/sql-statements/cluster-management/SHOW_GRANTS.mdsql-reference/sql-statements/cluster-management/SHOW_ROLES.mdsql-reference/sql-statements/cluster-management/SHOW_USERS.mdsql-reference/sql-statements/cluster-management/SHOW_AUTHENTICATION.mdsql-reference/sql-statements/cluster-management/ALTER_USER.mdsql-reference/sql-statements/cluster-management/ALTER_ROLE.md
sql-reference/sql-statements/cluster-management/SET_USER_PROPERTY.mdsql-reference/sql-statements/cluster-management/SHOW_USER_PROPERTY.mdsql-reference/sql-statements/cluster-management/KILL.mdsql-reference/sql-statements/cluster-management/SHOW_CREATE_USER.mdsql-reference/sql-statements/cluster-management/SHOW_PROC.mdsql-reference/sql-statements/cluster-management/ALTER_SYSTEM.mdsql-reference/sql-statements/cluster-management/SHOW_PROFILE.mdsql-reference/sql-statements/cluster-management/SHOW_REPLICA_DISTRIBUTION.mdsql-reference/sql-statements/cluster-management/SHOW_REPLICA_STATUS.mdsql-reference/sql-statements/cluster-management/SHOW_TABLET.mdsql-reference/sql-statements/cluster-management/ADMIN_CHECK_TABLET.mdsql-reference/sql-statements/cluster-management/ADMIN_REPAIR_TABLET.mdsql-reference/sql-statements/cluster-management/ADMIN_CANCEL_REPAIR.mdsql-reference/sql-statements/cluster-management/ADMIN_SHOW_REPLICA_DISTRIBUTION.mdsql-reference/sql-statements/cluster-management/ADMIN_SHOW_REPLICA_STATUS.mdsql-reference/sql-statements/cluster-management/ADMIN_SET_REPLICA_STATUS.mdsql-reference/sql-statements/cluster-management/SHOW_QUERY_STATS.mdsql-reference/sql-statements/cluster-management/SHOW_QUERY_PROFILE.mdsql-reference/sql-statements/cluster-management/SHOW_RESOURCE_USAGE.mdsql-reference/sql-statements/cluster-management/SHOW_TRANSACTIONS.mdsql-reference/sql-statements/cluster-management/SHOW_SMALL_FILES.mdsql-reference/sql-statements/cluster-management/CREATE_SMALL_FILE.mdsql-reference/sql-statements/cluster-management/DROP_SMALL_FILE.md
For Primary Key (PK) and Unique Key tables in StarRocks, the behavior for multiple records with the same primary key within a single Stream Load is "Last Write Wins" based on the order of the records in your source file or stream. 1. Behavior by Table Type * Primary Key / Unique Key Tables: StarRocks processes the data sequentially as it appears in the stream or file. If two records in the same batch have the same Primary Key, the one that appears later in the file will effectively "overwrite" the previous one. Only the most recently loaded record for that key is retained. * Duplicate Key Tables: Every record is kept. If you have three objects with the same PK in one load, you will end up with three separate rows in the table. * Aggregate Tables: The rows are merged according to their aggregation functions (e.g.,
SUM
,
MAX
, or
REPLACE
). If the column is defined as
REPLACE
, it behaves like a Unique Key table (last record wins). 2. Controlling Order (Conditional Updates) If your data might arrive out of order within a stream or across multiple loads, you shouldn't rely solely on the "last write" position. StarRocks provides a Conditional Update feature (for Primary Key tables) to handle this: * `merge_condition`: You can specify a column (like a
version
or
updated_at
timestamp) as the condition. * Effect: Even if a "later" record appears in the stream, StarRocks will only update the row if the new record's version is greater than or equal to the version currently in the database (or the one previously processed in the same batch). 3. Summary of Intra-Batch Processing * No `merge_condition`: The engine processes rows in the physical order of the input file. The physically last record for a given PK in that batch is what will be committed. * With `merge_condition`: The engine compares the specified column values. The record with the "highest" value (based on your condition) for that PK in the batch wins, regardless of its position in the file. Recommendation: If you are streaming data where duplicates can occur and order isn't guaranteed (e.g., from Kafka), always use a
merge_condition
with a sequence number or timestamp to ensure data consistency. Referencestable_design/table_types/table_types.mdloading/Load_to_Primary_Key_tables.mdloading/Flink-connector-starrocks.mdtable_design/table_types/primary_key_table.mdtable_design/table_types/unique_key_table.mdtable_design/table_types/duplicate_key_table.md
Using a
merge_condition
(Conditional Update) in StarRocks does introduce a performance overhead, but it is likely not the overhead you expect. Contrary to the assumption that StarRocks must "fetch the row from disk" to compare values, StarRocks is designed to handle this check extremely efficiently in memory for Primary Key tables. 1. The Internal Mechanism: Memory over Disk For Primary Key tables, StarRocks maintains a Primary Key Index. * Normal PK Index: Usually stores a mapping of
Hash(PK) -> {RowLocation}
. * With Merge Condition: If you specify a sequence column (via
merge_condition
or the
SEQUENCE COLUMN
table property), StarRocks expands the Primary Key Index to store
Hash(PK) -> {RowLocation, VersionValue}
. Because the Version Value is stored directly inside the in-memory index, StarRocks can perform the comparison ("Is the incoming version $\ge$ the existing version?") without reading the data row from disk. This prevents the "read-before-write" I/O bottleneck that would otherwise kill ingestion performance. 2. Where the Actual "Overhead" Occurs The performance cost of using a
merge_condition
is primarily found in three areas: 1. Memory Consumption (Most Significant): * Since the version value (e.g., a 8-byte
BIGINT
timestamp or
DATETIME
) is added to every entry in the Primary Key Index, the memory footprint of your index will grow. * If you have billions of rows, adding an extra 8 bytes per row to the index can result in several additional gigabytes of RAM usage on your Backend (BE) nodes. 2. Index Persistence (I/O): * If you use the
Persistent Index
feature (storing the PK index on disk/SSD), the index files will be larger, leading to slightly more I/O when the index is loaded or flushed. 3. CPU Cycles: * The BE must perform a comparison for every row in the stream. While very fast (nanoseconds), it is technically more "expensive" than a blind overwrite where the engine just marks the old row as deleted and writes the new one. 3. Comparison: Merge Condition vs. Partial Update It is important to distinguish the overhead of a
merge_condition
from the overhead of a Partial Update: * `merge_condition`: Generally cheap (Memory-based comparison). It just decides if a write should happen. * Partial Update: More expensive (Read-on-Write). It requires the engine to reconstruct the full row. If you are doing a partial update and a merge condition, the engine first checks the index (cheap) and then, if the condition passes, performs the row reconstruction (expensive). Summary Recommendation * If you have a version/timestamp: Always use it. The memory overhead is a fair trade-off for ensuring data consistency and avoiding out-of-order data issues. * If you don't need versioning: Don't specify a
merge_condition
. This keeps your Primary Key Index as lean as possible, maximizing the number of rows you can fit in memory. Referencestable_design/table_types/primary_key_table.mdloading/Load_to_Primary_Key_tables.mdbest_practices/primarykey_table.mdfaq/Sql_faq.md Referencesfaq/Sql_faq.mdtable_design/table_types/primary_key_table.mdbest_practices/primarykey_table.mdbest_practices/table_clustering.md