跳到主要内容
版本: 最新版本-3.5

混合行-列存储

作为一款 OLAP 数据库,StarRocks 最初以列式存储方式存储数据,这可以增强复杂查询(例如聚合查询)的性能。从 v3.2.3 版本开始,StarRocks 也支持使用混合行-列存储来存储数据,数据以逐行和逐列两种方式存储。这种混合行-列存储非常适合各种场景,例如基于主键的高并发、低延迟的点查询和部分列更新,同时提供与列式存储相当的高效分析能力。此外,混合行-列存储支持预处理语句,这提高了查询性能和安全性。

列式存储与混合行-列存储之间的比较

混合行-列存储

  • 存储方式:数据以逐行和逐列两种方式存储。简单来说,使用混合行-列存储的表包含一个额外的、隐藏的二进制类型列 __row。当数据写入表时,来自每个涉及行的值列的所有值都会被编码并写入 __row 列(如下所示)。由于数据以逐行和逐列两种方式存储,因此会产生额外的存储成本。

    img

  • 应用场景:支持行式和列式存储的用户场景,但会产生额外的存储成本。

    • 行式存储的用户场景
      • 基于主键的高并发点查询。
      • 针对由少量字段组成的表的大多数字段的查询。
      • 部分列更新(更具体地说,需要更新多个列和少量数据行)
    • 列式存储的用户场景:复杂数据分析。

面向列

  • 存储方式:数据以逐列方式存储。

    img

  • 应用场景:复杂数据分析。

    • 对海量数据集进行复杂的查询和分析,例如聚合分析和多表连接查询。
    • 表由许多字段组成(例如宽表),但针对这些表的查询只涉及少数几列。

基本用法

创建使用混合行-列存储的表

  1. 启用 FE 配置项 enable_experimental_rowstore

    ADMIN SET FRONTEND CONFIG ("enable_experimental_rowstore" = "true");
  2. 在创建表时在 PROPERTIES 中指定 "STORE_TYPE" = "column_with_row"

注意
  • 该表必须是主键表。
  • __row 列的长度不能超过 1 MB。
  • 自 v3.2.4 起,StarRocks 扩展支持以下列类型:BITMAP、HLL、JSON、ARRAY、MAP 和 STRUCT。
CREATE TABLE users (
id bigint not null,
country string,
city string,
revenue bigint
)
PRIMARY KEY (id)
DISTRIBUTED by HASH (id)
PROPERTIES ("store_type" = "column_with_row");

插入、删除和更新数据

与使用列式存储的表类似,您可以通过数据加载和 DML 语句在使用了混合行-列存储的表上插入、删除和更新数据。本节演示如何在上述具有混合行-列存储的表上运行 DML 语句。

  1. 插入数据行。

    1. INSERT INTO users (id, country, city, revenue)
      VALUES
      (1, 'USA', 'New York', 5000),
      (2, 'UK', 'London', 4500),
      (3, 'France', 'Paris', 6000),
      (4, 'Germany', 'Berlin', 4000),
      (5, 'Japan', 'Tokyo', 7000),
      (6, 'Australia', 'Sydney', 7500);
  2. 删除数据行。

    DELETE FROM users WHERE id = 6;
  3. 更新数据行。

    UPDATE users SET revenue = 6500 WHERE id = 4;

查询数据

本节以点查询为例。点查询采用短路,直接查询行存储中的数据,可以提高查询性能。

以下示例仍然使用上述具有混合行-列存储的表。经过上述表创建和数据修改操作后,表存储的数据如下

MySQL [example_db]> SELECT * FROM users ORDER BY id;
+------+---------+----------+---------+
| id | country | city | revenue |
+------+---------+----------+---------+
| 1 | USA | New York | 5000 |
| 2 | UK | London | 4500 |
| 3 | France | Paris | 6000 |
| 4 | Germany | Berlin | 6500 |
| 5 | Japan | Tokyo | 7000 |
+------+---------+----------+---------+
5 rows in set (0.03 sec)
  1. 确保系统启用查询的短路功能。一旦启用查询的短路功能,满足某些标准(以评估查询是否为点查询)的查询将采用短路来扫描面向行的存储中的数据。

    SHOW VARIABLES LIKE '%enable_short_circuit%';

    如果未启用查询的短路功能,请运行 SET enable_short_circuit = true; 命令将变量 enable_short_circuit 设置为 true

  2. 查询数据。如果查询满足以下标准:WHERE 子句中的条件列包括所有主键列,并且 WHERE 子句中的运算符为 =IN,则查询采用短路。

    注意

    WHERE 子句中的条件列可以包括超出所有主键列的额外列。

    SELECT * FROM users WHERE id=1;
  3. 检查查询计划以验证查询是否可以使用短路。如果查询计划包含 Short Circuit Scan: true,则查询可以采用短路。

    MySQL [example_db]> EXPLAIN SELECT * FROM users WHERE id=1;
    +---------------------------------------------------------+
    | Explain String |
    +---------------------------------------------------------+
    | PLAN FRAGMENT 0 |
    | OUTPUT EXPRS:1: id | 2: country | 3: city | 4: revenue |
    | PARTITION: RANDOM |
    | |
    | RESULT SINK |
    | |
    | 0:OlapScanNode |
    | TABLE: users |
    | PREAGGREGATION: OFF. Reason: null |
    | PREDICATES: 1: id = 1 |
    | partitions=1/1 |
    | rollup: users |
    | tabletRatio=1/6 |
    | tabletList=10184 |
    | cardinality=-1 |
    | avgRowSize=0.0 |
    | Short Circuit Scan: true | -- The query can use the shortcut.
    +---------------------------------------------------------+
    17 rows in set (0.00 sec)

使用预处理语句

您可以使用预处理语句查询具有混合行-列存储的表中的数据。

-- Prepare the statements for execution.
PREPARE select_all_stmt FROM 'SELECT * FROM users';
PREPARE select_by_id_stmt FROM 'SELECT * FROM users WHERE id = ?';

-- Declare variables in the statements.
SET @id1 = 1, @id2 = 2;

-- Use the declared variables to execute the statements.
-- Query data with ID 1 or 2 separately.
EXECUTE select_by_id_stmt USING @id1;
EXECUTE select_by_id_stmt USING @id2;

限制

  • 目前,StarRocks 共享数据集群不支持混合行-列存储。
  • 自 v3.2.4 起,可以使用ALTER TABLE 修改具有混合行-列存储的表。
  • 查询的短路目前仅适用于计划批数据加载后发生的查询。由于在数据写入过程的应用阶段发生查询短路时可能会产生索引互斥,因此数据写入可能会阻止查询短路,从而影响数据写入期间点查询的响应时间。
  • 混合行-列存储可能会显着增加存储消耗。这是因为数据以行和列格式存储,并且行存储的数据压缩率可能不如列存储。
  • 混合行-列存储可能会增加数据加载期间的时间和资源消耗。
  • 具有混合行-列存储的表可以作为在线服务的可行解决方案,但这种类型的表的性能可能无法与成熟的 OLTP 数据库竞争。
  • 具有混合行-列存储的表不支持依赖列式存储的功能,例如列模式下的部分更新。
  • 具有混合行-列存储的表必须是主键表。