資料倉庫(十四)--java--presto---hive的分頁查詢
我們在SpringMVC框架中使用那個presto查詢hive的資料做展示時,發現在table裡分頁是個不可避免的話題。
建議去掉count
但是尷尬的是 對於海量資料 count的效率是很低的,因為在不加條件的情況下基本上要掃描全表。
count操作效能比較收集
oracle裡Count一億條資料 大於10分鐘
mysql,3000萬行記錄,count(*)需要200s
hive+presto count 8499萬條記錄 需要30s
效率對比如圖:
查詢準確資料只用了214毫秒,查詢數量count卻花了39秒的時間,如果我們要先獲取準確的數量的話就做不到迅速響應的查詢。
所以我們建議在海量資料列表顯示時去掉count,預設給比較大的數值,包含所有的資料量。
如果需要準確count的場景,建議增加下拉框選擇準確count的模式下再去查詢count並說明該模式需要更長的查詢時間。
如何分頁
在使用hive的sql語句查詢時,很悲傷的發現hive的sql沒有limit 5,20 的用法,只有limit 20,只能限制條數,不支援直接跳過多少條資料。
還好hive支援使用where id between 10 to 20 或者 時間。
例如
select *
from table t1
where t1.DATE_COLUMN
between cast(from_unixtime(unix_timestamp(),'yyyy-MM-01 00:00:00') as timestamp)
and cast(from_unixtime(unix_timestamp()) as timestamp)
;
limit 與between的區別在於
limit是根據查詢出的結果裡進行跳過和條數限制。
between則作為查詢條件來使用。如果針對全量表 between是比較好進行分頁的。 但是對於有查詢條件的時候,between就比較複雜了,因為查詢條件查出來的資料 列的值的範圍是多少 我們並不知道。
所以 需要另外的一種 分頁邏輯,數值型別int型別的自增id。
只要id的排序順序一定,無論我們的查詢條件是什麼,查詢出來的資料都是有序的,而且id有範圍。
使用命令如下:
#獲取第一頁資料:
select * from table where type=2 order by id asc limit 10;
#獲取第二頁資料:
#需要獲取第一頁10條中最大的id為preId,作為下一頁的條件。
int preId=select max(id) from table where type=2 order by id asc limit 10;
select * from table where type=2 and id >preId order by id asc limit 10;
#獲取第三頁資料:
#需要獲取2頁20條中最大的id為preId,作為下一頁的條件。
int preId=select max(id) from table where type=2 order by id asc limit 20;
select * from table where type=2 and id >preId order by id asc limit 10;
總結
可以看到第一個limit的數值是跳過的條數,第二個limit是每頁的條數。
自增列id生成
在我們設計的hive分頁邏輯中,很重要的一個輔助欄位就是唯一不重複的自增id。
這個在把資料寫入分散式叢集時如何生成不重複的自增數值id目前還沒有找到很好的方法。
但是 通過hive的row_number()方法可以很好的在新表中統一生成自增列。
使用命令
create table chip_pt(id BIGINT,position string,rs string,linenum string,filename string,createdate string) partitioned by (chromosome string);
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
set hive.exec.max.dynamic.partitions.pernode=100000;
set hive.exec.max.dynamic.partitions.pernode.Maximum=100000;
set hive.exec.max.dynamic.partitions=100000;
set hive.exec.max.created.files=100000;
set mapred.max.split.size=1024000000;
set mapred.min.split.size.per.node=1024000000;
set mapred.min.split.size.per.rack=1024000000;
set mapred.reduce.tasks=100;
set hive.map.aggr=true;
set hive.groupby.skewindata=true;
set hive.enforce.bucketing = true;
insert overwrite table chip_pt
partition(chromosome)
select row_number() over (order by position) as id,position,rs,linenum,filename,createdate,chromosome from chip;
注意id必須使用int型別才能很好的進行排序分頁。
當然這種方式針對海量資料來說還是有點麻煩,也就是每次有更新資料都得重新生成一次帶有自增列的新表。
除此之外 自己在寫入hive時維護自增列也是一種思路,不過比較麻煩而且容易有重複的自增id。
總結
hive表格由於資料量大,所以要做分頁還是比較麻煩的,所以在程式設計時儘可能的避免的分頁場景。