最佳实践

1 建表

1.1 数据模型选择

Doris 数据模型上目前分为三类: AGGREGATE KEY, UNIQUE KEY, DUPLICATE KEY。三种模型中数据都是按KEY进行排序。

1.1.1 AGGREGATE KEY

  1. AGGREGATE KEY相同时,新旧记录进行聚合,目前支持的聚合函数有SUM, MIN, MAX, REPLACE
  2. AGGREGATE KEY模型可以提前聚合数据, 适合报表和多维分析业务。
  3. ```
  4. CREATE TABLE site_visit
  5. (
  6. siteid INT,
  7. city SMALLINT,
  8. username VARCHAR(32),
  9. pv BIGINT SUM DEFAULT '0'
  10. )
  11. AGGREGATE KEY(siteid, city, username)
  12. DISTRIBUTED BY HASH(siteid) BUCKETS 10;
  13. ```

1.1.2. UNIQUE KEY

  1. UNIQUE KEY 相同时,新记录覆盖旧记录。目前 UNIQUE KEY 实现上和 AGGREGATE KEY REPLACE 聚合方法一样,二者本质上相同。适用于有更新需求的分析业务。
  2. ```
  3. CREATE TABLE sales_order
  4. (
  5. orderid BIGINT,
  6. status TINYINT,
  7. username VARCHAR(32),
  8. amount BIGINT DEFAULT '0'
  9. )
  10. UNIQUE KEY(orderid)
  11. DISTRIBUTED BY HASH(orderid) BUCKETS 10;
  12. ```

1.1.3. DUPLICATE KEY

  1. 只指定排序列,相同的行不会合并。适用于数据无需提前聚合的分析业务。
  2. ```
  3. CREATE TABLE session_data
  4. (
  5. visitorid SMALLINT,
  6. sessionid BIGINT,
  7. visittime DATETIME,
  8. city CHAR(20),
  9. province CHAR(20),
  10. ip varchar(32),
  11. brower CHAR(20),
  12. url VARCHAR(1024)
  13. )
  14. DUPLICATE KEY(visitorid, sessionid)
  15. DISTRIBUTED BY HASH(sessionid, visitorid) BUCKETS 10;
  16. ```

1.2 大宽表与 Star Schema

业务方建表时, 为了和前端业务适配, 往往不对维度信息和指标信息加以区分, 而将 Schema 定义成大宽表。对于 Doris 而言, 这类大宽表往往性能不尽如人意:

  • Schema 中字段数比较多, 聚合模型中可能 key 列比较多, 导入过程中需要排序的列会增加。
  • 维度信息更新会反应到整张表中,而更新的频率直接影响查询的效率。

使用过程中,建议用户尽量使用 Star Schema 区分维度表和指标表。频繁更新的维度表也可以放在 MySQL 外部表中。而如果只有少量更新, 可以直接放在 Doris 中。在 Doris 中存储维度表时,可对维度表设置更多的副本,提升 Join 的性能。

1.3 分区和分桶

Doris 支持两级分区存储, 第一层为 RANGE 分区(partition), 第二层为 HASH 分桶(bucket)。

1.3.1. RANGE分区(partition)

  1. RANGE分区用于将数据划分成不同区间, 逻辑上可以理解为将原始表划分成了多个子表。业务上,多数用户会选择采用按时间进行partition, 让时间进行partition有以下好处:
  2. * 可区分冷热数据
  3. * 可用上Doris分级存储(SSD + SATA)的功能
  4. * 按分区删除数据时,更加迅速

1.3.2. HASH分桶(bucket)

  1. 根据hash值将数据划分成不同的 bucket
  2. * 建议采用区分度大的列做分桶, 避免出现数据倾斜
  3. * 为方便数据恢复, 建议单个 bucket size 不要太大, 保持在 10GB 以内, 所以建表或增加 partition 时请合理考虑 bucket 数目, 其中不同 partition 可指定不同的 buckets 数。

1.4 稀疏索引和 Bloom Filter

Doris对数据进行有序存储, 在数据有序的基础上为其建立稀疏索引,索引粒度为 block(1024行)。

稀疏索引选取 schema 中固定长度的前缀作为索引内容, 目前 Doris 选取 36 个字节的前缀作为索引。

  • 建表时建议将查询中常见的过滤字段放在 Schema 的前面, 区分度越大,频次越高的查询字段越往前放。
  • 这其中有一个特殊的地方,就是 varchar 类型的字段。varchar 类型字段只能作为稀疏索引的最后一个字段。索引会在 varchar 处截断, 因此 varchar 如果出现在前面,可能索引的长度可能不足 36 个字节。具体可以参阅 数据模型、ROLLUP 及前缀索引
  • 除稀疏索引之外, Doris还提供bloomfilter索引, bloomfilter索引对区分度比较大的列过滤效果明显。 如果考虑到varchar不能放在稀疏索引中, 可以建立bloomfilter索引。

1.5 物化视图(rollup)

Rollup 本质上可以理解为原始表(Base Table)的一个物化索引。建立 Rollup 时可只选取 Base Table 中的部分列作为 Schema。Schema 中的字段顺序也可与 Base Table 不同。

下列情形可以考虑建立 Rollup:

1.5.1. Base Table 中数据聚合度不高。

这一般是因 Base Table 有区分度比较大的字段而导致。此时可以考虑选取部分列,建立 Rollup。

如对于 site_visit 表:

  1. site_visit(siteid, city, username, pv)

siteid 可能导致数据聚合度不高,如果业务方经常根据城市统计pv需求,可以建立一个只有 city, pv 的 Rollup:

  1. ALTER TABLE site_visit ADD ROLLUP rollup_city(city, pv);

1.5.2. Base Table 中的前缀索引无法命中

这一般是 Base Table 的建表方式无法覆盖所有的查询模式。此时可以考虑调整列顺序,建立 Rollup。

如对于 session_data 表:

  1. session_data(visitorid, sessionid, visittime, city, province, ip, brower, url)

如果除了通过 visitorid 分析访问情况外,还有通过 brower, province 分析的情形,可以单独建立 Rollup。

  1. ALTER TABLE session_data ADD ROLLUP rollup_brower(brower,province,ip,url) DUPLICATE KEY(brower,province);

2 Schema Change

Doris中目前进行 Schema Change 的方式有三种:Sorted Schema Change,Direct Schema Change, Linked Schema Change。

2.1. Sorted Schema Change

  1. 改变了列的排序方式,需对数据进行重新排序。例如删除排序列中的一列, 字段重排序。
  2. ```
  3. ALTER TABLE site_visit DROP COLUMN city;
  4. ```

2.2. Direct Schema Change: 无需重新排序,但是需要对数据做一次转换。例如修改列的类型,在稀疏索引中加一列等。

  1. ```
  2. ALTER TABLE site_visit MODIFY COLUMN username varchar(64);
  3. ```

2.3. Linked Schema Change: 无需转换数据,直接完成。例如加列操作。

  1. ```
  2. ALTER TABLE site_visit ADD COLUMN click bigint SUM default '0';
  3. ```

建表时建议考虑好 Schema,这样在进行 Schema Change 时可以加快速度。