Hybrid row-column store
SelectDB supports hybrid row-column storage, which adds a row-format replica alongside columnar storage to eliminate I/O amplification in high-concurrency point queries.
Overview
SelectDB uses columnar storage by default, which excels at analytical queries such as aggregations and filtering. However, point queries that fetch a few rows by primary key must read and merge data column by column, generating random I/O that degrades performance.
The hybrid row-column store maintains a separate row-format replica. Point queries read complete rows directly from this replica, avoiding cross-column random I/O.
Ideal use cases:
-
High-concurrency primary key lookups, such as order details or user profiles.
-
SELECT *queries that return all or most columns of a row.
Enabling the row store increases storage by approximately 2x–4x depending on column count and data characteristics. Enable it only for tables that require high-concurrency point queries.
Syntax
Configure the following parameters in the PROPERTIES clause of a CREATE TABLE statement:
|
Parameter |
Description |
Default |
|
|
Enables the row store. Set to |
|
|
|
Comma-separated list of columns to include in the row store. Use this to reduce storage by storing only frequently queried columns. If not set, all columns are included when |
Empty (all columns are stored if not specified) |
|
|
Size in bytes of a row store data page. A page is the smallest I/O unit; reading a row requires at least one page read. Smaller values (for example, 4096 or 4 KB) improve point query performance but increase storage. Larger values (for example, 65536 or 64 KB) save storage but increase I/O per query. |
|
When the row store is used
The optimizer routes queries to the row store in two scenarios.
High-concurrency primary key point queries
The following conditions must be met:
-
The table uses the Unique Key model with Merge-on-Write (MOW), enabled by setting
enable_unique_key_merge_on_write = trueat table creation. -
The row store is enabled by setting
store_row_column = trueor by specifying columns inrow_store_columns. -
The WHERE clause contains AND-connected equality conditions on all primary key columns. Example:
SELECT * FROM tbl WHERE k1 = 1 AND k2 = 2.
If a query requests columns not in the row store (when using row_store_columns), those columns are fetched from columnar storage. Check the EXPLAIN plan for the SHORT-CIRCUIT flag to verify this optimization. High-Concurrency Point Queries.
General SELECT * queries
The following conditions must be met:
-
The table uses the Duplicate Key model or the Unique Key model (MOW table).
-
The row store is enabled for all columns (
store_row_column = true). -
The query is a
SELECT *statement withORDER BYandLIMITclauses, which triggers late materialization.
Example:
SELECT * FROM tbl WHERE k < 10 ORDER BY k LIMIT 10;
Check the EXPLAIN plan for FETCH ROW STORE and OPT TWO PHASE markers to confirm row store usage.
Analytical queries such as aggregations and range scans continue to use columnar storage.
Examples
Row store properties are set during table creation and cannot be modified later.
Enable full row store
Store all columns in row format. Ideal for high-concurrency SELECT * point queries.
CREATE TABLE user_profile (
user_id BIGINT,
user_name VARCHAR(64),
age INT,
city VARCHAR(32),
register_date DATE
)
UNIQUE KEY(user_id)
DISTRIBUTED BY HASH(user_id) BUCKETS 16
PROPERTIES (
"store_row_column" = "true",
"enable_unique_key_merge_on_write" = "true"
);
Enable partial row store
Store only frequently queried columns in row format to balance performance and storage.
CREATE TABLE order_info (
order_id BIGINT,
user_id BIGINT,
amount DECIMAL(12, 2),
status INT,
create_time DATETIME,
detail VARCHAR(1024)
)
UNIQUE KEY(order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 32
PROPERTIES (
"row_store_columns" = "user_id,amount,status,create_time",
"enable_unique_key_merge_on_write" = "true"
);
Adjust row store page size
For wide tables, increase row_store_page_size to reduce page count and improve read efficiency.
CREATE TABLE wide_table (
id BIGINT,
col1 VARCHAR(256),
col2 VARCHAR(256),
col3 VARCHAR(256)
)
UNIQUE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 8
PROPERTIES (
"store_row_column" = "true",
"row_store_page_size" = "65536",
"enable_unique_key_merge_on_write" = "true"
);
Usage notes
-
Enabling the row store increases storage by 2x–4x in typical scenarios. Test with your actual data to determine the exact overhead.
-
The
row_store_page_sizeparameter also affects storage. Balance point query performance against storage cost based on your requirements. -
To reduce storage overhead, use
row_store_columnsto store only the columns that need row-format access. -
Row store properties are set during table creation and cannot be modified later.