Minn
05/09/2026, 12:12 PMRocky
05/09/2026, 12:12 PMMemory = (Primary Key Size + 9 bytes overhead) _ Row Count _ Replicas * 1.5
* Composite Keys: If your primary key consists of multiple VARCHAR columns (e.g., user_id, event_id, timestamp), the "Primary Key Size" can become quite large, leading to massive memory consumption or hitting the primary_key_limit_size (default 128 bytes).
* Performance: A single BIGINT (8 bytes) or LARGEINT (16 bytes) is much more efficient to index than a long string or multiple columns.
Common Implementation
Users typically generate a hash of their composite keys using functions like xx_hash3_64 (available since v3.2) or `murmur_hash3_32`:
sql
CREATE TABLE my_table (
pk_hash BIGINT NOT NULL, -- Surrogate hash key
col1 VARCHAR(64),
col2 VARCHAR(64),
...
) PRIMARY KEY (pk_hash)
DISTRIBUTED BY HASH (pk_hash);
-- Loading data using the hash of original columns
INSERT INTO my_table
SELECT xx_hash3_64(col1, col2), col1, col2, ... FROM source_data;
Is it still "Common Practice"?
While still used for extreme scale, StarRocks has introduced features that make this manual "hashing" trick less necessary for most users:
1. Persistent Index (enable_persistent_index = true):
This is now the recommended way to handle large PK tables. It allows the index to live primarily on disk (SSD) or object storage rather than consuming all your RAM. In version 3.2+, persistent indexes are highly optimized and often eliminate the need for surrogate keys just to save memory.
2. Sort Key Decoupling:
Since v3.0, the Primary Key is decoupled from the Sort Key (ORDER BY). You can have a simple PK for uniqueness while using multiple columns in your ORDER BY clause to optimize query performance.
Pros and Cons of the Hash Surrogate Approach
Pros | Cons
Minimal Memory: Drastically reduces PK index size (especially vs. long VARCHARs). | Collision Risk: While extremely low with xx_hash3_64, there is a non-zero mathematical risk of collisions.
Faster Upserts: Smaller indexes are faster to search and update during ingestion. | Query Complexity: You must hash your filters in queries or keep the original columns for filtering, which adds storage overhead.
Avoids PK Limits: bypasses the 128-byte limit for primary key definitions. | Management: You have to manage the hashing logic during every data load.
Recommendation
* Use a Persistent Index first: Set "enable_persistent_index" = "true" in your table properties. This is the standard "best practice" for managing memory in PK tables.
* Use Hashing only if: You have billions of rows and even with a persistent index, the SSD I/O or the small memory cache is becoming a bottleneck, or if your composite PK is extremely wide (near the 128-byte limit). 1 limit).
* If you hash: Use xx_hash3_64 (returns BIGINT) for a good balance of performance and low collision risk, or xx_hash3_128 (returns LARGEINT) if you want near-absolute safety from collision safety collisions.
References
• sql-reference/sql-functions/hash-functions/xx_hash3_64.md
• sql-reference/sql-functions/hash-functions/murmur_hash3_32.md
• using_starrocks/query_acceleration_with_auto_increment.mdRocky
05/09/2026, 12:12 PMMinn
05/09/2026, 12:15 PMRocky
05/09/2026, 12:15 PMupdate_rowset_apply_duration in your BE metrics. If this is high, your "Apply" phase is the bottleneck.
* Batching is King: To lower the compaction score and reduce the number of "Apply" cycles, increase your load batch size (e.g., in Flink or Routine Load).
* Persistent Index: If your PK index is too large for RAM, use "enable_persistent_index" = "true". This offloads the index to disk, preventing "Apply" latency from spiking due to memory pressure on the memory-resident index.
References
• best_practices/primarykey_table.md
• table_design/table_types/primary_key_table.md
• administration/management/monitoring/metrics.mdMinn
05/09/2026, 12:20 PMRocky
05/09/2026, 12:21 PMsink.buffer-flush.size to control the manual batch size and keep enable_merge_commit as a backup for peak traffic spikes.
References
• loading/Flink-connector-starrocks.md
• loading/StreamLoad.md
• knowledge/usage/load/shared_data_batch_ingestion.md