You need to enable JavaScript to run this app.
导航

行存表使用指南

最近更新时间2024.02.18 19:02:34

首次发布时间2024.01.15 15:06:50

1 语法说明

1.1 DDL语法

  • 建表语句
CREATE TABLE [IF NOT EXISTS] [database.]table_name
(column_definition1[, column_definition2, ...])
ENGINE = ROW_STORE
PRIMARY KEY(column1[, column2]);

行存建表语句和普通StarRocks表相似, 主要通过`ENGINE = ROW_STORE`来指明是否为行存表.

column_definition参数说明:

col_name col_type [NULL | NOT NULL] [DEFAULT "default_value"]

其中:

  • col_name:列名称

  • col_type:列数据类型

支持的列类型信息如下:

类型描述说明
整型类INT、LARGEINT用于主键Key和Value字段
TINYINT、SMALLINT、BIGINT仅用于Value字段
浮点类FLOAT、DOUBLE、DECIMAL仅用于Value字段
日期类DATE用于主键Key和Value字段
DATETIME仅用于Value字段
字符串类VARCHAR用于主键Key和Value字段
CHAR仅用于Value字段
Boolean类型BOOLEAN用于主键Key和Value字段

说明

  1. 行存表并不支持分区表和分桶, 因此建表语句中不能含有分区和分桶的信息。
  2. 行存表默认3副本,不支持指定具体副本个数, 因此建表语句没有Properties字段。
  • 删表语句
DROP TABLE [IF EXISTS] [database.]table_name [FORCE]

行存表的删除,不支持回收站功能,因此执行删除表的SQL后,会清除对应的数据,且无法恢复。
在SQL语句中指定FORCE会等待数据删除完才会结束; 不指定FORCE,则采用异步删除逻辑。

  • 数据变更
-- 添加列
ALTER TABLE [database.]table ADD COLUMN column_name column_type [DEFAULT "default_value"]

-- 表重名名
ALTER TABLE table_name RENAME new_table_name;

行存表的数据变更行为与列存表不一样,列存表数据变更的时候会重写数据,而行存表并不会重写数据,因此行存表的数据变更非常快。

目前行存表的数据变更只支持两种动作:添加列以及修改表名,添加列也仅只支持在最后一列添加新列。

列存表的一些高级能力,例如二级索引和物化视图等能力,目前在行存表中并未支持,因此Index和Materialed View相关的语法也都未支持。

1.2 DML语法

  • 数据查询语法

行存表询语法基本上同列存表。列存表的相关语法参考StarRocks社区

1.点查询

对于行存表,使用全主键进行查询时,会走短路径对SQL进行优化。
示例

-- 创建表
CREATE DATABASE IF NOT EXISTS demo;
DROP TABLE IF EXISTS demo.t1;
CREATE TABLE IF NOT EXISTS demo.t1 (
    k1 int,
    k2 varchar(16),
    v1 varchar(16) DEFAULT '1',
    v2 DATE NOT NULL DEFAULT '2222-12-12' COMMENT "YYYY-MM-DD",
    v3 TINYINT DEFAULT '0' COMMENT "range [-128, 127]")
ENGINE=ROW_STORE
PRIMARY KEY (k1, k2);

--插入数据
INSERT INTO demo.t1(k1, k2, v1, v2, v3) VALUES (1, '1', 'a', '2222-10-23', 31);
INSERT INTO demo.t1(k1, k2, v1, v2, v3) VALUES (1, '2', 'b', '2222-10-24', 32);
INSERT INTO demo.t1(k1, k2, v1, v2, v3) VALUES (1, '3', 'c', '2222-10-25', 33);
INSERT INTO demo.t1(k1, k2, v1, v2, v3) VALUES (2, '4', 'd', '2222-10-26', 34);


-- 多主键查询: 主键(k1, k2)
SELECT * FROM demo.t1 WHERE k1 = 1 AND k2 = '1';
SELECT * FROM demo.t1 WHERE k1 = 1 AND k2 IN ('1', '2');

-- 通过EXPLAIN查看执行计划,从执行计划可以判断是否走短路读
EXPLAIN SELECT * FROM demo.t1 WHERE k1 = 1 AND k2 IN ('1', '2');

--关闭短路读写能力,查看SQL执行计划
SET enable_short_circuit = false;
EXPLAIN SELECT * FROM demo.t1 WHERE k1 = 1 AND k2 IN ('1', '2');

--开启短路读写能力
SET enable_short_circuit = true;

2.范围查询

在行存表中,对于主键的范围查询也进行了优化,根据主键的范围,计算数据的扫描范围,减少数据的摄取量。
示例
以多主键范围查询为例,也适合于单一主键范围查询。

-- 多主键范围查询: 主键(k1, k2, k3)
SELECT * FROM demo.t1 WHERE k1 = 1 and k2 <= '4';
SELECT * FROM demo.t1 WHERE k1 >= 1 and k2 <= '4';
SELECT * FROM demo.t1 WHERE k1 >= 1 and k2 <= '4' and k2 > '2';

3.全表查询

行存表查询时,也支持非主键的查询功能。
示例

-- 非主键查询
SELECT sum(v3) FROM demo.t1 WHERE v1 = 'a';

SELECT v2 FROM demo.t1 WHERE v1 = 'a' and v3 > 30;

注意

行存表支持全表扫描, 但全表扫描的效率是远远低于列存表的,在数据量大的情况下,容易出现查询超时,因此需要尽量避免行存表出现全表扫描。

  • 数据处理语法

行存表中支持插入、更新、删除操作,语法基本上同列存表。列存表的相关语法参考StarRocks社区

1.插入

-- 支持Insert values
INSERT INTO demo.t1(k1, k2, v1, v2, v3) VALUES (3, '5', 'e', '2222-12-22', 34);

-- 支持Partial insert, 字段列表必须包含全部主键列, 未指明的列会填入默认值或者设置null
INSERT INTO demo.t1(k1, k2, v1) VALUES (4, '6', 'f'),(5, '7', 'g');

-- 支持insert ignore语法, 当出现主键冲突时, 忽略新值, 保留旧值
INSERT IGNORE INTO demo.t1  VALUES (4, '6', 'f1','2222-12-22', 12),(5, '7', 'g1','2222-12-22', 13);
INSERT IGNORE INTO demo.t1(k1, k2, v1) VALUES (4, '6', 'f1'),(5, '7', 'g1');

-- 支持insert duplicate语法, 当出现主键冲突时, 能够按照语法赋值
--- partial insert and upsert
INSERT INTO demo.t1 (k1, k2, v1) VALUES (4, '6', 'f2') AS v ON DUPLICATE KEY UPDATE v1 = v.v1;
--- 常量赋值
INSERT INTO demo.t1 (k1, k2, v1) VALUES (4, '6', 'v1_new') AS v ON DUPLICATE key UPDATE v1 = 'x';
--- 表达式计算
INSERT INTO demo.t1 (k1, k2, v3) VALUES (4, '6', 10) AS v ON DUPLICATE key UPDATE v3 = v.v3 + 1;
--- 使用旧值进行表达式计算
INSERT INTO demo.t1 (k1, k2, v3) VALUES (4, '6', 10) AS v ON DUPLICATE key UPDATE v3 = t1.v3 + 1;

-- 支持Insert select
CREATE TABLE IF NOT EXISTS demo.t1_copy (
    k1 int,
    k2 varchar(16),
    v1 varchar(16) DEFAULT '3',
    v2 DATE NOT NULL DEFAULT '2222-12-12' COMMENT "YYYY-MM-DD",
    v3 TINYINT DEFAULT '0' COMMENT "range [-128, 127]")
ENGINE=ROW_STORE
PRIMARY KEY (k1, k2);
INSERT INTO demo.t1_copy SELECT * FROM demo.t1;

注意

行存表的插入默认语义与列存表保持一致, 默认为upsert语法, 插入时并不检查主键唯一性, 如果主键相同, 则新写入的值覆盖旧值.

2.更新

-- 主键点更新
UPDATE demo.t1 SET v1 = 'value1_new' WHERE k1 = 3 AND k2 = '5';

-- 主键范围更新
UPDATE demo.t1 SET v1 = 'value1_new_2' WHERE k1 = 1 AND k2 > '1' AND k2 <= '5';

-- 非主键大范围更新
UPDATE demo.t1 SET v1 = 'value1_new_3' WHERE v3 > 30 AND v3 < 32;

-- 支持表达式计算
UPDATE demo.t1 SET v3 = v3 + 1 WHERE k1 = 1;

注意

行存表不支持更新时修改主键的值。

3.删除

-- 主键点删除
DELETE FROM demo.t1 WHERE k1 = 3 AND k2 = '5';

-- 主键范围删除
DELETE FROM demo.t1 WHERE k1 = 1 AND k2 > '1' AND k2 <= '5';

-- 非主键删除
DELETE FROM demo.t1 WHERE v3 > 30 AND v3 < 32;

1.3 辅助语法

  • 查询表结构及建表语句

    -- 查询表字段属性
    DESC demo.t1;
    
    -- 展示建表语句
    SHOW CREATE TABLE demo.t1;
    
  • 查询表大小

    SHOW DATA FROM demo.t1;
    

注意

行存表为了性能, 没有对存储大小进行精确统计,使用Show data返回实际数据的近似值。

2 参数配置

行存表参数配置都是Session级参数, 可以通过SET系统变量方式修改配置项的数值

配置项默认值说明用户参数
enable_short_circuittrue短路读写的开关文档呈现
enable_row_store_update_atomictrue行存表更新时, 使用CAS检验原值, 防止行级LostUpdate事务异常出现文档呈现
enable_audit_execute_stmtfalsePreparestmt的执行默认不打印audit日志, 如果需要打印日志, 打开该配置项隐藏
enable_row_store_runtime_filtertrue行存表的RuntimeFilter开关参数隐藏
enable_row_store_push_down_limittrue行存表支持LIMIT的下推开关隐藏
enable_row_store_push_down_topntrue行存表支持TOPN的下推开关隐藏

3 使用示例

3.1 示例一:MySQL Client样例

--创建行存表
CREATE DATABASE IF NOT EXISTS demo;
DROP TABLE IF EXISTS demo.t1;
CREATE TABLE IF NOT EXISTS demo.t1(
    k1 int,
    k2 int,
    v1 varchar(16),
    v2 DATE NOT NULL COMMENT "YYYY-MM-DD",
    v3 TINYINT COMMENT "range [-128, 127]"
) ENGINE=ROW_STORE
PRIMARY KEY (k1, k2);

--插入
INSERT INTO demo.t1(k1, k2, v1, v2, v3) VALUES
     (1, 2, 'a', "2222-12-22", 33),
     (1, 3, 'b', "2222-12-22", 34),
     (1, 4, 'c', "2222-12-22", 35),
     (2, 2, 'd', "2222-12-22", 36),
     (2, 3, 'd', "2222-12-22", 37),
     (3, 3, 'e', "2222-12-22", 100),
     (4, 4, 'f', "2222-12-22", 101);
     
--查询
SELECT count(*) FROM demo.t1;
SELECT * FROM demo.t1 limit 3;
SELECT k2, sum(k1) FROM demo.t1 group by k2;

--更新
update demo.t1 set v1 = '5' where k1 = 3 and k2 = 3;
select * from demo.t1 where k1 = 3 and k2 = 3;

--删除数据
DELETE FROM demo.t1 WHERE k1 = 1 and k2 = 2;
select * from demo.t1 WHERE k1 = 1 and k2 = 2;
DELETE FROM demo.t1 WHERE k1 = 1;
select * from demo.t1 WHERE k1 = 1;

--清空
TRUNCATE TABLE demo.t1;

--drop表
DROP TABLE demo.t1 FORCE;

3.2 示例二:JDBC连接样例

步骤一:创建行存表

CREATE DATABASE IF NOT EXISTS demo;
CREATE TABLE IF NOT EXISTS demo.tbl_point_query(
    `k1` int(11),
    `v1` varchar(30) NULL,
    `v2` decimal(27, 9) NULL
    )
ENGINE=ROW_STORE
PRIMARY KEY (k1);

步骤二:采用Java程序使用PreparedStatement

public static void main(String[] args) throws Exception {
    // 设置 JDBC url,并在 Server 端开启 prepared statement
    String mysqlUrl = "jdbc:mysql://${FE地址}:9030/?useServerPrepStmts=true";
    String mysqlUser = "${mysqlUser}";
    String mysqlPassword = "${mysqlPassword}";

    DriverManager.registerDriver(((java.sql.Driver) Class.forName("com.mysql.cj.jdbc.Driver").getDeclaredConstructor().newInstance()));
    Connection conn = DriverManager.getConnection(mysqlUrl, mysqlUser, mysqlPassword);

    // use `?` for placement holders
    String insertSql = "INSERT INTO demo.tbl_point_query VALUES(?,?,?)";
    PreparedStatement insertPstmt = conn.prepareStatement(insertSql);
    insertPstmt.setInt(1, 1);
    insertPstmt.setString(2, "v1");
    insertPstmt.setBigDecimal(3,  new BigDecimal("123456.12"));
    insertPstmt.execute();


    // use `?` for placement holders
    String selectSql = "SELECT * FROM demo.tbl_point_query where k1 = ?";
    PreparedStatement selectPstmt = conn.prepareStatement(selectSql);

    selectPstmt.setInt(1, 1);
    ResultSet rs = selectPstmt.executeQuery();
    while (rs.next()) {
        System.out.println(String.format("The value of k1: %s, the value of v1: %s,the value of v2: %s",
                rs.getInt(1),rs.getString(2), rs.getBigDecimal(3)));
    }
}

说明

用例中${FE地址}、${mysqlUser}、${mysqlPassword}需要根据实际环境替换

如果您使用的是maven工程,需要在pom.xml文件引入mysql依赖:

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
</dependency>