在工做中咱們常用的數據庫,數據庫通常存放的咱們系統中經常使用的數據,通常爲百萬級別。若是數據量龐大,達到千萬級、億級又須要對他們進行關聯運算,該怎麼辦呢?
前面咱們已經介紹了HDFS和MapReduce了,它倆結合起來可以進行各類運算,但是MapReduce的學習成本過高了,若是有一種工具能夠直接使用sql將hdfs中的數據查出來,並自動編寫mapreduce進行運算,這就須要使用到咱們的hive數據倉庫。java
Hive是基於Hadoop的一個數據倉庫工具,能夠將結構化的數據文件映射爲一張數據庫表,並提供類SQL查詢功能。
用戶接口:包括CLI、JDBC/ODBC、WebGUI
元數據存儲:一般是存儲在關係數據庫如 mysql,derby中。
解釋器、編譯器、優化器、執行器
sequenceDiagram 客戶端->>Hive處理轉換成MapReduce: 發送HSQL語句 Hive處理轉換成MapReduce->>MapReduce運行: 提交任務到Hadoop MapReduce運行->>執行結果文件放到HDFS或本地: 執行結果
--- | Hive | RDBMS |
---|---|---|
查詢語言 | HQL | SQL |
數據存儲 | HDFS | Raw Device or Local FS |
執行 | MapReduce | Excutor |
執行延遲 | 高 | 低 |
處理數據規模 | 大 | 小 |
索引 | 0.8版本後加入位圖索引 | 有複雜的索引 |
==hive中具備sql數據庫,用來存儲元數據信息(如:表的屬性,數據的位置)。hive只適合用來作批量數據統計分析。讀多寫少==node
db:在hdfs中表現爲hive.metastore.warehouse.dir目錄下的一個文件夾
table:在hdfs中表現爲所屬db目錄下的一個文件夾
external table:與table相似,不過其數據存放位置能夠在任意指定路徑。刪除表時只會刪除元數據,不會刪除實際數據
partition:在hdfs中表現爲table目錄下的子目錄
bucket: 在hdfs中表現爲同一個表目錄下根據hash散列以後的多個文件
單機版(內置關係型數據庫derby) 元數據庫mysql版 這裏使用經常使用的mysql版,使用derby的話不太方便,由於derby會將文件保存在你當前啓動的目錄。若是下次你換個目錄啓動,會發現以前保存的數據不見了。
mysql安裝僅供參考,不一樣版本mysql有各自的安裝流程。
# 刪除原有的mysql rpm -qa | grep mysql rpm -e mysql-libs-5.1.66-2.el6_3.i686 --nodeps rpm -ivh MySQL-server-5.1.73-1.glibc23.i386.rpm rpm -ivh MySQL-client-5.1.73-1.glibc23.i386.rpm # 修改mysql的密碼,並記得設置容許用戶遠程鏈接 /usr/bin/mysql_secure_installation # 登陸mysql mysql -u root -p
vi conf/hive-env.sh #配置其中的$hadoop_home
vi hive-site.xml #添加以下內容 <configuration> <!--配置mysql的鏈接地址--> <property> <name>javax.jdo.option.ConnectionURL</name> <value>jdbc:mysql://localhost:3306/hive?createDatabaseIfNotExist=true</value> <description>JDBC connect string for a JDBC metastore</description> </property> <!--配置mysql的驅動--> <property> <name>javax.jdo.option.ConnectionDriverName</name> <value>com.mysql.jdbc.Driver</value> <description>Driver class name for a JDBC metastore</description> </property> <!--配置登陸用戶名--> <property> <name>javax.jdo.option.ConnectionUserName</name> <value>root</value> <description>username to use against metastore database</description> </property> <!--配置登陸密碼--> <property> <name>javax.jdo.option.ConnectionPassword</name> <value>root</value> <description>password to use against metastore database</description> </property> </configuration>
安裝hive和mysql完成後,將mysql的鏈接jar包拷貝到$HIVE_HOME/lib目錄下 若是出現沒有權限的問題,在mysql受權
mysql -uroot -p #執行下面的語句 *.*:表示全部庫下的全部表 %:任何ip地址或主機均可以鏈接 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENDIFIED BY 'root' WITH GRANT OPTION; FLUSH PRIVILEGES;
到這一步其實已經安裝好了,可是因爲hadoop中的jline包版本和咱們安裝hive的jline包版本不一致,會致使hql沒法被執行。 所以咱們還要把hive的lib目錄中的jline.2.12.jar替換掉$HADOOP_HOME/share/hadoop/yarn/lib/jline.0.9.94.jar
bin/hive
1.bin/hive 2.bin/beeline !connect jdbc:hive2://server1:10000 3.bin/beeline -u jdbc:hive2://server1:10000 -n hadoop
create table tb_external(id int,name string) row format delimited fields terminated by',' location 'hdfs://kris/myhiveexternal';
在hdfs中已在對應路徑存在文件mysql
如今試試直接查詢sql
==爲了保證數據的安全,咱們通常把源數據表設置爲外部表。數據只能經過外部加載導入==shell
hive> create table student(id INT,age INT,name STRING) > partitioned by(stat_date STRING) > clustered by(id) sorted by(age) into 2 buckets > row format delimited fields terminated by ',';
alter table student add partition(stat_date='20190613') partition(stat_date='20190614'); alter table student add partition(stat_date='20190615') location '/user/hive/warehouse/student';
alter table student drop partition(stat_date='20190613');
建立的分區會在hdfs對應的路徑上建立文件夾數據庫
==若是增長的分區帶了路徑,那麼不會在hdfs的路徑上顯示對應的文件夾==瀏覽器
show partitions student;
alter table student rename to students;
alter table students add columns(name1 string);
==增長的列會在全部列後面,在partition列前面==安全
alter table students replace columns(id int,age int,name string);
#查看錶 show tables #查看數據庫 show databases #查看分區 show partitions table_name #查看方法 show functions #顯示錶詳細信息 desc extended table_name #格式話表信息 desc formatted table_name
使用load data操做 hive會將文件複製到表對應的hdfs文件夾下函數
load data local inpath "students1.txt" [overwrite] into table students partition(stat_date="20190614");
加上overwrite會講原有對應分區的數據清除。
若是目標表(分區)已經有一個文件,而且文件名和filepath中的文件名衝突,那麼現有的文件會被新文件所替代。工具
保存select查詢結果的幾種方式:
一、將查詢結果保存到一張新的hive表中
create table t_tmp as select * from t_p;
二、將查詢結果保存到一張已經存在的hive表中
insert into table t_tmp select * from t_p;
三、將查詢結果保存到指定的文件目錄(能夠是本地,也能夠是hdfs)
insert overwrite local directory '/home/hadoop/test' select * from t_p; insert overwrite directory '/aaa/test' select * from t_p;
插入分桶表的數據須要是已經分好桶的,建立分桶的表並不會自動幫咱們進行分桶。
#設置變量,設置分桶爲true, 設置reduce數量是分桶的數量個數 set mapreduce.job.reduces=2; # 或者選擇如下方式 set hive.enforce.bucketing = true; # 向分桶表中插入數據 insert into student partition(stat_date='20190614') select id,age,name from tmp_stu where stat_date='20190614' cluster by(id);
可見在hdfs上根據id分紅了兩個桶
讓咱們看看其中一個桶的內容
注意:
==1.order by 會對輸入作全局排序,所以只有一個reducer,會致使當輸入規模較大時,須要較長的計算時間。==
==2.sort by不是全局排序,它是在數據進去reduce task時有序。所以,若是用sort by進行排序,而且設置mapreduce.job.reduces>1,則sort by只保證每一個reduce task的輸出有序,不保證全局有序。==
==3.distribute by根據distribute by指定的內容將數據分到同一個reducer==
==4.cluster by除了具備distribute by的功能外,還會對該字段進行排序。所以咱們能夠這麼認爲cluster by=distribute by + sort by==
==可是cluster by只能指定同一字段,當咱們要對某一字段進行分桶,又要對另外一字段進行排序時,用distribute by + sort by更加靈活。==
==分桶表的做用:最大的做用是用來提升join操做的效率;==
思考:select a.id,a.name,b.addr from a join b on a.id=b.id;
若是a表和b表已是分桶表,並且分桶的字段是id字段。作這個join操做時,還須要全表作笛卡爾積嗎?(文末給出答案)
數據分桶的原理: 跟MR中的HashPartitioner的原理如出一轍 MR中:按照key的hash值去模除以reductTask的個數 Hive中:按照分桶字段的hash值去模除以分桶的個數 Hive也是 針對某一列進行桶的組織。Hive採用對列值哈希,而後除以桶的個數求餘的方式決定該條記錄存放在哪一個桶當中。
好處: 一、方便抽樣 二、提升join查詢效率
將數據導入分桶表主要經過如下步驟
第一步:
從hdfs或本地磁盤中load數據,導入中間表(也就是上文用到的tmp_stu)
第二步:
經過從中間表查詢的方式的完成數據導入 分桶的實質就是對 分桶的字段作了hash 而後存放到對應文件中,因此說若是原有數據沒有按key hash ,須要在插入分桶的時候hash, 也就是說向分桶表中插入數據的時候必然要執行一次MAPREDUCE,這也就是分桶表的數據基本只能經過從結果集查詢插入的方式進行導入
==咱們須要確保reduce 的數量與表中的bucket 數量一致,爲此有兩種作法==
1.讓hive強制分桶,自動按照分桶表的bucket 進行分桶。(推薦) set hive.enforce.bucketing = true; 2.手動指定reduce數量 set mapreduce.job.reduces = num; / set mapreduce.reduce.tasks = num; 並在 SELECT 後增長CLUSTER BY 語句 以爲不錯記得給我點贊加關注喔~ 公衆號:喜訊XiCent
本文由博客一文多發平臺 OpenWrite 發佈!