本文将指导您如何创建列存表,并详细介绍建表时常见的约束、属性配置方法及实用示例。
适用场景
本文适用于需要在列存引擎中创建新表的用户,尤其适合以下场景:
新建用于在线分析的列存表。
新建带主键以支持精确查询的列存表。
为离线分析场景创建仅依赖 Base 层的列存表,以优化写入性能。
前置准备
在开始创建列存表前,请确保满足以下条件:
使用列存引擎的 SQL 连接地址。如何查看列存引擎的连接地址,请参考 使用MySQL客户端访问列存引擎。
已具备在目标库中创建表的权限。
已规划好表的字段类型和分区策略。
快速开始
下面是一个最基础的列存表示例,它创建了一个非主键表,并按 device_id 进行了哈希分区。
CREATE TABLE IF NOT EXISTS sensor_data (
device_id VARCHAR NOT NULL,
region VARCHAR NOT NULL,
ts TIMESTAMP NOT NULL,
temperature DECIMAL(15, 2),
humidity BIGINT
)
PARTITION BY LIST(`bucket`(100, device_id));
语法说明
建表语法
create_table_statement :: = CREATE TABLE [IF NOT EXISTS] table_name
'('
column_definition,
(',' column_definition )*
[',' PRIMARY KEY '(' pk_list ')']
')'
PARTITION BY LIST '(' part_list ')'
[ WITH '(' table_options ')' ]
column_definition ::= column_name data_type [NOT NULL]
pk_list ::= column_name [, column_name ...]
part_expr ::= `bucket`(bucket_num, column_name)
| `identity`(column_name)
| `year`(column_name)
| `month`(column_name)
| `day`(column_name)
| `hour`(column_name)
table_options ::= attr_def [, attr_def ...]
attr_def ::= `attr_name` = 'attr_value'
语法要点
PRIMARY KEY (...):可选。不指定时,表示创建非主键表。PARTITION BY LIST (...):必选。用于指定 Base 层的分区规则。WITH (...):可选。用于设置表属性,例如关闭 Delta 层或调整文件配置。格式要求:表属性名使用反引号
` `包裹,属性值使用单引号' '包裹。
字段类型
支持的数据类型,请参考数据类型。
分区函数
支持以下分区函数:
分区函数 | 说明 | 适用列类型 |
| 对指定列做哈希分桶, | 任何类型,建议高基数列。 |
| 按字段原值分区。 |
|
| 按年分区。 |
|
| 按月分区。 |
|
| 按天分区。 |
|
| 按小时分区。 |
|
分区字段选择建议
优先选择高基数列:例如用户ID、设备ID等,作为分区字段,这有利于数据打散和负载均衡。
主键表约束:如果创建的是主键表,分区键必须来自主键列。
时间维度查询:如果查询常按时间范围过滤,可优先考虑使用
year、month、day、hour等时间分区函数。分区函数需要用反引号
` `包裹。
表属性
您可以通过 WITH (...) 子句为列存表设置特定的属性。
写法示例:
WITH (
`column.engine.delta_store.memstore.skip_write.enabled` = 'true',
`column.engine.delta_store.query.enabled` = 'false'
)Delta 层相关属性
Delta 层用于承接实时写入与查询。如果业务对数据新鲜度要求高,请保留 Delta 层;如果主要是离线分析,可关闭 Delta 层以提高写入效率。
属性名 | 是否可选 | 默认值 | 说明 |
| 可选 | 基于引擎类型自动判断 | 引擎类型。通常使用列存连接地址时,默认值为 COLUMN。 |
| 可选 | false | 是否跳过 Delta 层。false 表示写入 Delta 层,实时性更高;true 表示不写 Delta 层。 |
| 可选 | true | 是否查询 Delta 层。只有在数据写入 Delta 层时,查询 Delta 层才有意义。 |
| 可选 | 600000 | Delta 层数据 Dump 到 Base 层的时间周期,单位为毫秒,默认 10 分钟。 |
| 可选 | 5 * 节点数量 | Delta 层数据的分区数。数据在经过 PARTITION BY 分区后,还会再做一次哈希拆分,便于 Delta 层管理。 |
配置建议:
实时场景:要求“写入后尽快可查”,建议保留默认配置。
离线场景:对数据新鲜度无要求,建议建表时显式关闭 Delta 层,以减少开销、提升写入效率:
WITH ( `column.engine.delta_store.memstore.skip_write.enabled` = 'true', `column.engine.delta_store.query.enabled` = 'false' )
数据文件与快照相关属性
用于控制底层数据文件的格式、压缩方式和快照保留策略。
属性名 | 是否可选 | 默认值 | 说明 |
| 可选 |
| 数据文件格式,支持 |
| 可选 |
| 压缩算法,支持 |
| 可选 |
| Parquet Row Group 大小(字节),默认 128 MB。 |
| 可选 |
| 目标数据文件大小(字节),默认 512 MB。 |
| 可选 |
| 最少保留的快照数量。 |
| 可选 |
| 快照最大保留时间(毫秒),默认 1 小时。 |
配置建议:
对于复杂的 ETL 任务,或对底层 Snapshot 文件有较强依赖的场景(例如数据管道中某个步骤依赖上一个快照),建议将 column.engine.lce.history.expire.max-snapshot-age-ms 配置得更长一些,例如设置为 6 小时:
WITH (
`column.engine.lce.history.expire.max-snapshot-age-ms` = '21600000'
)查看表结构
使用 DESCRIBE 或 DESC 命令查看表的字段定义:
DESCRIBE TABLE tableName;
-- 或简写为
DESC tableName;查看表属性
使用 SHOW TABLE VARIABLES 命令查看表的属性:
-- 查看所有属性
SHOW TABLE VARIABLES FROM tableName;
-- 按条件过滤,例如查看分区规则
SHOW TABLE VARIABLES FROM tableName LIKE 'PARTITION_KEY';
-- 查看以 'column.engine' 开头的所有已设置属性
SHOW TABLE VARIABLES FROM tableName LIKE 'column.engine%';
示例
示例一:创建销售订单主键表
电商或零售场景中,销售订单表通常需要按订单 ID 精确查询,适合建立主键表。
CREATE TABLE IF NOT EXISTS order_detail (
order_id VARCHAR NOT NULL,
user_id VARCHAR NOT NULL,
created_at TIMESTAMP NOT NULL,
product_id VARCHAR,
category VARCHAR,
quantity BIGINT,
amount DECIMAL(15, 2),
status VARCHAR,
PRIMARY KEY(order_id, user_id, created_at)
)
PARTITION BY LIST(`bucket`(100, order_id));该表以 order_id、user_id 和 created_at 作为联合主键。分区键 order_id 属于主键列,满足约束。
示例二:创建设备测量数据非主键表
物联网场景中,设备持续上报传感器测量数据,写入量大、主要用于聚合分析,适合建立非主键表。
CREATE TABLE IF NOT EXISTS measurement (
device_id VARCHAR NOT NULL,
region VARCHAR NOT NULL,
ts TIMESTAMP NOT NULL,
metric VARCHAR NOT NULL,
value DOUBLE,
unit VARCHAR
)
PARTITION BY LIST(`bucket`(100, device_id));该表未定义主键,适合以聚合分析为主的场景。按 device_id 分区有助于数据打散和均衡负载。
示例三:创建离线分析场景的销售汇总表
数仓场景中,销售汇总数据通常通过批量 ETL 写入,对实时性没有要求,可以关闭 Delta 层以提升写入效率。
CREATE TABLE IF NOT EXISTS sale_summary (
shop_id VARCHAR NOT NULL,
region VARCHAR NOT NULL,
sale_date DATE NOT NULL,
category VARCHAR NOT NULL,
total_sales DECIMAL(15, 2),
order_count BIGINT,
return_rate DOUBLE
)
PARTITION BY LIST(`bucket`(50, shop_id), `day`(sale_date))
WITH (
`column.engine.delta_store.memstore.skip_write.enabled` = 'true',
`column.engine.delta_store.query.enabled` = 'false'
);该表使用组合分区(店铺ID哈希 + 日期),并通过 WITH 子句关闭了 Delta 层的读写,优化了批量写入性能。