-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13515 from Yulei-Yang/master
完成数据开发->建表模块的更新
- Loading branch information
Showing
4 changed files
with
853 additions
and
645 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# 数据分布和副本 | ||
|
||
## 数据分片 | ||
|
||
Doris 表按两层结构进行数据划分,分别是分区和分桶。示意如下: | ||
 | ||
|
||
每个分桶文件就是一个数据分片(Tablet),Tablet是数据划分的最小**逻辑**单元。每个 Tablet 包含若干数据行。各个 Tablet 之间的数据没有交集,并且在物理上是独立存储的。 | ||
|
||
一个 Tablet 只属于一个 Partition,相应的多个 Tablet 在逻辑上归属于不同的分区(Partition)。而一个 Partition 包含若干个 Tablet。因为 Tablet 在物理上是独立存储的,所以可以视为 Partition 在物理上也是独立。Tablet 是数据移动、复制等操作的最小物理存储单元。 | ||
|
||
|
||
## 副本 | ||
|
||
为了提高保存数据的可靠性和计算时的性能,Doris对每个表复制多份进行存储。数据的每份复制就叫做一个副本。Doris按Tablet为基本单元对数据进行副本存储,默认一个分片有3个副本。建表时可在PROPERTIES中设置副本的数量: | ||
```sql | ||
PROPERTIES | ||
( | ||
"replication_num" = "3" | ||
); | ||
``` | ||
|
||
|
||
下图示例,有两个表分别导入Doris,表1 导入后按 3 副本存储,表2 导入后按 2 副本存储。 | ||
 | ||
|
||
**关于副本** | ||
- 每个 分片 的副本数量默认为3,建议保持默认即可。在建表语句中,所有 Partition 中的 Tablet 副本数量统一指定。而在增加新分区时,可以单独指定新分区中分片的副本数量。 | ||
- 最大副本数量取决于集群中部署BE服务的独立 IP 的数量(注意不是 BE 数量)。Doris 中副本分布的原则是:不允许同一个 Tablet 的副本分布在同一台物理机上,而识别物理机即通过 IP。所以,即使在同一台物理机上部署了 3 个或更多 BE 实例,如果这些 BE 的 IP 相同,则依然只能设置副本数为 1。 | ||
- 副本数量可以在运行时修改。 | ||
- 副本数量强烈建议保持为奇数。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# 索引、排序列和前缀索引 | ||
|
||
## 索引 | ||
|
||
Doris 支持比较丰富的索引结构来减少数据的扫描和提高查询效率,目前支持的索引类型有: | ||
|
||
- Sorted Compound Key Index,可以最多指定三个列组成复合排序键,通过该索引,能够有效进行数据裁剪,从而能够更好支持高并发的报表场景 | ||
|
||
- Z-order Index :可以高效对数据模型中的任意字段组合进行范围查询 | ||
|
||
- Min/Max :有效过滤数值类型的等值和范围查询 | ||
|
||
- Bloom Filter :对高基数列的等值过滤裁剪非常有效 | ||
|
||
- Invert Index :能够对任意字段实现快速检索 | ||
|
||
|
||
不同于传统的数据库设计,Doris 不支持在任意列上创建索引。Doris 这类 MPP 架构的 OLAP 数据库,通常都是通过提高并发来处理大量数据的。 | ||
|
||
## 排序列(Sort Key) | ||
|
||
为了提高查询性能,Doris优化了数据存储的组织结构。本质上,Doris 的数据存储在类似 SSTable(Sorted String Table)的数据结构中。该结构是一种有序的数据结构,可以按照指定的列进行排序存储(可以是一列或者多列),这些列即称为排序列。在这种数据结构上,以排序列作为条件进行查找,会非常的高效。 | ||
|
||
在 Aggregate、Unique 和 Duplicate 三种数据模型中。底层的数据存储,是按照各自建表语句中,AGGREGATE KEY、UNIQUE KEY 和 DUPLICATE KEY 中指定的列进行排序存储的。Rollup 可以指定自己的排序列,但排序列必须是 Rollup 列顺序的前缀。 | ||
|
||
**注意** | ||
|
||
- 在建表语句中的列定义中,排序列的定义必须出现在其他列的定义之前。 | ||
- 排序列的顺序是由create table语句中的列顺序决定的。 | ||
|
||
## 前缀索引 | ||
|
||
即在排序的数据结构(SSTable)基础上,实现的一种根据给定前缀列,快速查询数据的索引方式。对于能使用上排序结构的查询,Doris采用二分查找算法定位到目标数据的区间。但如果表中数据行数很多,直接对排序列进行二分查找需要把所有filter列的数据都加载到内存中,这会消耗大量内存空间。为优化这个细节,Doris在Sort Key的基础上引入稀疏的Shortkey Index(前缀索引),Sortkey Index的内容会比数据量少1024倍(Doris把每 1024 行数据组成一个逻辑数据块 (称作Data Block),每个Data Block在前缀索引中存储一行索引),因此会全量缓存在内存中,实际查找的过程中可以有效加速查询。 | ||
|
||
当Sort Key列数非常多时,会占用大量内存,为了性能考虑,对前缀索引项做了限制: | ||
- 最多可选取 3 列作为Shortkey 列; | ||
- 不能使用 FLOAT / DOUBLE 类型的列; | ||
- 只能按排序键的顺序来构造前缀索引 | ||
- VARCHAR / CHAR 类型列只能出现一次,并且只能是最后位置; | ||
- 所有列字节数不超过36字节,VARCHAR / CHAR列按剩余字节数折断; | ||
- 当用户在建表语句中指定short_key属性时,例如"short_key" = "4"指定4个列作为short_key, 可突破上述限制; | ||
|
||
我们举例说明: | ||
|
||
### 示例 | ||
|
||
1. 以下表结构的前缀索引为 user_id(8 Bytes) + age(4 Bytes) + message(prefix 20 Bytes)。 | ||
|
||
| ColumnName | Type | | ||
| -------------- | ------------ | | ||
| user_id | BIGINT | | ||
| age | INT | | ||
| message | VARCHAR(100) | | ||
| max_dwell_time | DATETIME | | ||
| min_dwell_time | DATETIME | | ||
|
||
2. 以下表结构的前缀索引为 user_name(20 Bytes)。即使没有达到 36 个字节,因为遇到 VARCHAR,所以直接截断,不再往后继续。 | ||
|
||
| ColumnName | Type | | ||
| -------------- | ------------ | | ||
| user_name | VARCHAR(20) | | ||
| age | INT | | ||
| message | VARCHAR(100) | | ||
| max_dwell_time | DATETIME | | ||
| min_dwell_time | DATETIME | | ||
|
||
当我们的查询条件是**前缀索引的前缀**时,可以极大的加快查询速度。比如在第一个例子中,我们执行如下查询: | ||
|
||
```sql | ||
SELECT * FROM table WHERE user_id=1829239 and age=20; | ||
``` | ||
|
||
该查询的效率会**远高于**如下查询: | ||
|
||
```sql | ||
SELECT * FROM table WHERE age=20; | ||
``` | ||
|
||
所以在建表时,**正确的选择列顺序,能够极大地提高查询效率**。 | ||
|
||
### 最佳实践 | ||
|
||
- **通过ROLLUP来调整前缀索引** | ||
|
||
因为建表时已经指定了列顺序,所以一个表只有一种前缀索引。这对于使用其他不能命中前缀索引的列作为条件进行的查询来说,效率上可能无法满足需求。因此,我们可以通过创建 ROLLUP 来人为的调整列顺序。 | ||
|
||
- **优化排序列的先后顺序来提高查询性能** | ||
|
||
当Sort Key涉及多个列的时候,谁先谁后也有讲究,区分度高、经常查询的列建议放在前面。 | ||
|
||
- **注意排序列的数量** | ||
|
||
1. 如果选择了大量的列用于排序列,那么数据导入时排序的开销会增大整个导入过程的耗时; | ||
2. 设计良好的少量排序列也能快速定位到数据行所在的位置,增加更多列进行排序也不会带来查询的提升 |
Oops, something went wrong.