1. 建表
字段類型
tinyint |
1字節 |
范圍:-2^7 + 1 ~ 2^7 - 1 |
smallint |
2字節 |
范圍:-2^15 + 1 ~ 2^15 - 1 |
bigint |
8字節 |
范圍:-2^63 + 1 ~ 2^63 - 1 |
largeint |
16字節 |
范圍:-2^127 + 1 ~ 2^127 - 1 |
float |
4字節 |
支持科學計數法 |
double |
12字節 |
支持科學計數法 |
decamal[(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 |
hll |
1~16385個字節 |
hll列類型,不需要指定長度和默認值、長度根據數據的聚合 程度系統內控制,並且HLL列只能通過配套的hll_union_agg、Hll_cardinality、hll_hash進行查詢或使用 |
bitmap |
|
bitmap列類型,不需要指定長度和默認值。表示整型的集合,元素最大支持到2^64 - 1 |
agg_type |
聚合類型,如果不指定,則該列為 key 列。否則,該列為 value 列 |
SUM、MAX、MIN、REPLACE |
分區
Doris支持單分區和復合分區兩種建表方式。
在復合分區中:
第一級稱為Partition, 即分區。用戶指定某一維度列做為分區列(當前只支持整型和時間類型的列),並指定每個分區的取值范圍。
第二級稱為Distribution, 即分桶。用戶可以指定一個或多個維度列以及桶數進行HASH分布。
以下場景推薦使用復合分區
1. 有時間維或類似帶有有序值的維度,可以以這類維度列作為分區列。分區粒度可以根據導入頻次、分區數據量等進行評估。
2. 歷史數據刪除需求:如有刪除歷史數據的需求(比如僅保留最近N天的數據)。使用復合分區,可以通過刪除歷史分區來達到目的。也可以通過在指定分區內發送DELETE語句進行刪除。
3. 解決數據傾斜的問題:每個分區可以單獨指定分桶數量。如按天分區,當每天的數據量差異很大的時,可以通過指定分區的分桶數,合理規划不同分區的數據,分桶列建議選擇區分度大的列。
也可以不是用復合分區,僅使用單分區。則數據只做HASH分布。
========================創建單分區表 CREATE TABLE student( id INT, name VARCHAR(50) DEFAULT '', age INT, count BIGINT SUM DEFAULT '0' ) AGGREGATE KEY (id,name,age) DISTRIBUTED BY HASH(id) buckets 10 PROPERTIES("replication_num" = "1");
建立一張student表。分桶列為id,桶數為10,副本數為1。
======================創建復合分區表 CREATE TABLE student2( dt DATE, id INT, name VARCHAR(50) DEFAULT '', age INT, count BIGINT SUM DEFAULT '0' ) AGGREGATE KEY (dt,id,name,age) PARTITION BY RANGE(dt) ( PARTITION p202007 VALUES LESS THAN ('2020-08-01'), PARTITION p202008 VALUES LESS THAN ('2020-09-01'), PARTITION p202009 VALUES LESS THAN ('2020-10-01') ) DISTRIBUTED BY HASH(id) buckets 10 PROPERTIES("replication_num" = "1");
創建student2表,使用dt字段作為分區列,並且創建3個分區,分別是: P202007 范圍值是[最小值, 2020-08-01) P202008 范圍值是[2020-08-01, 2020-09-01) P202009 范圍值是[2020-09-01, 2020-10-01)
數據模型
Doris數據模型上目前分為三種
AGGREGATE KEY, UNIQUE KEY, DUPLICATE KEY。
三種模型都是按KEY進行排序
① AGGREGATE KEY 聚合模型
適用場景
在數據分析領域,有很多需要對數據進行統計和匯總操作的場景。比如:
- 分析網站或APP訪問流量,統計用戶的訪問總時長、訪問總次數;
- 廣告廠商為廣告主提供的廣告點擊總量、展示總量、消費統計等;
- 分析電商的全年的交易數據, 獲得某指定季度或者月份的, 各人口分類(geographic)的爆款商品.
適合采用聚合模型來分析的場景具有如下特點:
- 業務方進行的查詢為匯總類查詢,比如sum、count、 max等類型的查詢;
- 不需要召回原始的明細數據;
- 老數據不會被頻繁更新,只會追加新數據。
模型原理
DorisDB會將指標列按照相同維度列進行聚合。當多條數據具有相同的維度時,DorisDB會把指標進行聚合。從而能夠減少查詢時所需要的處理的數據量,進而提升查詢的效率。
AGGREGATE KEY相同時,新舊記錄將會進行聚合操作,目前支持SUM,MIN,MAX,REPLACE。
AGGREGATE KEY模型可以提前聚合數據,適合報表和多維度業務。
注意點:
- 聚合表中數據會分批次多次導入, 每次導入會形成一個版本. 相同排序鍵的數據行聚合有三種觸發方式: ①. 數據導入時, 數據落盤前的聚合; ②. 數據落盤后, 后台的多版本異步聚合; ③. 數據查詢時, 多版本多路歸並聚合.
- 數據查詢時, 指標列采用先聚合后過濾的方式, 把沒必有做指標的列存儲為維度列.
(1)建表 CREATE TABLE site_visit( siteid INT, city SMALLINT, username VARCHAR(32), pv BIGINT SUM DEFAULT '0' ) AGGREGATE KEY(siteid, city, username) DISTRIBUTED BY HASH(siteid) BUCKETS 10;
PROPERTIES("replication_num" = "1");
排序列為siteid、city、username
指標列為pv,使用聚合函數SUM (2)插入2條數據 mysql> insert into site_visit values(1,1,'name1',10); mysql> insert into site_visit values(1,1,'name1',20); (3)查看結果 select * from site_visit;
② UNIQUE KEY 更新模型
適用場景
有些分析場景之下,數據會更新, DorisDB采用更新模型來滿足這種需求。比如在電商場景中,訂單的狀態經常會發生變化,每天的訂單更新量可突破上億。在這種量級的更新場景下進行實時數據分析,如果在明
細模型下通過delete+insert的方式,是無法滿足頻繁更新需求的; 因此, 用戶需要使用更新模型來滿足數據分析需求。
以下是一些適合更新模型的場景特點:
- 已經寫入的數據有大量的更新需求;
- 需要進行實時數據分析。
模型原理
更新模型中, 排序鍵滿足唯一性約束, 成為主鍵.
DorisDB存儲內部會給每一個批次導入數據分配一個版本號, 同一主鍵的數據可能有多個版本, 查詢時, 最大(最新)版本的數據勝出.
注意事項
- 導入數據時需要將所有字段補全才能夠完成更新操作,即,下述例子中的orderid、status、username和amount四個字段都需必須存在。
- 對於更新模型的數據讀取,需要在查詢時完成多版本合並,當版本過多時會導致查詢性能降低。所以在向更新模型導入數據時,應該適當降低導入頻率,從而提升查詢性能。建議在設計導入頻率時以滿足業務對實時性的要求為准。如果業務對實時性的要求是分鍾級別,那么每分鍾導入一次更新數據即可,不需要秒級導入。
- 在查詢時,對於value字段的過濾通常在多版本合並之后。將經常過濾字段且不會被修改的字段放在主鍵上, 能夠在合並之前就將數據過濾掉,從而提升查詢性能。
- 因為合並過程需要將所有主鍵字段進行比較,所以應該避免放置過多的主鍵字段,以免降低查詢性能。如果某個字段只是偶爾會作為查詢中的過濾條件存在,不需要放在主鍵中。
UNIQUE KEY相同時,新記錄覆蓋舊記錄。目前UNIQUE KEY和AGGREGATE KEY的REPLACE聚合方法一致。適用於有更新需求的業務。
1)建表 CREATE TABLE sales_order( orderid BIGINT, status TINYINT, username VARCHAR(32), amount BIGINT DEFAULT '0' ) UNIQUE KEY(orderid) DISTRIBUTED BY HASH(orderid) BUCKETS 10;
PROPERTIES("replication_num" = "1");
UNIQUE(orderid)為主鍵,orderid為排序列,定義在其他列之前;
其他列為指標列,其聚合類型為REPLACE;
(2)插入2條數據 mysql> insert into sales_order values(1,1,'name1',100); mysql> insert into sales_order values(1,1,'name1',200); (3)查詢
③ DUPLICATE KEY 明細模型
適用場景:
- 需要保留原始的數據(例如原始日志,原始操作記錄等)來進行分析;
- 查詢方式靈活, 不局限於預先定義的分析方式, 傳統的預聚合方式難以命中;
- 數據更新不頻繁。導入數據的來源一般為日志數據或者是時序數據, 以追加寫為主要特點, 數據產生后就不會發生太多變化
模型原理:
指定數據表的排序列, 沒有明確指定的情況下, 那么DorisDB會為表選擇默認的幾個列作為排序列。這樣,在查詢中,有相關排序列的過濾條件時,DorisDB能夠快速地過濾數據,降低整個查詢的時延。
注意:
在向DorisDB明細模型表中導入完全相同的兩行數據時,DorisDB會認為是兩行數據。只指定排序列,相同的行並不會合並。
充分利用排序列,在建表時將經常在查詢中用於過濾的列放在表的前面,這樣能夠提升查詢速度。
明細模型中, 可以指定部分的維度列為排序鍵; 而聚合模型和更新模型中, 排序鍵只能是全體維度列.
(1)建表 CREATE TABLE session_data( visitorid SMALLINT, sessionid BIGINT, city CHAR(20), ip varchar(32) ) DUPLICATE KEY(visitorid, sessionid) DISTRIBUTED BY HASH(sessionid, visitorid) BUCKETS 10 PROPERTIES("replication_num" = "1");
以visitorid和 sessionid作為排序列,且排序列在其他列之前;
(2)插入數據 mysql> insert into session_data values(1,1,'beijing','www.111.com'); mysql> insert into session_data values(1,1,'beijing','www.111.com'); mysql> insert into session_data values(3,2,'beijing','www.111.com'); mysql> insert into session_data values(2,2,'beijing','www.111.com'); mysql> insert into session_data values(2,1,'beijing','www.111.com'); (3)查詢 mysql> select * from session_data; +-----------+-----------+---------+-------------+
| visitorid | sessionid | city | ip |
+-----------+-----------+---------+-------------+
| 1 | 1 | beijing | www.111.com |
| 1 | 1 | beijing | www.111.com |
| 2 | 1 | beijing | www.111.com |
| 3 | 2 | beijing | www.111.com |
| 2 | 2 | beijing | www.111.com |
+-----------+-----------+---------+-------------+
5 rows in set (0.02 sec)
Rollup物化索引結構
Rollup可以理解為表的一個物化索引結構。Rollup可以調整列的順序以增加前綴索引的命中率,也可以減少key列以增加數據的聚合度。
(1)以session_data為例添加Rollup
(2)比如我經常需要看某個城市的ip數,那么可以建立一個只有ip和city的rollup;
mysql> alter table session_data add rollup rollup_city_ip(city, ip);
(3)創建完畢后,再次查看表結構
(4)然后可以通過explain查看執行計划,是否使用到了rollup
mysql> explain select ip from session_data where city='shanghai';
數據導入
為適配不同的數據導入需求,Doris系統提供5種不同的導入方式。每種導入方式支持不同的數據源,存在不同的方式(異步、同步)
(1)Broker load
通過Broker進程訪問並讀取外部數據源(HDFS)導入Doris。用戶通過MySql協議提交導入作業后,異步執行。通過show load命令查看導入結果。
(2)Stream load
用戶通過HTTP協議提交請求並攜帶原始數據創建導入。主要用於快速將本地文件或數據流中的數據導入到Doris。導入命令同步返回導入結果。
(3)Insert
類似MySql中的insert語句,Doris提供insert into tbl select ...;的方式從Doris的表中讀取數據並導入到另一張表。或者通過insert into tbl values(...);的方式插入單條數據
(4)Multi load
用戶可以通過HTTP協議提交多個導入作業。Multi Load可以保證多個導入作業的原子生效
(5)Routine load
用戶通過MySql協議提交例行導入作業,生成一個常住線程,不間斷的從數據源(如Kafka)中讀取數據並導入Doris中。
Broker Load
Broker load是一個導入的異步方式,支持的數據源取決於Broker進程支持的數據源。
適用場景:
① 源數據在Broker可以訪問的存儲系統中,如HDFS ;
② 數據量在幾十到百GB級別。
基本原理:用戶在提交導入任務后,FE(Doris系統的元數據和調度節點)會生成相應的PLAN(導入執行計划,BE會執行導入計划將輸入導入Doris中)並根據BE(Doris系統的計算和存儲節點)的個數和文件的大小,將Plan分給多個BE執行,每個BE導入一部分數
據。BE在執行過程中會從Broker拉取數據,在對數據轉換之后導入系統。所有BE均完成導入,由FE最終決定是否導入是否成功。
(1)啟動hdfs集群 ,啟動hive的元數據 memstore
hive --service metastore &
(2)進入到hive創建student_tmp表,雖然官網提示說支持列式存儲,但測試發現並不支持,會提示一下錯誤
所以在hive表里創建行式存儲表
[kris@hadoop102 ~]# hive create table student_tmp_h( id int, name string, age int, score decimal(10,4)) partitioned by ( `dt` string) row format delimited fields terminated by '\t';
(3)插入數據 hive (default)> set hive.exec.dynamic.partition=true; hive (default)> set hive.exec.dynamic.partition.mode=nonstrict; insert into student_tmp_h values(1,'張三',11,99.8,20200908),(2,'李四',12,99.9,20200908),(3,'王五',13,100,20200908), (4,'趙六',14,55.5,20200908),(5,'test1',13,66.5,20200908),(7,'test2',14,80,20200908),(8,'test3',19,75,20200908);
(5)將hadoop集群的配置文件復制到doris集群的broker上
[kris@hadoop102 ~]# cd /opt/module/hadoop-3.1.3/etc/hadoop/
[kris@hadoop102 hadoop]$ scp hdfs-site.xml /opt/module/apache-doris/apache_hdfs_broker/conf [kris@hadoop102 conf]$ xsync hdfs-site.xml #分發到另外兩台機器上
(6)使用mysql客戶端登錄doris創建對應表student_result [kris@hadoop102 be]$ mysql -hdadoop102 -P 9030 -uroot mysql> use example_db; create table student_result ( id int , name varchar(50), age int , score decimal(10,4), dt varchar(20) ) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 10 PROPERTIES("replication_num" = "1"); (7)編寫導入語句,dt是分區列,在數據塊讀不到所以使用固定值 LOAD LABEL example_db.label1 ( DATA INFILE("hdfs://hadoop102/user/hive/warehouse/student_tmp_h/dt=20200908/*") INTO TABLE student_result COLUMNS TERMINATED BY "\t" (co1,co2,co3,co4) set( id=co1, name=co2, age=co3, score=co4, dt='20200908' ) ) WITH BROKER 'broker2' PROPERTIES ( "timeout" = "3600" ); mysql> show load \G; *************************** 15. row *************************** JobId: 21034 Label: label1 State: FINISHED Progress: ETL:100%; LOAD:100% Type: BROKER EtlInfo: unselected.rows=0; dpp.abnorm.ALL=0; dpp.norm.ALL=7 TaskInfo: cluster:N/A; timeout(s):3600; max_filter_ratio:0.0 ErrorMsg: NULL CreateTime: 2021-10-24 15:32:37 EtlStartTime: 2021-10-24 15:32:41 EtlFinishTime: 2021-10-24 15:32:41 LoadStartTime: 2021-10-24 15:32:41 LoadFinishTime: 2021-10-24 15:32:43 URL: NULL JobDetails: {"Unfinished backends":{"98200135-d214-421d-915f-7a2ff9944b84":[]},"ScannedRows":7,"TaskNumber":1,"All backends":{"98200135-d214-421d-915f-7a2ff9944b84":[10003]},"FileNumber":1,"FileSize":138} 15 rows in set (0.00 sec)
Stream Load
適合導入小數據量的文件
Stream Load是一個同步的導入方式,用戶通過發送HTTP協議將本地文件或數據流導入到Doris中,Stream load同步執行導入並返回結果。用戶可以直接通過返回判斷導入是否成功。
具體幫助使用HELP STREAM LOAD 查看
mysql> help stream load
(1)創建文件
(2)將文件上傳到集群
(3)通過命令將csv數據導入到doris,-H指定參數,column_separator指定分割符,-T指定數據源文件。
[kris@hadoop102 apache-doris]$ vim table2_data 2017-07-03,1,1,jim,2
2017-07-05,2,1,grace,2
2017-07-12,3,2,tom,2
2017-07-15,4,3,bush,3 [kris@hadoop102 apache-doris]$ curl --location-trusted -u test:123456 -T table2_data -H "label:table2_20170707" -H "column_separator:," http://hadoop102:8030/api/example_db/table2/_stream_load
{ "TxnId": 3015, "Label": "table2_20170707", "Status": "Success", "Message": "OK", "NumberTotalRows": 4, "NumberLoadedRows": 4, "NumberFilteredRows": 0, "NumberUnselectedRows": 0, "LoadBytes": 87, "LoadTimeMs": 117, "BeginTxnTimeMs": 0, "StreamLoadPutTimeMs": 2, "ReadDataTimeMs": 0, "WriteDataTimeMs": 58, "CommitAndPublishTimeMs": 52 }
(4)查看對應表,導入成功
Routine Load
例行導入功能為用戶提供了一種自動從指定數據源進行數據導入的功能。
當前僅支持Kafka系統進行例行導入。
使用限制:
1. 支持無認證的Kafka訪問,以及通過SSL方式認證的Kafka集群
2. 僅支持kafka0.10.0.0 及以上版本
先安裝好zookeeper和kafka,創建topic,並往topic里灌一批數據
bin/kafka-topics.sh --zookeeper hadoop102:2181/kafka --create --replication-factor 2 --partitions 3 --topic test
import org.apache.kafka.clients.producer.KafkaProducer; import org.apache.kafka.clients.producer.ProducerRecord; import java.util.Properties; public class product { public static void main(String[] args) { Properties props = new Properties(); props.put("bootstrap.servers", "hadoop102:9092,hadoop103:9092,hadoop104:9092"); props.put("acks", "-1"); props.put("batch.size", "16384"); props.put("linger.ms", "10"); props.put("buffer.memory", "33554432"); props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer"); props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer"); KafkaProducer<String, String> producer = new KafkaProducer<String, String>(props); for (int i = 0; i < 100; i++) { producer.send(new ProducerRecord<String,String>("test",i+"\tname"+i+"\t18")); } producer.flush(); producer.close(); } }
① 在doris中創建對應表 create table student_kafka( id int, name varchar(50), age int ) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 10 PROPERTIES("replication_num" = "1"); ② 創建導入作業,desired_concurrent_number指定並行度 CREATE ROUTINE LOAD example_db.test ON student_kafka PROPERTIES( "desired_concurrent_number"="3", "strict_mode" = "false" ) FROM KAFKA( "kafka_broker_list"= "hadoop102:9092,hadoop103:9092,hadoop104:9092", "kafka_topic" = "test", "property.group.id"="test_group", "property.kafka_default_offsets" = "OFFSET_BEGINNING", "property.enable.auto.commit"="false" ); ③ 創建完作業導入作業后查詢doris
動態分區
在很多實際應用場景中,數據的時效性很重要,需要為新達到數據創建新分區, 刪除過期. DorisDB的動態分區機制可以實現分區rollover: 對分區實現進行生命周期管理(TTL),自動增刪分區。
動態分區是在Doris0.12版本加入的功能。旨在對表級別的分區實現生命周期管理(TTL),減少用戶的使用負擔。
目前實現了動態添加分區及動態刪除分區的功能
原理:
在某些場景下,用戶會將表按照天進行分區划分,每天定時執行例行任務,這時需要使用方手動管理分區,否則可能由於使用方沒有創建數據導致失敗這給使用方帶來額外的維護成本。
如果沒有動態分區這個功能,就要手動去創建分區,如果沒有創建就可能導致數據導入失敗。
在實現方式上,FE會啟動一個后台子線程,根據fe.conf中dynamic_partition_enable(默認是關閉的)及dynamic_partition_check_interval_seconds參數決定線程是否啟動以及該線程的調度頻率(過多久創建新的分區)。每次調度時,會在注冊表中讀取動態分區表的屬性。
建表的參數
dynamic_partition.enable |
是否開啟動態分區特性,可指定true或false,默認為true |
dynamic_partition.time_unit |
動態分區調度的單位,可指定day,week,month。當指定day時格式為yyyyMMDD。當指定week時格式為yyyy_ww,表示屬於這一年的第幾周。當指定為month時,格式為yyyyMM |
dynamic_partition.start |
動態分區的開始時間,以當天為准,超過該時間范圍的分區將會被刪除,如果不填寫默認值為Interger.Min_VALUE 即-2147483648 |
dynamic_partition.end |
動態分區的結束時間,以當天為基准,會提前創建N個單位的分區范圍 |
dynamic_partition.prefix |
動態創建的分區名前綴 |
dynamic_partition.buckets |
動態創建的分區所對應分桶數量 |
使用
(1)開啟動態分區功能,可以在fe.conf中設置dynamic_partition_enable=true,也可以使用命令進行修改。使用命令進行修改,並dynamic_partition_check_interval_seconds調度時間設置為5秒,意思就是每過5秒根據配置刷新分區。我這里做測試設置為5秒,真實場景可以設置為12小時。
修改表的分區屬性
動態分區的屬性可以修改,例如需要起/停動態分區的功能,可以通過ALTER TABLE來完成。
ALTER TABLE site_access SET("dynamic_partition.enable"="false"); ALTER TABLE site_access SET("dynamic_partition.enable"="true");
注意事項
動態分區的方式相當於把建分區的判斷邏輯交由DorisDB來完成,在配置的過程中一定要保證分區名稱滿足規范,否則會創建失敗。具體規范可以描述如下:
- 指定為 DAY 時,分區名后綴需為yyyyMMdd,例如20200325。
- 指定為 WEEK 時,分區名后綴需為yyyy_ww,例如 2020_13, 代表2020年第13周。
- 指定為 MONTH 時,動態創建的分區名后綴格式為 yyyyMM,例如 202003。
[kris@hadoop102 apache-doris]$ curl --location-trusted -u root -XGET http://hadoop102:8030/api/_set_config?dynamic_partition_enable=true Enter host password for user 'root': {"set":{"dynamic_partition_enable":"true"},"err":{}} [kris@hadoop102 apache-doris]$ curl --location-trusted -u root -XGET http://hadoop102:8030/api/_set_config?dynamic_partition_check_interval_seconds=5
Enter host password for user 'root': {"set":{"dynamic_partition_check_interval_seconds":"5"},"err":{}} mysql> ADMIN SET FRONTEND CONFIG ("dynamic_partition_enable" = "true"); mysql> ADMIN SET FRONTEND CONFIG ("dynamic_partition_check_interval_seconds"="5");
(2)創建一張調度單位為天,不刪除歷史分區的動態分區表
create table student_dynamic_partition (id int, time date, name varchar(50), age int ) duplicate key(id,time) PARTITION BY RANGE(time)() DISTRIBUTED BY HASH(id) buckets 10 PROPERTIES( "dynamic_partition.enable" = "true", "dynamic_partition.time_unit" = "DAY", "dynamic_partition.end" = "3", "dynamic_partition.prefix" = "p", "dynamic_partition.buckets" = "10", "replication_num" = "1" );
(3)查看分區表情況SHOW DYNAMIC PARTITION TABLES,更新最后調度時間
mysql> SHOW DYNAMIC PARTITION TABLES \G; *************************** 1. row *************************** TableName: student_dynamic_partition Enable: true TimeUnit: DAY Start: -2147483648
End: 3 Prefix: p Buckets: 10 ReplicationNum: 1 StartOf: NULL LastUpdateTime: 2021-10-23 19:49:08 LastSchedulerTime: 2021-10-23 19:49:55 State: NORMAL LastCreatePartitionMsg: NULL LastDropPartitionMsg: NULL
1 row in set (0.00 sec) ERROR: No query specified
(4)插入測試數據,可以全部成功 mysql> insert into student_dynamic_partition values(1,'2021-10-10 20:00:00','name1',18); ERROR 1064 (HY000): Insert has filtered data in strict mode, tracking_url=http://192.168.1.102:8040/api/_load_error_log?file=__shard_1/error_log_insert_stmt_3e5b75f4-33f8-11ec-8ee9-525400f13278_3e5b75f433f811ec_8ee9525400f13278 mysql> insert into student_dynamic_partition values(1,'2021-10-23 20:00:00','name1',18); Query OK, 1 row affected (0.05 sec) {'label':'insert_d6fc4b8c-33f7-11ec-8ee9-525400f13277', 'status':'VISIBLE', 'txnId':'1031'} mysql> insert into student_dynamic_partition values(1,'2021-10-24 20:00:00','name1',18); Query OK, 1 row affected (0.06 sec) {'label':'insert_e5a7f0e4-33f7-11ec-8ee9-525400f13277', 'status':'VISIBLE', 'txnId':'1034'} mysql> insert into student_dynamic_partition values(1,'2021-10-25 20:00:00','name1',18); Query OK, 1 row affected (0.03 sec) {'label':'insert_ed14936c-33f7-11ec-8ee9-525400f13277', 'status':'VISIBLE', 'txnId':'1037'} (5)使用命令查看表下的所有分區show partitions from student_dynamic_partition; mysql> show partitions from student_dynamic_partition \G; *************************** 1. row *************************** PartitionId: 19212 PartitionName: p20211023 VisibleVersion: 2 VisibleVersionTime: 2021-10-23 19:53:29 VisibleVersionHash: 1189085190502871807 State: NORMAL PartitionKey: time Range: [types: [DATE]; keys: [2021-10-23]; ..types: [DATE]; keys: [2021-10-24]; ) DistributionKey: id Buckets: 10 ReplicationNum: 1 StorageMedium: HDD CooldownTime: 9999-12-31 23:59:59 LastConsistencyCheckTime: NULL DataSize: 710.000 B IsInMemory: false *************************** 2. row *************************** PartitionId: 19233 PartitionName: p20211024 VisibleVersion: 2 VisibleVersionTime: 2021-10-23 19:53:54 VisibleVersionHash: 8153597939592092591 State: NORMAL PartitionKey: time Range: [types: [DATE]; keys: [2021-10-24]; ..types: [DATE]; keys: [2021-10-25]; ) DistributionKey: id Buckets: 10 ReplicationNum: 1 StorageMedium: HDD CooldownTime: 9999-12-31 23:59:59 LastConsistencyCheckTime: NULL DataSize: 714.000 B IsInMemory: false *************************** 3. row *************************** PartitionId: 19254 PartitionName: p20211025 VisibleVersion: 2 VisibleVersionTime: 2021-10-23 19:54:06 VisibleVersionHash: 1238099035870710564 State: NORMAL PartitionKey: time Range: [types: [DATE]; keys: [2021-10-25]; ..types: [DATE]; keys: [2021-10-26]; ) DistributionKey: id Buckets: 10 ReplicationNum: 1 StorageMedium: HDD CooldownTime: 9999-12-31 23:59:59 LastConsistencyCheckTime: NULL DataSize: 713.000 B IsInMemory: false *************************** 4. row *************************** PartitionId: 19275 PartitionName: p20211026 VisibleVersion: 1 VisibleVersionTime: 2021-10-23 19:49:15 VisibleVersionHash: 0 State: NORMAL PartitionKey: time Range: [types: [DATE]; keys: [2021-10-26]; ..types: [DATE]; keys: [2021-10-27]; ) DistributionKey: id Buckets: 10 ReplicationNum: 1 StorageMedium: HDD CooldownTime: 9999-12-31 23:59:59 LastConsistencyCheckTime: NULL DataSize: .000 IsInMemory: false 4 rows in set (0.00 sec) ERROR: No query specified mysql> select * from student_dynamic_partition; +------+------------+-------+------+
| id | time | name | age |
+------+------------+-------+------+
| 1 | 2021-10-25 | name1 | 18 |
| 1 | 2021-10-23 | name1 | 18 |
| 1 | 2021-10-24 | name1 | 18 |
+------+------------+-------+------+
3 rows in set (0.01 sec)
批量創建和修改分區
該功能在1.16版本中添加
1 建表時批量創建日期分區
用戶可以通過給出一個START值、一個END值以及一個定義分區增量值的EVERY子句批量產生分區。
其中START值將被包括在內而END值將排除在外。
例如: CREATE TABLE site_access ( datekey DATE, site_id INT, city_code SMALLINT, user_name VARCHAR(32), pv BIGINT DEFAULT '0' ) ENGINE=olap DUPLICATE KEY(datekey, site_id, city_code, user_name) PARTITION BY RANGE (datekey) ( START ("2021-01-01") END ("2021-01-04") EVERY (INTERVAL 1 day) ) DISTRIBUTED BY HASH(site_id) BUCKETS 10 PROPERTIES ( "replication_num" = "1" ); 相當於 自動創建如下等價的分區 PARTITION p20210101 VALUES [('2021-01-01'), ('2021-01-02')), PARTITION p20210102 VALUES [('2021-01-02'), ('2021-01-03')), PARTITION p20210103 VALUES [('2021-01-03'), ('2021-01-04')) **2 建表時批量創建數字分區** 當分區鍵為整數類型時直接使用數字進行分區,注意分區值需要使用引號引用,而EVERY則不用引號,如下: CREATE TABLE site_access ( datekey INT, site_id INT, city_code SMALLINT, user_name VARCHAR(32), pv BIGINT DEFAULT '0' ) ENGINE=olap DUPLICATE KEY(datekey, site_id, city_code, user_name) PARTITION BY RANGE (datekey) ( START ("1") END ("5") EVERY (1) ) DISTRIBUTED BY HASH(site_id) BUCKETS 10 PROPERTIES ( "replication_num" = "1" ); 上面的語句將產生如下分區: PARTITION p1 VALUES [("1"), ("2")), PARTITION p2 VALUES [("2"), ("3")), PARTITION p3 VALUES [("3"), ("4")), PARTITION p4 VALUES [("4"), ("5")) 3 建表時批量創建不同類型的日期分區 DorisDB也支持建表時同時定義不同類型的分區,只要求這些分區不相交,例如: CREATE TABLE site_access ( datekey DATE, site_id INT, city_code SMALLINT, user_name VARCHAR(32), pv BIGINT DEFAULT '0' ) ENGINE=olap DUPLICATE KEY(datekey, site_id, city_code, user_name) PARTITION BY RANGE (datekey) ( START ("2019-01-01") END ("2021-01-01") EVERY (INTERVAL 1 YEAR), START ("2021-01-01") END ("2021-05-01") EVERY (INTERVAL 1 MONTH), START ("2021-05-01") END ("2021-05-04") EVERY (INTERVAL 1 DAY) ) DISTRIBUTED BY HASH(site_id) BUCKETS 10 PROPERTIES ( "replication_num" = "1" ); 上面的語句將會產生如下分區: PARTITION p2019 VALUES [('2019-01-01'), ('2020-01-01')), PARTITION p2020 VALUES [('2020-01-01'), ('2021-01-01')), PARTITION p202101 VALUES [('2021-01-01'), ('2021-02-01')), PARTITION p202102 VALUES [('2021-02-01'), ('2021-03-01')), PARTITION p202103 VALUES [('2021-03-01'), ('2021-04-01')), PARTITION p202104 VALUES [('2021-04-01'), ('2021-05-01')), PARTITION p20210501 VALUES [('2021-05-01'), ('2021-05-02')), PARTITION p20210502 VALUES [('2021-05-02'), ('2021-05-03')), PARTITION p20210503 VALUES [('2021-05-03'), ('2021-05-04')) **4 建表后批量創建分區** 與建表時批量創建分區類似,DorisDB也支持通過ALTER語句批量創建分區。通過指定ADD PARITIONS關鍵字,配合START和END以及EVERY的值來創建分區。 ALTER TABLE site_access ADD PARTITIONS START ("2014-01-01") END ("2014-01-06") EVERY (interval 1 day);
數據導出
數據導出是Doris提供的一種將數據導出的功能。該功能可以將用戶指定的表或分區的數據以文本的格式,通過Broker進程導出到遠端存儲上,如HDFS/BOS等。
(1)啟動hadoop集群
(2)執行導出計划
export table student_dynamic_partition to "hdfs://hadoop102/tmp/hive/" PROPERTIES ( "column_separator"=",", "load_mem_limit"="2147483648", "timeout" = "3600" ) WITH BROKER "broker2" ;
(3)導出之后查看hdfs對應路徑,會多出許多文件
(4)使用命令查看有數據的文件內容,就是簡單的文本內容
[kris@hadoop102 hive]# hadoop dfs -cat /tmp/hive/export-data-69208f5fdf5e4e63-b3f75089d7f7611f-1599717109072
SQL函數
(1)查看函數名
mysql> show builtin functions in test_db;
(2)查看函數具體信息,比如查看year函數具體信息
mysql> show full builtin functions in test_db like 'year';
(2)官網地址
Colocation Join
Colocation Join是在Doris0.9版本引入的功能,旨在為Join查詢提供本性優化,來減少數據在節點上的傳輸耗時,加速查詢。與廣播join比較像;
原理
Colocation Join功能,是將一組擁有CGS 的表組成一個CG。保證這些表對應的數據分片會落在同一個be節點上,那么使得兩表再進行join的時候,可以通過本地數據進行直接join,減少數據在節點之間的網絡傳輸時間。
使用限制:
1)建表時兩張表的分桶列和數量需要完全一致,並且桶的個數也需要一致。
2)副本數,兩張表的所有分區的副本數需要一致
(1)使用,建兩張表,分桶列都為int類型,且桶的個數都是8個。兩張表的副本數都為默認副本數。
CREATE TABLE `tbl1` ( `k1` date NOT NULL COMMENT "", `k2` int(11) NOT NULL COMMENT "", `v1` int(11) SUM NOT NULL COMMENT "" ) ENGINE=OLAP AGGREGATE KEY(`k1`, `k2`) PARTITION BY RANGE(`k1`) ( PARTITION p1 VALUES LESS THAN ('2019-05-31'), PARTITION p2 VALUES LESS THAN ('2019-06-30') ) DISTRIBUTED BY HASH(`k2`) BUCKETS 8 PROPERTIES ( "colocate_with" = "group1" ); CREATE TABLE `tbl2` ( `k1` datetime NOT NULL COMMENT "", `k2` int(11) NOT NULL COMMENT "", `v1` double SUM NOT NULL COMMENT "" ) ENGINE=OLAP AGGREGATE KEY(`k1`, `k2`) DISTRIBUTED BY HASH(`k2`) BUCKETS 8 PROPERTIES ( "colocate_with" = "group1" );
(2)編寫查詢語句,並查看執行計划,HASH JOIN處colocate 顯示為true,代表優化成功。
mysql> explain SELECT * FROM tbl1 INNER JOIN tbl2 ON (tbl1.k2 = tbl2.k2);