Doris教程
概述:
Apache Doris Palo由百度研发,MPP
分析型数据库,10PB的数据集
可以实现:固定历史报表
,实时数据分析
,交互式,探索式数据分析
MPP:大规模并行处理
可使用范围:
mysql,oracal这种db产生的数据
后端应用产生的数据
前端,pc或者移动端页面产生的数据
网络事件监听
特点:
1、有自己的一套sql语法,进行大数据分析
2、支持大数据分析引擎,如Flink,Spark等
3、使用ODBC的方式,利用Doris的外表方式将Mysql或es建立映射关系(可直接在doris中操作数据库)
具体可实现功能:
1、最开始的功能是制作报表
2、现在可进行市场营销,金融投资类的分析,广告投放分析等
核心特性:
MPP架构、秒级查询、标准SQL语言兼容Mysql的协议、向量化执行器(高版本添加)、聚合表技术、Rollup可以获取更加粗粒度的结果、三高性能、运维简单
架构:
两种角色,两种进程(这种模式相当于前后端的意思)
大致流程:
fe接收解析调度,be计算结果返回给fe,fe展示给用户
基本架构:
FE(基于Java):
存储、维护集群元数据;负责接收、解析查询请求,规划查询计划,调度查询执行,返回查询结果。主要有三个角色:
Leader
和 Follower
:主要是用来达到元数据的高可用,保证单节点宕机的情况下,元数据能够实时地在线恢复,而不影响整个服务。
Observer
:用来扩展查询节点,同时起到元数据备份的作用。如果在发现集群压力非常大的情况下,需要去扩展整个查询的能力,那么可以加 observer 的节点。observer 不参与任何的写入,只参与读取。
BE(基于C++):
负责物理数据的存储和计算;依据 FE 生成的物理计划,分布式地执行查询。数据的可靠性由 BE 保证,BE 会对整个数据存储多副本或者是三副本。副本数可根据需求动态调整。
MySQL Client:
Doris 借助 MySQL 协议,用户使用任意 MySQL 的 ODBC/JDBC 以及 MySQL 的客户端,都可以直接访问 Doris。
Broker:
主要用于支持 Doris 读写远端存储上的文件和目录。(如:阿里云的oss之类的)
完全不依赖于外部组件
默认端口
实例名称 | 端口名称 | 默认端口 | 通讯方向 | 说明 |
---|---|---|---|---|
BE | be_prot | 9060 | FE-->BE | BE 上 thrift server 的端口 用于接收来自 FE 的请求 |
BE | webserver_port | 8040 | BE<-->FE | BE 上的 http server 端口 |
BE | heartbeat_service_port | 9050 | FE-->BE | BE 上心跳服务端口 用于接收来自 FE 的心跳 |
BE | brpc_prot* | 8060 | FE<-->BE BE<-->BE | BE 上的 brpc 端口 用于 BE 之间通信 |
FE | http_port | 8030 | FE<-->FE 用户<--> FE | FE 上的 http_server 端口 |
FE | rpc_port | 9020 | BE-->FE FE<-->FE | FE 上 thirt server 端口号 |
FE | query_port | 9030 | 用户<--> FE | FE 上的 mysql server 端口 |
FE | edit_log_port | 9010 | FE<-->FE | FE 上 bdbje 之间通信用的端口 |
Broker | broker_ipc_port | 8000 | FE-->BROKER BE-->BROKER | Broker 上的 thrift server 用于接收请求 |
安装
docker安装(官方推荐)
直接编译
安装前系统要求
系统要求
Linux | 版本 |
---|---|
Centos | 7.1及以上 |
Ubuntu | 16.04及以上 |
软件要求
软件 | 版本 |
---|---|
Java | 1.8及以上 |
GCC | 4.8.2及以上 |
开发及测试环境硬件配置需求
模块 | CPU | 内存 | 磁盘 | 网络 | 实例数量 |
---|---|---|---|---|---|
Frontend(FE) | 8核+ | 8GB+ | SSD 或 SATA,10GB+ * | 千兆网卡 | 1 |
Backend(BE) | 8核+ | 16GB+ | SSD 或 SATA,50GB+ * | 千兆网卡 | 1-3 * |
生产环境硬件配置需求
模块 | CPU | 内存 | 磁盘 | 网络 | 实例数量(最低要求) |
---|---|---|---|---|---|
Frontend | 16核+ | 64GB+ | SSD 或 RAID 卡,100GB+ * | 万兆网卡 | 1-5 * |
Backend | 16核+ | 64GB+ | SSD 或 SATA,100G+ * | 万兆网卡 | 10-100 * |
操作系统环境要求
#1.打开文件 vim /etc/security/limits.conf #2.在文件最后添加下面几行信息(注意* 也要复制进去) * soft nofile 65536 * hard nofile 65536 * soft nproc 65536 * hard nproc 65536 ulimit -n 65536 临时生效 #修改完文件后需要重新启动虚拟机 #重启永久生效,也可以用 。 #如果不修改这个句柄数大于等于60000,回头启动doris的be节点的时候就会报如下的错 #如果报错:Please set the maximum number of open file descriptors to be 65536 using 'ulimit -n 65536'. 代表句柄数没有生效,需要临时设置或者重启电脑 #第一次启动的时候可能会报错 Please set vm.max_map_count to be 2000000 under root using 'sysctl -w vm.max_map_count=2000000'. #解决方案: #命令行输入: sysctl -w vm.max_map_count=2000000
设置文件包含限制一个进程可以拥有的VMA(虚拟内存区域)的数量
#临时生效: sysctl -w vm.max_map_count=2000000 #永久剩下 vim /etc/sysctl.conf #在文件最后一行添加 vm.max_map_count=2000000 #让他永久生效 sysctl -p #检查是否生效 sysctl -a|grep vm.max_map_count
时钟同步(云服务器一般无需同步时间,多机部署需做此操作
)
Doris 的元数据要求时间精度要小于5000ms,所以所有集群所有机器要进行时钟同步,避免因为时钟问题引发的元数据不一致导致服务出现异常。
#如何时间同步?? 首先安装 ntpdate # ntpdate是一个向互联网上的时间服务器进行时间同步的软件 yum install ntpdate -y #然后开始三台机器自己同步时间 ntpdate ntp.sjtu.edu.cn 美国标准技术院时间服务器:time.nist.gov(192.43.244.18) 上海交通大学网络中心NTP服务器地址:ntp.sjtu.edu.cn(202.120.2.101) 中国国家授时中心服务器地址:cn.pool.ntp.org(210.72.145.44) # 将当前时间写入bios,这样才能永久生效不变,不然reboot后还会恢复到原来的时间 clock -w
关闭交换分区(swap)
交换分区是linux用来当做虚拟内存用的磁盘分区;
linux可以把一块磁盘分区当做内存来使用(虚拟内存、交换分区);
Linux使用交换分区会给Doris带来很严重的性能问题,建议在安装之前禁用交换分区;
#1、查看 Linux 当前 Swap 分区 free -m #2、关闭 Swap 分区 swapoff -a free -m total used free shared buff/cache available Mem: 5840 997 4176 9 666 4604 Swap: 6015 0 6015 swapoff -a 3.验证是否关闭成功 free -m total used free shared buff/cache available Mem: 5840 933 4235 9 671 4667 Swap: 0 0 0
注意事项:
-
FE 的磁盘空间主要用于存储元数据,包括日志和 image。通常从几百 MB 到几个GB 不等。
-
BE 的磁盘空间主要用于存放用户数据,总磁盘空间按用户总数据量* 3(3 副本)计算,然后再预留额外 40%的空间用作后台 compaction 以及一些中间数据的存放。
-
一台机器上可以部署多个 BE 实例,但是只能部署一个 FE。如果需要 3 副本数 据,那么至少需要 3 台机器各部署一个 BE 实例(而不是 1 台机器部署 3 个 BE 实例)。多 个 FE 所在服务器的时钟必须保持一致(允许最多 5 秒的时钟偏差)
-
测试环境也可以仅适用一个 BE 进行测试。实际生产环境,BE 实例数量直接决定了整体查询延迟。
-
所有部署节点关闭 Swap。
-
FE 节点数据至少为 1(1 个 Follower)。当部署 1 个 Follower 和 1 个 Observer 时,可以实现读高可用。当部署 3 个 Follower 时,可以实现读写高可用(HA)。
-
Follower 的数量必须为奇数,Observer 数量随意。
-
当集群可用性要求很高时(比如提供在线业务),可以部署 3 个Follower 和 1-3 个 Observer。如果是离线业务,建议部署 1 个 Follower 和 1-3 个 Observer。
-
Broker 是用于访问外部数据源(如 HDFS)的进程。通常,在每台机器上部署一个 broker 实例即可。
安装FE和BE(老版本是分开下载)
1、去官网下载源码包,官网地址:Apache Doris: Open source data warehouse for real time data analytics - Apache Doris
根据自己的配置选择性点击下载(avx2指令集和CPU有关,为提升效率,详情请自行查阅
)
当然你也可以选择历史版本下载
2、上传到linux
3、解压
官网下载下来的是gz结尾的,所以解压需要用 tar -zxvf xxx.tar.gz -C 路径名
4、修改FE配置文件
去自己的路劲中找到fe.conf文件 vim /opt/doris/fe/conf/fe.conf(`自己安装的路径`) #配置文件中指定元数据路径 `注意这个文件夹要自己创建` meta_dir = /opt/doris/doris-meta(`自己想要存放的位置`) #修改绑定 ip(每台机器修改成自己的 ip) priority_networks = `自己的ip地址(云服务器填写内网地址)`/24
注意事项:
-
生产环境强烈建议单独指定目录不要放在 Doris 安装目录下,最好是单独的磁盘(如果有SSD最好)
-
如果机器有多个 ip, 比如内网外网, 虚拟机 docker 等, 需要进行 ip 绑定,才能正确识别。
-
JAVA_OPTS 默认 java 最大堆内存为 4GB,建议生产环境调整至 8G 以上。
5、修改BE配置文件
#去自己的路劲中找到be.conf文件 vim /opt/doris/be/conf/be.conf(`自己安装的路径`) #配置文件中指定数据存放路径 `注意这个文件夹要自己创建` storage_root_path = /opt/module/apache-doris-0.15.0/doris•storage1;/opt/module/apache-doris-0.15.0/doris-storage2(`自己所要存放的所有位置,可以为多个,用;隔开,最后一个不要加`) #修改绑定 ip(每台机器修改成自己的 ip) priority_networks = `自己的ip地址(云服务器填写内网地址)`/24
6、启动FE和BE
#进入到fe的bin目录下执行 ./start_fe.sh(`前台启动,第一次推荐前台启动,可能会报错`) ./start_fe.sh --daemon(`后台启动`) #进入be的bin目录下执行 ./start_be.sh(`前台启动,第一次推荐前台启动,可能会报错`) ./start_be.sh --daemon(`后台启动`)
#第一次启动的时候可能会报错 Please set vm.max_map_count to be 2000000 under root using 'sysctl -w vm.max_map_count=2000000'. #解决方案: 命令行输入:sysctl -w vm.max_map_count=2000000 如果报错:Please set the maximum number of open file descriptors to be 65536 using 'ulimit -n 65536'. 解决方案:`临时修改,永久修改看上边` 命令行输入:ulimit -n 65536
7、查看FE和BE是否开启
#FE是否启动 #命令行输入 jps #显示含有下面信息则证明FE启动成功 87965 PaloFe (`数字为进程号,无需关心是否一致`) #BE是否启动 #命令行输入 jps 或 netstat -nltp |grep be #jps命令显示含有下面信息则证明BE启动成功 88553 DorisBE (`数字为进程号,无需关心是否一致`)
如果命令netstat -nltp |grep be,显示以下界面
8、如没有启动查询日志(可选)
#进入FE日志文件夹 cd /opt/doris/fe/log/ #错误日志一般名为 fe.warn.log #进入BE日志文件夹 cd /opt/doris/be/log/ #错误日志一般名为 be.warn.log
注意事项:
-
storage_root_path 默认在 be/storage 下,需要手动创建该目录。多个路径之间使用英文状态的分号;分隔(最后一个目录后不要加)。
-
可以通过路径区别存储目录的介质,HDD 或 SSD。可以添加容量限制在每个路径的末尾,通过英文状态逗号,隔开,如storage_root_path=/home/disk1/doris.HDD,50;/home/disk2/doris.SSD,10;/home/disk2/doris
-
说明:
-
/home/disk1/doris.HDD,50,表示存储限制为 50GB,HDD;
-
/home/disk2/doris.SSD,10,存储限制为 10GB,SSD;
-
/home/disk2/doris,存储限制为磁盘最大容量,默认为 HDD
-
如果机器有多个 IP, 比如内网外网, 虚拟机 docker 等, 需要进行 IP 绑定,才能正确识别。
因为FE和BE两个都是单独的个体,所以他俩相互间还不认识,就需要我们通过mysql的客户端将他们建立起联系
如果没有装mysql的家伙,记得先装mysql(安装教程自行搜索)
使用 MySQL Client 连接 FE
连接FE
#命令行输入 mysql -h 127.0.0.1 -P 9030 -uroot -p (`填写fe节点的IP,默认无密码,如果fe在本机,不写密码,也可登录,必须填写127.0.0.1,如果填写内网地址会报错`) (`注意P的大小写`) #默认root无密码,通过命令行修改root密码 SET PASSWORD FOR 'root' = PASSWORD('******'); #默认admin无密码,通过命令行修改admin密码(admin为http方式登录的用户) SET PASSWORD FOR 'admin' = PASSWORD('******');
查询FE状态
#以表格方式查看 SHOW PROC '/frontends'; #以文本行方式查看 SHOW PROC '/frontends' \G;(`推荐方式`)
表格方式演示
文本行方式演示(注:如果FOLLOWER的IsMaster为true则证明此FOLLOWER是Leader)
添加BE节点
#命令行输入(可多个) ALTER SYSTEM ADD BACKEND "192.168.1.1:9050";(`填写be节点的IP,如果为本机,云服务器必须填写内网地址,否则无效`) ALTER SYSTEM ADD BACKEND "192.168.1.2:9050"; ALTER SYSTEM ADD BACKEND "192.168.1.3:9050";
删除BE节点
#命令行输入 ALTER SYSTEM DECOMMISSION BACKEND "192.168.1.1:9050";
查看BE节点状态
#以表格方式查看 SHOW PROC '/backends'; #以文本行方式查看 show proc '/backends' \G;(`推荐方式`)
表格方式演示
文本行方式演示(注:Alive 为 true 表示该 BE 节点存活)
也可通过Http方式链接FE
在浏览器中输入地址(输入自己IP地址): http://192.168.1.1:8030/ 默认用户名为: admin(老版本默认用户名可能为:root和admin都可) 默认无密码
通过Http界面执行SQL
如果FE已经连接BE,可通过以下方式查看
通过Http页面查看日志
部署 FS_Broker(可选)
基本介绍
Broker 以插件的形式,独立于 Doris 部署。如果需要从第三方存储系统导入数据,需要部署相应的 Broker,默认提供了读取 HDFS、百度云 BOS 及 Amazon S3 的 fs_broker。
fs_broker 是无状态的,建议每一个 FE 和 BE 节点都部署一个 Broker。
1、编译 FS_BROKER 并拷贝文件
(1)进入源码目录下的 fs_brokers 目录,使用 sh build.sh 进行编译
(2)拷贝源码 fs_broker 的 output 目录下的相应Broker目录到需要部署的所有节点上,改名为: apache_hdfs_broker。建议和 BE 或者 FE 目录保持同级。
2、启动 Broker
#进入到所安装的broker目录 如: cd /opt/doris/apache_hdfs_broker/bin ./start_broker.sh --daemon
3、添加 Broker
要让 Doris 的 FE 和 BE 知道 Broker 在哪些节点上,通过 sql 命令添加Broker节点列表。
#使用mysql-client连接启动的 FE,执行以下命令: mysql -h 127.0.0.1 -P 9030 -uroot -p (`填写fe节点的IP,默认无密码,如果fe在本机,不写密码,也可登录,必须填写127.0.0.1,如果填写内网地址会报错`) (`注意P的大小写`) ALTER SYSTEM ADD BROKER broker_name"192.168.1.1:8000","192.168.1.2:8000","192.168.1.3:8000"; (`其中broker_host为Broker所在节点ip;broker_ipc_port在Broker配置文件中的conf/apache_hdfs_broker.conf`)
4、查看 Broker 状态
#使用 mysql-client 连接任一已启动的 FE,执行以下命令查看 Broker 状态: SHOW PROC "/brokers" \G;
注意事项:
-
在生产环境中,所有实例都应使用守护进程启动,以保证进程退出后,会被自动拉起,如Supervisor(opens new window)。
-
如需使用守护进程启动,在 0.9.0 及之前版本中,需要修改各个 start_xx.sh 脚本,去掉最后的 & 符号。
-
从 0.10.0 版本开始,直接调用sh start_xx.sh启动即可。
数据表设计
1、字段类型
字段 | 字节 | 范围 |
---|---|---|
TINYINT | 1 字节 | 范围:-2^7 + 1 ~ 2^7 - 1 |
SMALLINT | 2 字节 | 范围:-2^15 + 1 ~ 2^15 - 1 |
INT | 4 字节 | 范围:-2^31 + 1 ~ 2^31 - 1 |
BIGINT | 8 字节 | 范围:-2^63 + 1 ~ 2^63 - 1 |
LARGEINT | 16 字节 | 范围:-2^127 + 1 ~ 2^127 - 1 |
FLOAT | 4 字节 | 支持科学计数法 |
DOUBLE | 12 字节 | 支持科学计数法 |
DECIMAL[(precision, scale)] | 16 字节 | 保证精度的小数类型。默认是DECIMAL(10, 0) ,precision: 1 ~ 27 ,scale: 0 ~ 9,其中整数部分为 1 ~ 18,不支持科学计数法 |
DATE | 3 字节 | 范围:0000-01-01 ~ 9999-12-31 |
DATETIME | 8 字节 | 范围:0000-01-01 00:00:00 ~ 9999-12-31 23:59:59 |
CHAR[(length)] | 定长字符串。长度范围:1 ~ 255。默认为 1 | |
VARCHAR[(length)] | 变长字符串。长度范围:1 ~ 65533 | |
BOOLEAN | 与 TINYINT 一样,0 代表 false,1 代表 true | |
HLL | 1~16385 个字节 | hll 列类型,不需要指定长度和默认值,长度根据数据的聚合程度系统内控制,并且 HLL 列只能通过 配套的hll_union_agg、Hll_cardinality、hll_hash 进行查询或使用 |
BITMAP | bitmap 列类型,不需要指定长度和默认值。表示整型的集合,元素最大支持到 2^64 - 1 | |
STRING | 变长字符串,0.15 版本支持,最大支持 2147483643 字节(2GB-4),长度还受 be 配置string_type_soft_limit , 实际能存储的最大长度取两者最小值。只能用在 value 列,不能用在 key列和分区、分桶列 |
2、创建用户和数据库
(1)创建test用户
mysql -h 192.168.1.1 -P 9030 -uroot -p() (`填写fe节点的IP,默认无密码,如果fe在本机,不写密码,也可登录,必须填写127.0.0.1,如果填写内网地址会报错`) (`注意P的大小写`) create user 'test' identified by 'test';
(2)创建数据库
create database test_db;
(3)用户授权
grant all on test_db to test;
3、表的基本概念
在 Doris 中,数据都以关系表(Table)的形式进行逻辑上的描述。
(1)Row & Column
一张表包括行(Row)和列(Column)。Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。
-
在默认的数据模型中,Column 只分为排序列和非排序列。存储引擎会按照排序列对数据进行排序存储,并建立稀疏索引,以便在排序数据上进行快速查找。
-
而在聚合模型中,Column可以分为两大类:Key 和 Value。从业务角度看,Key和Value 可以分别对应维度列和指标列。从聚合模型的角度来说,Key 列相同的行,会聚合成一行。其中Value列的聚合方式由用户在建表时指定。
(2)Partition & Tablet
在 Doris 的存储引擎中,用户数据首先被划分成若干个分区(Partition),划分的规则通常是按照用户指定的分区列进行范围划分,比如按时间划分。而在每个分区内,数据被进一步的按照 Hash 的方式分桶,分桶的规则是要找用户指定的分桶列的值进行 Hash 后分桶。
每个分桶就是一个数据分片(Tablet),也是数据划分的最小逻辑单元。
Doris 支持两层的数据划分。第一层是 Partition,支持 Range 和 List 的划分方式。第二层是 Bucket(Tablet),仅支持 Hash 的划分方式。
也可以仅使用一层分区。使用一层分区时,只支持 Bucket 划分。
partition(分区):是在逻辑上将一张表按行(横向)划分
-
Partition 列可以指定一列或多列,在聚合模型中,分区列必须为 KEY 列。
-
不论分区列是什么类型,在写分区值时,都需要加双引号。
-
分区数量理论上没有上限。
-
当不使用 Partition 建表时,系统会自动生成一个和表名同名的,全值范围的 Partition。该 Partition 对用户不可见,并且不可删改。
-
创建分区时不可添加范围重叠的分区。
-
Partition可以视为是逻辑上最小的管理单元。数据的导入与删除,都可以或仅能针对一个 Partition 进行
Range 分区
--range分区创建语法 --Range Partition drop table if exists test.expamle_range_tb; CREATE TABLE IF NOT EXISTS test.expamle_range_tb1 ( `user_id` LARGEINT NOT NULL COMMENT "用户id", `date` DATE NOT NULL COMMENT "数据灌入日期时间", `timestamp` DATETIME NOT NULL COMMENT "数据灌入的时间戳", `city` VARCHAR(20) COMMENT "用户所在城市", `age` SMALLINT COMMENT "用户年龄", `sex` TINYINT COMMENT "用户性别" ) ENGINE=OLAP DUPLICATE KEY(`user_id`, `date`) -- 表模型 -- 分区的语法 PARTITION BY RANGE(`date`) -- 指定分区类型和分区列 ( -- 指定分区名称,分区的上界 前闭后开 PARTITION `p201701` VALUES LESS THAN ("2017-02-01"), PARTITION `p201702` VALUES LESS THAN ("2017-03-01"), PARTITION `p201703` VALUES LESS THAN ("2017-04-01") ) DISTRIBUTED BY HASH(`user_id`) BUCKETS 2;
-
分区列通常为时间列,以方便的管理新旧数据。
-
Partition 支持通过 VALUES LESS THAN (...) 仅指定上界,系统会将前一个分区的上界作为该分区的下界,生成一个左闭右开的区间。同时,也支持通过 VALUES [...) 指定上下界,生成一个左闭右开的区间。
-
通过 VALUES [...) 同时指定上下界比较容易理解。这里举例说明,当使用 VALUES LESS THAN (...) 语句进行分区的增删操作时,分区范围的变化情况:
--如上 expamle_range_tbl 得建表语句中可以看到,当建表完成后,会自动生成如下3个分区: --查看表中分区得情况 SHOW PARTITIONS FROM test.expamle_range_tbl \G; mysql> SHOW PARTITIONS FROM test.expamle_range_tbl \G; *************************** 1. row *************************** PartitionId: 12020 PartitionName: p201701 VisibleVersion: 1 VisibleVersionTime: 2022-08-30 21:57:36 State: NORMAL PartitionKey: date Range: [types: [DATE]; keys: [0000-01-01]; ..types: [DATE]; keys: [2017-02-01]; ) DistributionKey: user_id Buckets: 1 ReplicationNum: 3 StorageMedium: HDD CooldownTime: 9999-12-31 23:59:59 LastConsistencyCheckTime: NULL DataSize: 0.000 IsInMemory: false ReplicaAllocation: tag.location.default: 3 *************************** 2. row *************************** PartitionId: 12021 PartitionName: p201702 VisibleVersion: 1 VisibleVersionTime: 2022-08-30 21:57:36 State: NORMAL PartitionKey: date Range: [types: [DATE]; keys: [2017-02-01]; ..types: [DATE]; keys: [2017-03-01]; ) DistributionKey: user_id Buckets: 1 ReplicationNum: 3 StorageMedium: HDD CooldownTime: 9999-12-31 23:59:59 LastConsistencyCheckTime: NULL DataSize: 0.000 IsInMemory: false ReplicaAllocation: tag.location.default: 3 *************************** 3. row *************************** PartitionId: 12022 PartitionName: p201703 VisibleVersion: 1 VisibleVersionTime: 2022-08-30 21:57:35 State: NORMAL PartitionKey: date Range: [types: [DATE]; keys: [2017-03-01]; ..types: [DATE]; keys: [2017-04-01]; ) DistributionKey: user_id Buckets: 1 ReplicationNum: 3 StorageMedium: HDD CooldownTime: 9999-12-31 23:59:59 LastConsistencyCheckTime: NULL DataSize: 0.000 IsInMemory: false ReplicaAllocation: tag.location.default: 3 3 rows in set (0.00 sec)
这是他生成得三个分区:
p201701: [MIN_VALUE, 2017-02-01) p201702: [2017-02-01, 2017-03-01) p201703: [2017-03-01, 2017-04-01)
当我们增加一个分区 p201705 VALUES LESS THAN ("2017-06-01"),分区结果如下:
ALTER TABLE test.expamle_range_tbl ADD PARTITION p201705 VALUES LESS THAN ("2017-06-01"); p201701: [MIN_VALUE, 2017-02-01) p201702: [2017-02-01, 2017-03-01) p201703: [2017-03-01, 2017-04-01) p201705: [2017-04-01, 2017-06-01)
此时我们删除分区 p201703,则分区结果如下:
ALTER TABLE test.expamle_range_tbl DROP PARTITION p201703; p201701: [MIN_VALUE, 2017-02-01) p201702: [2017-02-01, 2017-03-01) p201705: [2017-04-01, 2017-06-01)
注意到 p201702 和 p201705 的分区范围并没有发生变化,而这两个分区之间,出现了一个空洞:[2017-03-01, 2017-04-01)。即如果导入的数据范围在这个空洞范围内,是无法导入的。
继续删除分区 p201702,分区结果如下:
p201701: [MIN_VALUE, 2017-02-01) p201705: [2017-04-01, 2017-06-01) 空洞范围变为:[2017-02-01, 2017-04-01)
现在增加一个分区 p201702new VALUES LESS THAN ("2017-03-01"),分区结果如下:
p201701: [MIN_VALUE, 2017-02-01) p201702new: [2017-02-01, 2017-03-01) p201705: [2017-04-01, 2017-06-01) 可以看到空洞范围缩小为:[2017-03-01, 2017-04-01)
现在删除分区 p201701,并添加分区 p201612 VALUES LESS THAN ("2017-01-01"),分区结果如下:
p201612: [MIN_VALUE, 2017-01-01) p201702new: [2017-02-01, 2017-03-01) p201705: [2017-04-01, 2017-06-01) 即出现了一个新的空洞:[2017-01-01, 2017-02-01)
综上,分区的删除不会改变已存在分区的范围。删除分区可能出现空洞。通过 VALUES LESS THAN 语句增加分区时,分区的下界紧接上一个分区的上界。
Range分区除了上述我们看到的单列分区,也支持多列分区,示例如下:
PARTITION BY RANGE(`date`, `id`) 前闭后开 ( PARTITION `p201701_1000` VALUES LESS THAN ("2017-02-01", "1000"), PARTITION `p201702_2000` VALUES LESS THAN ("2017-03-01", "2000"), PARTITION `p201703_all` VALUES LESS THAN ("2017-04-01")-- 默认采用id类型的最小值 )
在以上示例中,我们指定 date(DATE 类型) 和 id(INT 类型) 作为分区列。以上示例最终得到的分区如下:
* p201701_1000: [(MIN_VALUE, MIN_VALUE), ("2017-02-01", "1000") ) * p201702_2000: [("2017-02-01", "1000"), ("2017-03-01", "2000") ) * p201703_all: [("2017-03-01", "2000"), ("2017-04-01", MIN_VALUE))
注意,最后一个分区用户缺失,只指定了 date 列的分区值,所以 id 列的分区值会默认填充 MIN_VALUE。当用户插入数据时,分区列值会按照顺序依次比较,最终得到对应的分区。举例如下:
List 分区
-
分区列支持 BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, DATE, DATETIME, CHAR, VARCHAR 数据类型,分区值为枚举值。只有当数据为目标分区枚举值其中之一时,才可以命中分区。
-
Partition 支持通过 VALUES IN (...) 来指定每个分区包含的枚举值。
-
下面通过示例说明,进行分区的增删操作时,分区的变化。
--List分区创建语法 --List Partition CREATE TABLE IF NOT EXISTS test.expamle_list_tbl ( `user_id` LARGEINT NOT NULL COMMENT "用户id", `date` DATE NOT NULL COMMENT "数据灌入日期时间", `timestamp` DATETIME NOT NULL COMMENT "数据灌入的时间戳", `city` VARCHAR(20) NOT NULL COMMENT "用户所在城市", `age` SMALLINT NOT NULL COMMENT "用户年龄", `sex` TINYINT NOT NULL COMMENT "用户性别", `last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "用户最后一次访问时间", `cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费", `max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间", `min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时间" ) ENGINE=olap AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`) PARTITION BY LIST(`city`) ( PARTITION `p_cn` VALUES IN ("Beijing", "Shanghai", "Hong Kong"), PARTITION `p_usa` VALUES IN ("New York", "San Francisco"), PARTITION `p_jp` VALUES IN ("Tokyo") ) -- 指定分桶的语法 DISTRIBUTED BY HASH(`user_id`) BUCKETS 1 PROPERTIES ( "replication_num" = "3" );
如上 example_list_tbl 示例,当建表完成后,会自动生成如下3个分区:
p_cn: ("Beijing", "Shanghai", "Hong Kong") p_usa: ("New York", "San Francisco") p_jp: ("Tokyo")
当我们增加一个分区 p_uk VALUES IN ("London"),分区结果如下:
p_cn: ("Beijing", "Shanghai", "Hong Kong") p_usa: ("New York", "San Francisco") p_jp: ("Tokyo") p_uk: ("London")
当我们删除分区 p_jp,分区结果如下:
p_cn: ("Beijing", "Shanghai", "Hong Kong") p_usa: ("New York", "San Francisco") p_uk: ("London")
List分区也支持多列分区,示例如下
PARTITION BY LIST(`id`, `city`) ( PARTITION `p1_city` VALUES IN (("1", "Beijing"), ("2", "Shanghai")), PARTITION `p2_city` VALUES IN (("2", "Beijing"), ("1", "Shanghai")), PARTITION `p3_city` VALUES IN (("3", "Beijing"), ("4", "Shanghai")) )
在以上示例中,我们指定 id(INT 类型) 和 city(VARCHAR 类型) 作为分区列。以上示例最终得到的分区如下:
* p1_city: [("1", "Beijing"), ("1", "Shanghai")] * p2_city: [("2", "Beijing"), ("2", "Shanghai")] * p3_city: [("3", "Beijing"), ("3", "Shanghai")]
当用户插入数据时,分区列值会按照顺序依次比较,最终得到对应的分区。举例如下:
* 数据 ---> 分区 * 1, Beijing ---> p1_city * 1, Shanghai ---> p1_city * 2, Shanghai ---> p2_city * 3, Beijing ---> p3_city * 1, Tianjin ---> 无法导入 * 4, Beijing ---> 无法导入
tablet(又叫bucket,分桶):在物理上对一个分区再按行(横向)划分
-
Tablet之间的数据是没有交集的,独立存储的。Tablet 也是数据移动、复制等操作的最小物理存储单元。
-
如果使用了 Partition,则 DISTRIBUTED ... 语句描述的是数据在各个分区内的划分规则。如果不使用 Partition,则描述的是对整个表的数据的划分规则。
-
分桶列可以是多列,但必须为 Key 列。分桶列可以和 Partition 列相同或不同。
-
分桶列的选择,是在 查询吞吐 和 查询并发之间的一种权衡:
-
如果选择多个分桶列,则数据分布更均匀。如果一个查询条件不包含所有分桶列的等值条件,那么该查询会触发所有分桶同时扫描,这样查询的吞吐会增加,单个查询的延迟随之降低。这个方式适合高吞吐低并发的查询场景。
-
如果仅选择一个或少数分桶列,则对应的点查询可以仅触发一个分桶扫描。此时,当多个点查询并发时,这些查询有较大的概率分别触发不同的分桶扫描,各个查询之间的IO影响较小(尤其当不同桶分布在不同磁盘上时),所以这种方式适合高并发的点查询场景。
-
-
分桶的数量理论上没有上限
关于 Partition 和 Bucket的数量和数据量的建议
-
一个表的 Tablet 总数量等于 (Partition num * Bucket num)。
-
一个表的 Tablet 数量,在不考虑扩容的情况下,推荐略多于整个集群的磁盘数量。 数量原则
-
单个Tablet的数据量理论上没有上下界,但建议在1G - 10G的范围内。如果单个Tablet数据量过小,则数据的聚合效果不佳,且元数据管理压力大。如果数据量过大,则不利于副本的迁移、补齐,且会增加 Schema Change 或者 Rollup 操作失败重试的代价(这些操作失败重试的粒度是Tablet)。分桶应该控制桶内数据量 ,不易过大或者过小
-
当 Tablet 的数据量原则和数量原则冲突时,建议优先考虑数据量原则。
-
在建表时,每个分区的 Bucket 数量统一指定。但是在动态增加分区时(ADD PARTITION),可以单独指定新分区的 Bucket 数量。可以利用这个功能方便的应对数据缩小或膨胀。
-
一个 Partition 的 Bucket 数量一旦指定,不可更改。所以在确定 Bucket 数量时,需要预先考虑集群扩容的情况。比如当前只有 3 台 host,每台 host 有 1 块盘。如果 Bucket 的数量只设置为 3 或更小,那么后期即使再增加机器,也不能提高并发度。
4、索引
索引用于帮助快速过滤或查找数据。
目前 Doris 主要支持两类索引:
-
内建的智能索引:包括前缀索引和 ZoneMap 索引。 doris自己给我们创建的 根据什么创建
-
用户创建的二级索引:包括 Bloom Filter 索引 和 Bitmap倒排索引。
其中 ZoneMap 索引是在列存格式上,对每一列自动维护的索引信息,包括 Min/Max,Null 值个数等等。这种索引对用户透明。
(1)前缀索引
建表时会自动为指定的key创建前缀索引
doris中,对于前缀索引有如下约束:
-
他的索引键最大长度是36个字节
-
当他遇到了varchar数据类型的时候,即使没有超过36个字节,也会自动截断
所以在建表时,正确的选择列顺序,能够极大地提高查询效率。
(2)Bloom 索引
用户可以通过创建 bitmap index 加速查询
创建索
create index 索引名称 on 表名(给什么字段创建bitmap索引) using bitmap COMMENT '********'; create index user_id_bitmap on sale_detail_bloom(sku_id) USING BITMAP COMMENT '使用user_id创建的bitmap索引';
查看索引
SHOW INDEX FROM example_db.table_name;
删除索引
DROP INDEX [IF EXISTS] index_name ON [db_name.]table_name;
注意事项:
-
bitmap 索引仅在单列上创建。
-
bitmap 索引能够应用在 Duplicate、Uniq 数据模型的所有列和 Aggregate模型的key列上。
-
bitmap 索引支持的数据类型如下:(老版本只支持bitmap类型)
-
TINYINT,SMALLINT,INT,BIGINT,CHAR,VARCHAR,DATE,DATETIME,LARGEINT,DECIMAL,BOOL
-
-
bitmap索引仅在 Segment V2 下生效(Segment V2是升级版本的文件格式)。当创建 index 时,表的存储格式将默认转换为 V2 格式
(3)Bitmap Filter 索引
Doris的BloomFilter索引是从通过建表的时候指定,或者通过表的ALTER操作来完成。
建表时指定 BloomFilter 索引
PROPERTIES ( "bloom_filter_columns"="name,age,uid" )
alter修改表的时候指定
ALTER TABLE sale_detail_bloom SET ("bloom_filter_columns" = "k1,k3"); ALTER TABLE sale_detail_bloom SET ("bloom_filter_columns" = "k1,k4"); ALTER TABLE sale_detail_bloom SET ("bloom_filter_columns" = "");
建表示例:
CREATE TABLE IF NOT EXISTS sale_detail_bloom ( sale_date date NOT NULL COMMENT "销售时间", customer_id int NOT NULL COMMENT "客户编号", saler_id int NOT NULL COMMENT "销售员", sku_id int NOT NULL COMMENT "商品编号", category_id int NOT NULL COMMENT "商品分类", sale_count int NOT NULL COMMENT "销售数量", sale_price DECIMAL(12,2) NOT NULL COMMENT "单价", sale_amt DECIMAL(20,2) COMMENT "销售总金额" ) Duplicate KEY(sale_date, customer_id,saler_id,sku_id,category_id) PARTITION BY RANGE(sale_date) ( PARTITION P_202111 VALUES [('2021-11-01'), ('2021-12-01')) ) DISTRIBUTED BY HASH(saler_id) BUCKETS 1 properties( "bloom_filter_columns" = "customer_id,saler_id" );
查看BloomFilter索引:
SHOW CREATE TABLE sale_detail_bloom \G;
Doris BloomFilter适用场景:
满足以下几个条件时可以考虑对某列建立Bloom Filter 索引:
-
BloomFilter是在无法利用前缀索引的查询场景中,来加快查询速度的。
-
查询会根据该列高频过滤,而且查询条件大多是 in 和 = 过滤。
-
不同于Bitmap, BloomFilter适用于高基数列。比如UserID。因为如果创建在低基数的列上,比如 “性别” 列,则每个Block几乎都会包含所有取值,导致BloomFilter索引失去意义。字段随机
注意事项:
-
不支持对Tinyint、Float、Double 类型的列建Bloom Filter索引。
-
Bloom Filter索引只对 in 和 = 过滤查询有加速效果。
doris数据库使用注意事项
sql中使用with as 表名()临时表时,表名必须为小写可使用下划线(_),有的版本可能不支持大小写混合
用pagehelper插件分页时,必须加排序,某些版本可能存在翻页条件没问题,但数据无变化