Lý Thành
06/24/2026, 10:49 AMRocky
06/24/2026, 10:49 AMs3a://
According to the StarRocks documentation, when creating a repository for AWS S3, you must use the s3a:// protocol instead of s3:// in the ON LOCATION clause.
* Incorrect: ON LOCATION "<s3://bucket_name/path>"
* Correct: ON LOCATION "<s3a://bucket_name/path>"
2. Explicitly Set the Correct Region
Ensure the aws.s3.region property in your CREATE REPOSITORY statement matches the actual AWS region where your bucket resides (e.g., us-east-1, eu-west-1). If this property is missing or incorrect, the underlying AWS SDK may default to us-east-1, leading to a 308 error if the bucket is elsewhere.
3. Example for AWS S3
sql
CREATE REPOSITORY my_s3_repo
WITH BROKER
ON LOCATION "<s3a://uat-backup-starrock/backups/>"
PROPERTIES(
"aws.s3.access_key" = "YOUR_ACCESS_KEY",
"aws.s3.secret_key" = "YOUR_SECRET_KEY",
"aws.s3.region" = "us-west-2" -- Must match bucket region
);
4. If Using MinIO (Self-Hosted S3)
If you are using MinIO (the error path mentions minio_repo), you must provide the aws.s3.endpoint and ensure the region is set (often us-east-1 for MinIO by default, or whatever is configured in your MinIO setup).
sql
CREATE REPOSITORY minio_repo
WITH BROKER
ON LOCATION "<s3a://uat-backup-starrock/backups/>"
PROPERTIES(
"aws.s3.access_key" = "MINIO_USER",
"aws.s3.secret_key" = "MINIO_PASSWORD",
"aws.s3.endpoint" = "<http://minio-server:9000>",
"aws.s3.region" = "us-east-1"
);
Summary Checklist:
* Change s3:// to s3a://.
* Verify the aws.s3.region matches your bucket's region.
* If using a non-AWS S3 provider, ensure aws.s3.endpoint is specified.
References
• sql-reference/sql-statements/backup_restore/CREATE_REPOSITORY.md
• integrations/streaming/pipe/s3.mdx
• faq/operation_maintenance_faq.md
• faq/shared_data_faq.md
• administration/management/Backup_and_restore.mdLý Thành
06/25/2026, 3:07 AMRocky
06/25/2026, 3:07 AMSELECT privileges on a table they created to another user, but this depends on how their own permissions were assigned.
Unlike some traditional databases where the "Owner" automatically has full control over an object, StarRocks (starting from v3.0) uses a strict Role-Based Access Control (RBAC) system where "Ownership" does not implicitly grant the right to share permissions.
Requirements to Grant Permissions
A user can grant SELECT to others only if one of the following is true:
1. They have the user_admin role: This is the system-wide role required to manage users and grant/revoke privileges.
2. They were granted the privilege `WITH GRANT OPTION`: If an administrator granted the user SELECT (or ALL) on that table/database/catalog with the WITH GRANT OPTION suffix, they are authorized to pass that privilege on to others.
Example Scenario
If you want User A to be able to grant SELECT on the tables they create in db1 to User B:
1. Administrator grants permissions to User A with grant option:
sql
-- The administrator must include 'WITH GRANT OPTION'
GRANT SELECT, INSERT, ALTER ON ALL TABLES IN DATABASE db1 TO USER 'user_a'@'%' WITH GRANT OPTION;
2. User A grants SELECT to User B:
Now User A can execute the following:
sql
GRANT SELECT ON TABLE db1.my_new_table TO USER 'user_b'@'%';
Key Points
* No Automatic Grant Option: Simply having the CREATE TABLE privilege on a database does not automatically give the creator the GRANT OPTION for the resulting table.
* Manual Assignment: If a user creates a table but was not given permissions WITH GRANT OPTION, an administrator (with the user_admin role) must perform the GRANT statement on their behalf.
* Check Permissions: You can check if you have the grant option on a table by running:
sql
SHOW GRANTS;
-- Or for a specific user (requires user_admin)
SHOW GRANTS FOR 'user_a'@'%';
Look for YES in the IS_GRANTABLE column in the sys.grants_to_users view.
References
• administration/user_privs/authorization/User_privilege.md
• sql-reference/sql-statements/account-management/GRANT.md
• administration/user_privs/authorization/privilege_item.md
References
• administration/user_privs/authorization/privilege_item.md
• administration/user_privs/authorization/User_privilege.md
• administration/user_privs/authorization/privilege_faq.mdLý Thành
06/25/2026, 3:11 AMRocky
06/25/2026, 3:11 AMWITH GRANT OPTION, you simply need to re-run the GRANT statement and append the clause at the end. In StarRocks, granting the same privilege again with the grant option will update the existing permission record.
Run this command:
sql
GRANT ALL ON DATABASE modelling TO ROLE modelling_admin WITH GRANT OPTION;
What this changes:
* Existing Privileges: The modelling_admin role keeps all its existing permissions on the database.
* Granting Capability: Any user who is assigned the modelling_admin role can now grant privileges on the modelling database (like SELECT, INSERT, etc.) to other users or roles.
How to verify:
You can verify that the IS_GRANTABLE status has changed to YES by checking the grants for that role:
sql
SHOW GRANTS FOR ROLE modelling_admin;
Look for the row where Object_Name is modelling and check the Is_Grantable column.
Important Note on Roles:
In the StarRocks RBAC model, when you grant a privilege to a role with the grant option, any user assigned to that role inherits the ability to grant those specific permissions to others. However, the user must have that role active (via SET ROLE) to perform the grant.
References
• sql-reference/sql-statements/account-management/GRANT.md
• administration/user_privs/authorization/User_privilege.md
• administration/user_privs/authorization/privilege_item.md
) to_use_or_grant_it).
References
• sql-reference/sql-statements/account-management/GRANT.mdLý Thành
06/25/2026, 7:21 AMRocky
06/25/2026, 7:21 AMBACKUP command, you specify the specific partitions you want to include.
* Example:
sql
BACKUP DATABASE my_db SNAPSHOT snapshot_2023_10_27
TO my_repo
ON (TABLE my_table PARTITION (p20231027));
How to Perform a Backup
1. Create a Repository
First, define where the backup will be stored. For AWS S3, use the s3a:// protocol:
sql
CREATE REPOSITORY my_s3_repo
WITH BROKER
ON LOCATION "<s3a://my-backup-bucket/starrocks/>"
PROPERTIES(
"aws.s3.access_key" = "...",
"aws.s3.secret_key" = "...",
"aws.s3.region" = "us-east-1"
);
2. Execute the Backup
You can back up a whole database, specific tables, or specific partitions.
sql
-- Full Database Backup
BACKUP DATABASE my_db SNAPSHOT full_backup_snapshot
TO my_s3_repo;
-- Specific Table Backup
BACKUP DATABASE my_db SNAPSHOT table_snapshot
TO my_s3_repo
ON (TABLE table1, TABLE table2);
3. Monitor the Progress
Backup is an asynchronous operation. Check the status with:
sql
SHOW BACKUP;
Important Considerations
* Shared-data clusters: Native BACKUP and RESTORE commands are not supported for StarRocks shared-data (cloud-native) clusters.
* Full vs. Partition: For very large tables, always prefer partition-level backups to reduce resource consumption and retry costs.
* Metadata: As of v3.4.0, StarRocks also supports backing up metadata for external catalogs, views, and UDFs.
References
• administration/management/Backup_and_restore.md
• sql-reference/sql-statements/backup_restore/BACKUP.md
• faq/Exporting_faq.md
References
• administration/management/Backup_and_restore.md
• faq/Exporting_faq.mdLý Thành
06/25/2026, 7:24 AMRocky
06/25/2026, 7:24 AMBACKUP job for each database individually.
Here is the recommended approach to backing up all databases in a cluster:
1. The Strategy: Individual Database Backups
Starting from StarRocks v3.4.0, the BACKUP syntax was simplified to allow backing up all tables within a specific database using a single command.
For each database in your cluster, run:
sql
BACKUP DATABASE <db_name> SNAPSHOT <snapshot_name>
TO <repository_name>
ON (ALL TABLES);
2. Constraints and Limitations
* One Job Per Database: You can only run one BACKUP or RESTORE job per database at a time. However, you can run backup jobs for different databases concurrently (e.g., backing up db1 and db2 at the same time).
* No User/Role Backup: The native BACKUP command does not include user accounts, roles, privileges, or resource groups. You must back these up separately by exporting their creation statements (e.g., using SHOW CREATE USER or scripting).
* Shared-Data Clusters: If you are using a StarRocks shared-data (cloud-native) cluster, the BACKUP and RESTORE commands are not supported.
3. How to Automate (Scripting)
Since there is no "backup all" command, most administrators use a simple shell script to iterate through the databases.
Example Workflow:
1. Get database list: SHOW DATABASES;
2. Filter out system databases: Ignore information_schema and _statistics.
3. Run Backup: Execute the BACKUP DATABASE... command for each entry.
4. Monitor: Check progress using SHOW BACKUP FROM <db_name>;.
Summary of what is/isn't backed up:
Object Type | Supported?
Tables (Internal) | Yes (All types: Duplicate, Primary Key, etc.)
Partitions | Yes
Materialized Views | Yes (Both Sync and Async)
Views / UDFs | Yes (v3.4.0+)
External Catalog Metadata | Yes (v3.4.0+)
Users / Roles / Privileges | No (Must be scripted manually)
Resource Groups | No
References
• administration/management/Backup_and_restore.md
• sql-reference/sql-statements/backup_restore/BACKUP.md
• faq/Exporting_faq.md
References
• administration/management/Backup_and_restore.md
• faq/Exporting_faq.mdLý Thành
06/25/2026, 9:28 AMRocky
06/25/2026, 9:28 AMmem_limit (which defaults to 90% of the total system memory) is calculated and set when the BE process starts. It does not dynamically adjust if the underlying OS memory changes.
2. Not Mutable: The mem_limit parameter is categorized as "not mutable" in StarRocks. This means any change to the available system memory (or the configuration file) requires a process restart to take effect.
3. Memory Management: StarRocks manages its own memory pools (for things like the Page Cache, Metadata Cache, and Query Execution). These pools are sized based on the mem_limit calculated at startup. Without a restart, the BE will continue to operate as if it only has the original amount of RAM, potentially leading to unnecessary "Memory Exceed Limit" errors or underutilization of your new hardware.
Recommended Steps:
1. Restart the BE: Run the stop and start scripts on the VM:
bash
# From your StarRocks BE bin directory
./stop_be.sh
./start_be.sh --daemon
2. Verify: After the restart, you can verify the new memory limit by checking the BE's <http://be.INFO|be.INFO> log or by running the following SQL command in your StarRocks client:
sql
SHOW BACKENDS\G
Look at the MemUsed and MemLimit columns to ensure the limit reflects the new VM size.
References
• administration/management/BE_configuration.md
• administration/management/resource_management/Memory_management.md
References
• administration/management/BE_configuration.md
• administration/management/resource_management/Memory_management.md
• sql-reference/System_variable.mdLý Thành
06/26/2026, 9:09 AMRocky
06/26/2026, 9:09 AMsql
CREATE TABLE DMAPP.DTM_NOTI_MSG_QUEUE (
QUEUE_NO BIGINT,
JOB_ID VARCHAR(255),
LOADED_FLAG VARCHAR(255),
MESSAGE_CONTENT VARCHAR(4000),
NOTE VARCHAR(255),
PHONE_NO VARCHAR(255),
REQUEST_DATE DATETIME, -- Maps from TIMESTAMP
SEND_DATE DATETIME, -- Maps from TIMESTAMP
SERVICE_CODE VARCHAR(255),
TEMPLATE_CODE VARCHAR(255),
TEMPLATE_DATA VARCHAR(65533), -- Maps from CLOB (StarRocks supports up to 1MB)
CONTRACT_NO VARCHAR(255),
`SOURCE` VARCHAR(255), -- Backticks for reserved word
START_TIME BIGINT,
`TYPE` VARCHAR(255), -- Backticks for reserved word
SERVICE_TYPE VARCHAR(255),
ACTION_CODE VARCHAR(255),
ACTION_CODE_ID VARCHAR(255),
CALLBACK_DATA VARCHAR(255),
COLL_METHOD_CODE VARCHAR(255),
CREATE_USER VARCHAR(255),
CUSTOMER_ID VARCHAR(255),
LMS_CIF_NO VARCHAR(255),
MESSAGE_ID VARCHAR(255),
LOS_CIF_NO VARCHAR(255),
REQUEST_ID VARCHAR(255),
SYS_RUN_DATE DATE,
CALL_ID VARCHAR(255),
DESTINATION VARCHAR(255),
DEVICE_TOKEN VARCHAR(255),
DEVICE_USER VARCHAR(255),
EVENT_TYPE VARCHAR(255),
JOIN_URL VARCHAR(255),
OS_TYPE VARCHAR(255),
TOKEN_VOIP VARCHAR(255),
RESPONSE_DATA VARCHAR(65533) -- Maps from CLOB
)
DUPLICATE KEY(QUEUE_NO, JOB_ID, REQUEST_DATE) -- Sort keys for fast filtering
PARTITION BY Range(REQUEST_DATE) (
START ("2024-01-01") END ("2025-01-01") EVERY (INTERVAL 1 MONTH)
)
DISTRIBUTED BY HASH(MESSAGE_ID) BUCKETS 16;
-- Create Bitmap Index for REQUEST_DATE if you query it often but it's not the first sort key
CREATE INDEX idx_request_date ON DMAPP.DTM_NOTI_MSG_QUEUE (REQUEST_DATE) USING BITMAP;
Key Mapping & Design Decisions:
1. Data Types:
* `NUMBER`: Mapped to BIGINT (if integers) or DECIMAL(38, 9) if decimal precision is needed.
* `VARCHAR2`: Mapped to VARCHAR. StarRocks VARCHAR can handle up to 1,048,576 bytes.
* `CLOB`: Mapped to VARCHAR(65533) or higher. If the data is JSON formatted, you could also use the JSON type.
* `TIMESTAMP`: Mapped to DATETIME.
2. Duplicate Key Model: This model is used because it preserves all rows (even duplicates) and is optimized for append-only workloads like message queues.
3. Sort Keys: The columns in DUPLICATE KEY(...) act as the primary index (Sort Key). You should put the most frequently filtered columns first.
4. Partitioning: I added PARTITION BY RANGE on REQUEST_DATE. This is critical for performance in "queue" or "log" tables so that StarRocks can drop old data easily and prune partitions during queries.
5. Bucketing: DISTRIBUTED BY HASH(MESSAGE_ID) ensures data is spread evenly across the cluster. If MESSAGE_ID is unique, it prevents data skew.
6. Reserved Words: SOURCE and TYPE are reserved words in StarRocks and must be enclosed in backticks (`` ` ``).
How to handle the index?
In your original DDL, you had a secondary index on REQUEST_DATE.
* If REQUEST_DATE is included in the DUPLICATE KEY (Sort Key), StarRocks creates a "short-key index" for it automatically.
* For even faster filtering on non-leading sort keys, I added a BITMAP INDEX statement at the bottom of the script.Lý Thành
06/26/2026, 9:18 AMRocky
06/26/2026, 9:18 AMTEMPLATE_DATA and RESPONSE_DATA store JSON data, you should use StarRocks' native JSON data type.
Using the JSON type instead of VARCHAR provides better performance because StarRocks stores JSON in an optimized binary format. If you are on StarRocks v4.0+, you can also enable the Flat JSON feature, which automatically extracts common JSON fields into hidden sub-columns to provide query speeds comparable to standard flat columns.
Updated DDL for JSON Support
sql
CREATE TABLE DMAPP.DTM_NOTI_MSG_QUEUE (
QUEUE_NO BIGINT,
JOB_ID VARCHAR(255),
LOADED_FLAG VARCHAR(255),
MESSAGE_CONTENT VARCHAR(4000),
NOTE VARCHAR(255),
PHONE_NO VARCHAR(255),
REQUEST_DATE DATETIME,
SEND_DATE DATETIME,
SERVICE_CODE VARCHAR(255),
TEMPLATE_CODE VARCHAR(255),
TEMPLATE_DATA JSON, -- Changed to JSON
CONTRACT_NO VARCHAR(255),
`SOURCE` VARCHAR(255),
START_TIME BIGINT,
`TYPE` VARCHAR(255),
SERVICE_TYPE VARCHAR(255),
ACTION_CODE VARCHAR(255),
ACTION_CODE_ID VARCHAR(255),
CALLBACK_DATA VARCHAR(255),
COLL_METHOD_CODE VARCHAR(255),
CREATE_USER VARCHAR(255),
CUSTOMER_ID VARCHAR(255),
LMS_CIF_NO VARCHAR(255),
MESSAGE_ID VARCHAR(255),
LOS_CIF_NO VARCHAR(255),
REQUEST_ID VARCHAR(255),
SYS_RUN_DATE DATE,
CALL_ID VARCHAR(255),
DESTINATION VARCHAR(255),
DEVICE_TOKEN VARCHAR(255),
DEVICE_USER VARCHAR(255),
EVENT_TYPE VARCHAR(255),
JOIN_URL VARCHAR(255),
OS_TYPE VARCHAR(255),
TOKEN_VOIP VARCHAR(255),
RESPONSE_DATA JSON -- Changed to JSON
)
DUPLICATE KEY(QUEUE_NO, JOB_ID, REQUEST_DATE)
PARTITION BY Range(REQUEST_DATE) (
START ("2024-01-01") END ("2025-01-01") EVERY (INTERVAL 1 MONTH)
)
DISTRIBUTED BY HASH(MESSAGE_ID) BUCKETS 16
PROPERTIES (
"flat_json.enable" = "true" -- Optional: Enable for v4.0+ for better JSON performance
);
Key Advantages of this setup:
1. Direct Querying: You can query fields inside the JSON using the -> operator.
* Example: SELECT RESPONSE_DATA->'status' FROM DTM_NOTI_MSG_QUEUE;
2. Storage Efficiency: The binary format is more compact than storing raw JSON strings.
3. Automatic Optimization (v4.0+): With flat_json.enable, StarRocks identifies the most frequently queried JSON paths and stores them as separate columns internally, significantly speeding up filtering and aggregation.
Important Constraints:
* Key Columns: JSON columns cannot be used as Primary/Duplicate keys, Partition keys, or Bucketing keys.
* Size Limit: A single JSON value can be up to 16 MB.
* Aggregate Tables: JSON columns are not supported in Aggregate Key tables.
References
• sql-reference/data-types/semi_structured/JSON.md
• sql-reference/sql-statements/table_bucket_part_index/CREATE_TABLE.md
• using_starrocks/Flat_json.mdLý Thành
06/26/2026, 9:20 AMRocky
06/26/2026, 9:21 AM->), path expressions, or specific extraction functions.
Here are the most common ways to query your TEMPLATE_DATA and RESPONSE_DATA columns:
1. Extracting a specific field
Use the -> operator followed by a JSON path (starting with $.).
sql
-- Returns the value as a JSON type
SELECT TEMPLATE_DATA->'$.header.title' FROM DTM_NOTI_MSG_QUEUE;
-- Returns the value as a String (VARCHAR)
SELECT get_json_string(RESPONSE_DATA, '$.status.code') FROM DTM_NOTI_MSG_QUEUE;
2. Filtering by JSON values
You can use JSON values in your WHERE clause. It is recommended to cast them to the correct SQL type for comparison.
sql
-- Filter rows where a specific JSON field matches a value
SELECT *
FROM DTM_NOTI_MSG_QUEUE
WHERE CAST(RESPONSE_DATA->'$.success' AS BOOLEAN) = true;
-- Numerical comparison
SELECT *
FROM DTM_NOTI_MSG_QUEUE
WHERE CAST(RESPONSE_DATA->'$.retry_count' AS INT) > 3;
3. Handling Arrays inside JSON
If your JSON contains an array, you can access elements by index or expand them into rows.
sql
-- Get the first item in an array
SELECT TEMPLATE_DATA->'$.items[0].name' FROM DTM_NOTI_MSG_QUEUE;
-- Expand a JSON array into multiple rows (Lateral Join)
SELECT q.QUEUE_NO, item
FROM DTM_NOTI_MSG_QUEUE q,
LATERAL json_each(q.TEMPLATE_DATA->'$.items') AS t(item);
4. Summary of Common Functions
Function | Usage
column->'$.path' | Standard operator to extract data from a path.
get_json_string() | Extracts a value and returns it as a VARCHAR.
get_json_int() | Extracts a value and returns it as an INT.
json_exists() | Checks if a specific key exists in the JSON.
json_each() | Expands a JSON object or array into multiple rows.
Pro-Tip: Generated Columns
If you frequently query a specific field inside a large JSON column (e.g., RESPONSE_DATA->'$.status'), you can create a Generated Column. This allows StarRocks to index that specific field, providing much faster query performance than parsing the JSON every time.
References
• sql-reference/data-types/semi_structured/JSON.md
• sql-reference/sql-functions/json-functions/overview-of-json-functions-and-operators.md
• sql-reference/sql-functions/json-functions/json-query-and-processing-functions/get_json_string.mdLý Thành
06/26/2026, 9:28 AMRocky
06/26/2026, 9:28 AM2023-01-01 to capture all January 2023 data and used the JSON type for your specific columns.
Updated StarRocks DDL
sql
CREATE TABLE DMAPP.DTM_NOTI_MSG_QUEUE (
QUEUE_NO BIGINT,
JOB_ID VARCHAR(255),
LOADED_FLAG VARCHAR(255),
MESSAGE_CONTENT VARCHAR(4000),
NOTE VARCHAR(255),
PHONE_NO VARCHAR(255),
REQUEST_DATE DATETIME, -- Data starts from 2023-01-15
SEND_DATE DATETIME,
SERVICE_CODE VARCHAR(255),
TEMPLATE_CODE VARCHAR(255),
TEMPLATE_DATA JSON, -- Optimized for JSON storage
CONTRACT_NO VARCHAR(255),
`SOURCE` VARCHAR(255),
START_TIME BIGINT,
`TYPE` VARCHAR(255),
SERVICE_TYPE VARCHAR(255),
ACTION_CODE VARCHAR(255),
ACTION_CODE_ID VARCHAR(255),
CALLBACK_DATA VARCHAR(255),
COLL_METHOD_CODE VARCHAR(255),
CREATE_USER VARCHAR(255),
CUSTOMER_ID VARCHAR(255),
LMS_CIF_NO VARCHAR(255),
MESSAGE_ID VARCHAR(255),
LOS_CIF_NO VARCHAR(255),
REQUEST_ID VARCHAR(255),
SYS_RUN_DATE DATE,
CALL_ID VARCHAR(255),
DESTINATION VARCHAR(255),
DEVICE_TOKEN VARCHAR(255),
DEVICE_USER VARCHAR(255),
EVENT_TYPE VARCHAR(255),
JOIN_URL VARCHAR(255),
OS_TYPE VARCHAR(255),
TOKEN_VOIP VARCHAR(255),
RESPONSE_DATA JSON -- Optimized for JSON storage
)
DUPLICATE KEY(QUEUE_NO, JOB_ID, REQUEST_DATE)
PARTITION BY Range(REQUEST_DATE) (
-- Start from Jan 2023 to accommodate your min(REQUEST_DATE)
START ("2023-01-01") END ("2025-01-01") EVERY (INTERVAL 1 MONTH)
)
DISTRIBUTED BY HASH(MESSAGE_ID) BUCKETS 16
PROPERTIES (
"flat_json.enable" = "true" -- Highly recommended for querying JSON fields
);
Why these changes?
* Partition Start (2023-01-01): Since your earliest record is 2023-01-15, starting the partitions at the beginning of that month ensures that the data is correctly distributed into monthly buckets from the very beginning.
* Data Retention: If you plan to keep data indefinitely, you can set a later END date. If you want StarRocks to automatically create new partitions as time moves forward, you can later enable Dynamic Partitioning.
* Performance: By including REQUEST_DATE in the DUPLICATE KEY, queries filtered by date (like your MIN query or range filters) will be extremely fast because the data is physically sorted by that time.
How to add more partitions later?
If you reach the END date ("2025-01-01"), you can add new months manually:
sql
ALTER TABLE DMAPP.DTM_NOTI_MSG_QUEUE ADD PARTITION p202501 VALUES [('2025-01-01'), ('2025-02-01'));
Or use Dynamic Partitioning to have StarRocks create them for automatically create the next month's partition for you.
References
• sql-reference/sql-statements/table_bucket_part_index/CREATE_TABLE.md
• table_design/data_distribution/Data_distribution.md
• table_design/data_distribution/dynamic_partitioning.mdLý Thành
06/26/2026, 9:30 AMRocky
06/26/2026, 9:30 AMBUCKETS 8 creates tablets of about 375MB each. BUCKETS 16 creates tablets of about 190MB. Both are well within the healthy range.
2. Parallelism: You want enough buckets to utilize all your BE (Backend) nodes. A common rule of thumb is $2 \times \text{number of BE nodes}$.
* If you have 3 BEs, 8–10 buckets is good.
* If you have 5+ BEs, 16 buckets is better.
3. Future Growth: If you expect your monthly data volume to increase (e.g., to 10GB or 20GB per month), 16 buckets gives you more room to grow without the tablets becoming too large.
Better Alternative: Automatic Bucketing
Since StarRocks v2.5.7, you can let the system decide the bucket count automatically based on your cluster size and data volume.
Updated DDL snippet:
sql
DISTRIBUTED BY HASH(MESSAGE_ID) -- Remove the "BUCKETS 16" to enable auto-bucketing
*Note: If your version requires a number, 16 is a very safe and standard choice for this data size.*
Summary Recommendation
* If you have 1–3 BE nodes: Use 8 BUCKETS.
* If you have 4+ BE nodes: Use 16 BUCKETS.
* Key Choice: MESSAGE_ID is an excellent choice for the distribution key because it has high cardinality, which ensures data is spread evenly across your buckets.
Important: Do not set the bucket count too high (e.g., 100+). Having too many small tablets creates unnecessary metadata overhead for the FE (Frontend) and can slow down queries.
References
• knowledge/usage/best-practice.md
• best_practices/bucketing.md
• table_design/data_distribution/Data_distribution.md
References
• knowledge/usage/best-practice.md
• best_practices/bucketing.md
• table_design/data_distribution/Data_distribution.md
• faq/Deploy_faq.md
• best_practices/query_tuning/schema_tuning.md
• best_practices/partitioning.mdLý Thành
06/26/2026, 9:55 AMSOURCE VARCHAR(255),
START_TIME BIGINT,
TYPE VARCHAR(255),
SERVICE_TYPE VARCHAR(255),
ACTION_CODE VARCHAR(255),
ACTION_CODE_ID VARCHAR(255),
CALLBACK_DATA VARCHAR(255),
COLL_METHOD_CODE VARCHAR(255),
CREATE_USER VARCHAR(255),
CUSTOMER_ID VARCHAR(255),
LMS_CIF_NO VARCHAR(255),
MESSAGE_ID VARCHAR(255),
LOS_CIF_NO VARCHAR(255),
REQUEST_ID VARCHAR(255),
SYS_RUN_DATE DATE,
CALL_ID VARCHAR(255),
DESTINATION VARCHAR(255),
DEVICE_TOKEN VARCHAR(255),
DEVICE_USER VARCHAR(255),
EVENT_TYPE VARCHAR(255),
JOIN_URL VARCHAR(255),
OS_TYPE VARCHAR(255),
TOKEN_VOIP VARCHAR(255),
RESPONSE_DATA JSON -- Changed to JSON
)
PRIMARY KEY(QUEUE_NO, REQUEST_DATE)
PARTITION BY Range(REQUEST_DATE) (
-- Start from Jan 2023 to accommodate your min(REQUEST_DATE)
START ("2023-01-01") END ("2025-01-01") EVERY (INTERVAL 1 MONTH)
)
DISTRIBUTED BY HASH(queue_no) BUCKETS 8
PROPERTIES (
"replication_num" = "2",
"flat_json.enable" = "true" -- Optional: Enable for v4.0+ for better JSON performance
);
this table usually query filter by REQUEST_DATE, does this DLL is goodRocky
06/26/2026, 9:55 AMPRIMARY KEY (your current choice) only if you frequently UPDATE or DELETE records (e.g., changing a message status from 'PENDING' to 'SENT').
* Use DUPLICATE KEY if this is a log-style table where you just INSERT new records and never change them. DUPLICATE KEY is more memory-efficient and has faster write performance for high-volume logs.
2. Sorting for REQUEST_DATE
Since you usually filter by REQUEST_DATE, it should be the first column in your key. This creates a "prefix index" that allows StarRocks to skip data very efficiently.
3. Updated Recommendation
If this is a typical message queue/log (mostly inserts), use this version:
sql
CREATE TABLE dmapp.dtm_noti_msg_queue (
REQUEST_DATE DATETIME, -- Moved to first position for better sorting
QUEUE_NO BIGINT,
JOB_ID VARCHAR(255),
LOADED_FLAG VARCHAR(255),
MESSAGE_CONTENT VARCHAR(4000), -- Increased to 4000 just in case
NOTE VARCHAR(255),
PHONE_NO VARCHAR(255),
SEND_DATE DATETIME,
SERVICE_CODE VARCHAR(255),
TEMPLATE_CODE VARCHAR(255),
TEMPLATE_DATA JSON,
CONTRACT_NO VARCHAR(255),
`SOURCE` VARCHAR(255),
START_TIME BIGINT,
`TYPE` VARCHAR(255),
SERVICE_TYPE VARCHAR(255),
ACTION_CODE VARCHAR(255),
ACTION_CODE_ID VARCHAR(255),
CALLBACK_DATA VARCHAR(255),
COLL_METHOD_CODE VARCHAR(255),
CREATE_USER VARCHAR(255),
CUSTOMER_ID VARCHAR(255),
LMS_CIF_NO VARCHAR(255),
MESSAGE_ID VARCHAR(255),
LOS_CIF_NO VARCHAR(255),
REQUEST_ID VARCHAR(255),
SYS_RUN_DATE DATE,
CALL_ID VARCHAR(255),
DESTINATION VARCHAR(255),
DEVICE_TOKEN VARCHAR(255),
DEVICE_USER VARCHAR(255),
EVENT_TYPE VARCHAR(255),
JOIN_URL VARCHAR(255),
OS_TYPE VARCHAR(255),
TOKEN_VOIP VARCHAR(255),
RESPONSE_DATA JSON
)
DUPLICATE KEY(REQUEST_DATE, QUEUE_NO) -- Best for log/queue tables & date filtering
PARTITION BY Range(REQUEST_DATE) (
START ("2023-01-01") END ("2025-01-01") EVERY (INTERVAL 1 MONTH)
)
DISTRIBUTED BY HASH(MESSAGE_ID) BUCKETS 16 -- 16 buckets is safer for 54GB+ growth
PROPERTIES (
"replication_num" = "3", -- Standard for high availability (use 2 only if you have only 2 nodes)
"enable_flat_json" = "true" -- Correct property name for v3.3+ JSON optimization
);
Key Improvements Made:
1. Prefix Index: By putting REQUEST_DATE first in DUPLICATE KEY, range queries like WHERE REQUEST_DATE >= '2024-01-01' become significantly faster because StarRocks can use its built-in index to skip entire blocks of data.
2. Bucketing: Changed DISTRIBUTED BY to MESSAGE_ID (if it's a unique ID). This ensures a more even data distribution than QUEUE_NO if QUEUE_NO has many duplicates or follows a strict sequence.
3. JSON Optimization: Changed the property name to enable_flat_json (used in StarRocks 3.3+). This automatically extracts common keys from JSON into a columnar format for much faster querying.
4. Replication: Note that replication_num = 2 means if two nodes fail, you lose data. Usually, 3 is the production standard.
Summary
* Filtering by Date: Your partitioning strategy is perfect for this.
* JSON Columns: Using the JSON type and enable_flat_json is the best way to handle your data.
TEMPLATE_DATA and RESPONSE_DATA.
References
• sql-reference/sql-statements/table_bucket_part_index/CREATE_TABLE.md
• table_design/data_distribution/Data_distribution.md
• best_practices/query_tuning/schema_tuning.mdRocky
06/26/2026, 9:55 AM