1. 程式人生 > >HAWQ技術解析(六) —— 定義物件

HAWQ技術解析(六) —— 定義物件

        HAWQ本質上是一個數據庫系統,所以這裡所說的物件指的是資料庫物件。和其它關係資料庫類似,HAWQ中有資料庫、表空間、表、檢視、自定義資料型別、自定義函式、序列等物件。本篇將簡述這些物件的建立與管理。對HAWQ中表的儲存方式與分佈策略等特性的選擇,會對資料庫效能產生極大的影響,同時這也是一個複雜的話題,將在下一篇單獨討論。

一、建立和管理資料庫
        HAWQ中資料庫的概念與MySQL類似,一個HAWQ例項中通常會建立多個數據庫,這和Oracle中資料庫的概念不同。在Oracle體系結構中,資料庫是一個“最大”的概念,大多數情況下一個Oracle資料庫對應一個例項,RAC是一個數據庫對應多個例項。儘管可以在一個HAWQ系統中建立很多資料庫,但是客戶端程式在某一時刻只能連線到一個數據庫,這也決定了HAWQ不能執行跨庫的查詢。

1. 模板資料庫
        HAWQ初始化後, 就有了template0和template1兩個模板庫,開始時這兩個庫的內容是一樣的,並且template0庫和template1都不可刪除。兩者最主要的區別是,預設時可以連線template1並在其中建立物件,但不能連線template0。
        不能刪除模板資料庫:
gpadmin=# drop database template0;
ERROR:  cannot drop a template database
gpadmin=# drop database template1;
ERROR:  cannot drop a template database
gpadmin=# drop database postgres;
ERROR:  cannot drop a template database
        預設時不能連線template0,但可以連線template1:
gpadmin=# \c template0
FATAL:  database "template0" is not currently accepting connections
Previous connection kept
gpadmin=# \c template1
You are now connected to database "template1" as user "gpadmin".
        每一個新建立的資料庫都基於一個模板,建庫時如果不指定 TEMPLATE屬性,預設用的是template1模板庫。除非希望某些物件在每一個新建立的資料庫中都存在,不要在template1中建立任何物件。
        template1是預設模板,並且其中的物件和資料會被克隆到每個以它為模板的新建資料庫中:
template1=# create table t1 (a int);
CREATE TABLE
template1=# insert into t1 values (1);
INSERT 0 1
template1=# create database db1;
CREATE DATABASE
template1=# \dt
               List of relations
 Schema | Name | Type  |  Owner  |   Storage   
--------+------+-------+---------+-------------
 public | t1   | table | gpadmin | append only
(1 row)

template1=# select * from t1;
 a 
---
 1
(1 row)
        HAWQ還有一個模板庫postgres。不要修改template0或postgres,HAWQ內部需要使用它們。以template0為模板可以建立一個完全乾淨的資料庫,其中只包含HAWQ在初始化時預定義的標準物件。如果修改了template1,可能就需要這麼做。
        指定以template0為模板建立資料庫:
template1=# create database db2 with template template0;
CREATE DATABASE
        通過配置,也可以連線template0:
template1=# set allow_system_table_mods='DML'; 
SET
template1=# update pg_database set datallowconn='t' where datname='template0'; 
UPDATE 1
template1=# \c template0
You are now connected to database "template0" as user "gpadmin".
template0=# update pg_database set datallowconn='f' where datname='template0'; 
ERROR:  permission denied: "pg_database" is a system catalog
template0=# set allow_system_table_mods='DML'; 
SET
template0=# update pg_database set datallowconn='f' where datname='template0'; 
UPDATE 1
template0=# \q
[
[email protected]
~]$ psql -d template0 psql: FATAL: database "template0" is not currently accepting connections

2. 建立資料庫
        建立資料庫的使用者必須要適當的許可權,比如超級使用者,或者被設定了createdb角色屬性。除了象前面例子中,使用CREATE DATABASE命令建立資料庫,還可以使用客戶端程式createdb建立一個數據庫。例如,執行下面的命令將連線HAWQ主機並建立名為db3的資料庫,主機名和埠號必須與HAWQ的master節點相匹配。
[[email protected] ~]$ createdb -h hdp3 -p 5432 db3
[[email protected] ~]$ psql -h hdp3
psql (8.2.15)
Type "help" for help.

gpadmin=# \l
                 List of databases
   Name    |  Owner  | Encoding | Access privileges 
-----------+---------+----------+-------------------
 db1       | gpadmin | UTF8     | 
 db2       | gpadmin | UTF8     | 
 db3       | gpadmin | UTF8     | 
 gpadmin   | gpadmin | UTF8     | 
 postgres  | gpadmin | UTF8     | 
 template0 | gpadmin | UTF8     | 
 template1 | gpadmin | UTF8     | 
(7 rows)
        某些物件,如角色(使用者),是被HAWQ中的所有資料庫所共享的。而另外一些物件,如表,則只有它所在的資料庫能感知它的存在。

3. 檢視資料庫列表
        psql客戶端程式的\l元命令顯示資料庫列表。如果是資料庫超級使用者,也可以從pg_database系統目錄表中查詢資料庫列表。
gpadmin=# \l
                 List of databases
   Name    |  Owner  | Encoding | Access privileges 
-----------+---------+----------+-------------------
 db1       | gpadmin | UTF8     | 
 db2       | gpadmin | UTF8     | 
 db3       | gpadmin | UTF8     | 
 gpadmin   | gpadmin | UTF8     | 
 postgres  | gpadmin | UTF8     | 
 template0 | gpadmin | UTF8     | 
 template1 | gpadmin | UTF8     | 
(7 rows)

gpadmin=# select datname from pg_database;
  datname  
-----------
 hcatalog
 template1
 postgres
 gpadmin
 template0
 db1
 db2
 db3
(8 rows)
        可以看到,從pg_database查詢出的結果比\l命令多返回一個庫名為hcatalog。此庫僅HAWQ系統使用,並且不允許連線。
gpadmin=# \c hcatalog
FATAL:  "hcatalog" database is only for system use
Previous connection kept

4. 修改資料庫
        ALTER DATABASE命令可以用於修改資料庫的預設配置,如下面的命令修改search_path伺服器配置引數,改變資料庫db1預設的模式查詢路徑。
gpadmin=# alter database db1 set search_path to myschema, public, pg_catalog;
NOTICE:  schema "myschema" does not exist
ALTER DATABASE
        HAWQ不支援修改資料庫改名。
gpadmin=# alter database db1 rename to db11;
ERROR:  Cannot support rename database statement yet

5. 刪除資料庫
        DROP DATABASE命令刪除一個數據庫。它刪除資料庫在系統目錄中的條目,並刪除磁碟上的資料。只有資料庫屬主或超級使用者才能刪除資料庫。並且,不能刪除一個還有連線的資料庫,包括不能刪除自己當前會話連線的資料庫。在刪除一個數據庫前,可先連線到template1或其它資料庫。
gpadmin=# \c template1
You are now connected to database "template1" as user "gpadmin".
template1=# drop database db1;
DROP DATABASE
        也可以使用客戶端程式dropdb刪除一個數據庫。
[[email protected] ~]$ dropdb -h hdp3 -p 5432 db2
        一個數據庫有連線時是不允許刪除的,必須先終止所有連線,在沒有連線之後再刪除資料庫。
gpadmin=# drop database db3;
ERROR:  database "db3" is being accessed by other users
gpadmin=# select procpid,current_query from pg_stat_activity where datname='db3';
 procpid | current_query 
---------+---------------
  790583 | <IDLE>
(1 row)

gpadmin=# select pg_terminate_backend(790583);
 pg_terminate_backend 
----------------------
 t
(1 row)

gpadmin=# drop database db3;
DROP DATABASE
        注意,刪除資料庫操作是不可回滾的。

二、建立和管理表空間
        很多資料庫系統,如Oracle和MySQL等,都有表空間的概念。HAWQ的表儲存在HDFS上,其表空間管理有自己的特點。HAWQ在表空間之上有一個檔案空間的概念,系統中所有元件的檔案系統位置的集合構成一個檔案空間。檔案空間可以被一個或多個表空間所使用。實際上,一個檔案空間物理上就是一個HDFS的目錄及其子目錄。在表空間定義中需要指定它所屬檔案空間。一個檔案空間下的所有表空間檔案都儲存在該檔案空間所對應的HDFS目錄下。
        表空間允許為經常使用和不經常使用的資料庫物件賦予不同的儲存,或控制特定資料庫物件的I/O效能。例如,將經常使用的表放在高效能檔案系統(如SSD)上,而將其它表放在普通標準硬碟上。通過這種方式,DBA可以在HAWQ叢集中使用多個HDFS目錄,靈活規劃資料庫物件的物理儲存。

1. 建立檔案空間
        檔案空間是一個符號儲存識別符號,對映為一組HAWQ主機檔案系統的位置,指示HAWQ系統的儲存空間。為了建立一個檔案空間,需要在HAWQ叢集上準備HDFS檔案系統目錄,然後使用hawq filespace應用程式定義檔案空間。必須以資料庫超級使用者建立一個檔案空間。
        注意,HAWQ並不直接感知底層的檔案系統邊界。它將檔案儲存在所指定的目錄中,但不能人為控制邏輯檔案系統中單個檔案的磁碟位置。

(1)為檔案空間準備HDFS目錄
[[email protected] ~]# su - hdfs
[[email protected] ~]$ hdfs dfs -mkdir /hawq_data1
[[email protected] ~]$ hdfs dfs -chown -R gpadmin:gpadmin /hawq_data1
(2)用gpadmin使用者登入HAWQ master
$ su - gpadmin
(3)建立一個檔案空間配置檔案:
$ hawq filespace -o hawqfilespace_config
(4)在提示符下,輸入檔案空間的名字、master檔案系統位置和segment檔案系統位置。
[[email protected] ~]$ hawq filespace -o hawqfilespace_config
Enter a name for this filespace
> testfs
Enter replica num for filespace. If 0, default replica num is used (default=3)
> 

Please specify the DFS location for the filespace (for example: localhost:9000/fs)
location> mycluster/hawq_data1
20170306:11:24:52:352152 hawqfilespace:hdp3:gpadmin-[INFO]:-[created]
20170306:11:24:52:352152 hawqfilespace:hdp3:gpadmin-[INFO]:-
To add this filespace to the database please run the command:
   hawqfilespace --config /home/gpadmin/hawqfilespace_config

[[email protected] ~]$ more /home/gpadmin/hawqfilespace_config
filespace:testfs
fsreplica:3
dfs_url::mycluster/hawq_data1
[[email protected] ~]$ hawq filespace --config /home/gpadmin/hawqfilespace_config
Reading Configuration file: '/home/gpadmin/hawqfilespace_config'

CREATE FILESPACE testfs ON hdfs 
('mycluster/hawq_data1/testfs') WITH (NUMREPLICA = 3);
20170306:11:25:50:352658 hawqfilespace:hdp3:gpadmin-[INFO]:-Connecting to database
20170306:11:25:50:352658 hawqfilespace:hdp3:gpadmin-[INFO]:-Filespace "testfs" successfully created
        此時HDFS上會看到建立了/hawq_data1/testfs目錄。
[[email protected] ~]$ hdfs dfs -ls /hawq_data1
Found 1 items
drwx------   - gpadmin gpadmin          0 2017-03-07 14:32 /hawq_data1/testfs

2. 建立表空間
        建立完檔案空間,使用CREATE TABLESPACE命令定義一個使用該檔案空間的表空間。
gpadmin=# create tablespace testts filespace testfs;
CREATE TABLESPACE
        目前HAWQ只允許資料庫超級使用者定義表空間,並且不支援向其他使用者GRANT/REVOKE表空間上的CREATION許可權。
gpadmin=# create user wxy with superuser login password 'mypassword';
CREATE ROLE
gpadmin=# grant create on tablespace testts to wxy;
ERROR:  Cannot support GRANT/REVOKE on TABLESPACE statement
        相關資訊參見https://issues.apache.org/jira/browse/HAWQ-24

3. 使用表空間儲存資料庫物件
        擁有表空間上CREATE許可權的使用者能夠在此表空間中建立資料庫物件,例如資料庫、表等。使用default_tablespace引數,為沒有指定表空間的CREATE TABLE語句指定預設表空間。
        與一個數據庫關聯的表空間儲存資料庫的系統目錄、資料庫的伺服器程序建立的臨時檔案、資料庫中建立時沒有指定TABLESPACE的表。如果建立資料庫時不指定表空間,資料庫使用其模板資料庫相同的表空間。如果有適當的許可權,可以在任意資料庫中使用一個表空間。
[[email protected] ~]$ psql -d template1 -U wxy -h hdp3
template1=# create database db1 tablespace testts;
CREATE DATABASE
template1=# \c db1
You are now connected to database "db1" as user "wxy".
db1=# create table t1 (a int);
CREATE TABLE
db1=# create table t2 (a int) tablespace testts;
CREATE TABLE
db1=# set default_tablespace = testts;
SET
db1=# create table t3 (a int);
CREATE TABLE
db1=# set default_tablespace = dfs_default;
SET
db1=# create table t4 (a int);
CREATE TABLE
db1=# select relname,reltablespace from pg_catalog.pg_class where relname in ('t1','t2','t3','t4');
 relname | reltablespace 
---------+---------------
 t1      |             0
 t2      |             0
 t3      |             0
 t4      |         16385
(4 rows)
        pg_class.reltablespace為0,說明表儲存在從資料庫繼承的預設表空間testts裡。特別要指出的是,所有非共享的系統表也都存放在這裡。

4. 查看錶空間和檔案空間
        每個HAWQ系統有以下預設表空間:
  • pg_global是共享系統目錄的表空間。
  • pg_default是預設表空間,template1和template0資料庫使用。
        這些表空間使用系統預設的檔案空間,pg_system,指示系統初始化時建立的資料目錄位置。pg_filespace和pg_filespace_entry目錄表儲存檔案空間資訊。可以將這些表與pg_tablespace關聯檢視完整的表空間的定義,例如:
db1=# select spcname as tblspc, fsname as filespc,
db1-#           fsedbid as seg_dbid, fselocation as datadir
db1-#    from   pg_tablespace pgts, pg_filespace pgfs,
db1-#           pg_filespace_entry pgfse
db1-#    where  pgts.spcfsoid=pgfse.fsefsoid
db1-#           and pgfse.fsefsoid=pgfs.oid
db1-#    order by tblspc, seg_dbid;
   tblspc    |  filespc   | seg_dbid |                    datadir                    
-------------+------------+----------+-----------------------------------------------
 dfs_default | dfs_system |        0 | hdfs://mycluster/hawq_data
 testts      | testfs     |        0 | hdfs://{replica=3}mycluster/hawq_data1/testfs
(2 rows)

5. 刪除表空間和檔案空間
        只有表空間的屬主或超級使用者可以刪除表空間。直到表空間所有的資料庫物件都被刪除後,才能刪除表空間。
postgres=# drop tablespace testts;
ERROR:  tablespace "testts" is not empty: existing database.
postgres=# drop filespace testfs;
ERROR:  filespace "testfs" is not empty
postgres=# drop database db1;
DROP DATABASE
postgres=# drop filespace testfs;
ERROR:  filespace "testfs" is not empty
postgres=# drop tablespace testts;
DROP TABLESPACE
postgres=# drop filespace testfs;
DROP FILESPACE
postgres=#
          此時HDFS上的/hawq_data1/testfs目錄已經刪除。
[[email protected] ~]$ hdfs dfs -ls /hawq_data1/testfs
ls: `/hawq_data1/testfs': No such file or directory
[[email protected] ~]$

三、建立和管理模式
        模式(schema)是一個有趣的概念,不同資料庫系統中的模式代表完全不同的東西。如Oracle中,預設在建立使用者的時候,就建立了一個和使用者名稱一樣的模式,並且互相繫結,因此很多情況下Oracle的使用者和模式可以通用。MySQL中的schema是database的同義詞。而HAWQ中的模式是從PostgreSQL來的,其概念與SQLserver的模式更為類似,是資料庫中的邏輯物件。
        HAWQ的模式是資料庫中物件和資料的邏輯組織。模式允許在一個數據庫中有多個同名的物件,如表。如果物件屬於不同的模式,同名物件之間不會衝突。使用schema有如下好處:
  • 方便管理多個使用者共享一個數據庫,但是又可以互相獨立。
  • 方便管理眾多物件,更有邏輯性。
  • 方便相容某些第三方應用程式,如果建立物件時是帶schema的。
        比如要設計一個複雜系統,由眾多模組構成,有時候模組間又需要有獨立性。各模組存放單獨的資料庫顯然是不合適的。這時候使用schema來劃分各模組間的物件,再對使用者進行適當的許可權控制,這樣邏輯也非常清晰。

1. 預設的“Public”模式
        每個資料庫有一個預設的名為public的模式。如果不建立任何模式,物件則被建立在public模式中。所有資料庫角色(使用者)都具有public模式中的CREATE和USAGE許可權。當建立了一個模式,需要給使用者授予訪問模式的許可權。

2. 建立模式
        使用CREATE SCHEMA命令建立一個新模式。為了在模式中建立和訪問物件,完整的物件名稱由模式名+物件名組成,物件名和模式名稱用點號分隔。可以建立一個屬於其他人的模式,語法是:CREATE SCHEMA <schemaname> AUTHORIZATION <username>;

3. 模式查詢路徑
        可以設定search_path配置引數指定資料庫物件有效模式的查詢順序。查詢路徑列表中的第一個存在的模式為預設模式。如果沒有指定模式,物件在預設模式中建立。
(1)設定模式查詢路徑
        search_path配置引數設定模式查詢順序。ALTER DATABASE命令設定查詢路徑
ALTER DATABASE db1 SET search_path TO u1,public, pg_catalog;
(2)檢視當前模式
        使用current_schema()函式檢視當前模式。
SELECT current_schema();
        使用SHOW命令檢視當前查詢路徑。
SHOW search_path;
        set search_path to my_schema;只能改變當前session,如果需要長久生效可以為使用者建立一個變數:
alter role etl set search_path=trade;
        官方建議是這樣的:在管理員建立一個具體資料庫後,應該為所有可以連線到該資料庫的使用者分別建立一個與使用者名稱相同的模式,然後,將search_path設定為"$user",即預設的模式是與使用者名稱相同的模式。
4. 刪除模式
        使用DROP SCHEMA命令刪除一個模式。
DROP SCHEMA myschema;
        預設時,模式必須為空後才能刪除它。為了刪除一個非空的模式,可以使用:DROP SCHEMA <schemaname> CASCADE;
        該命令將刪除模式及該模式下的所有物件(表、資料、函式等等)。

5. 系統模式
        使用psql的\dn元命令檢視當前連線資料庫的所有模式。
gpadmin=# \dn
       List of schemas
        Name        |  Owner  
--------------------+---------
 hawq_toolkit       | gpadmin
 information_schema | gpadmin
 pg_aoseg           | gpadmin
 pg_bitmapindex     | gpadmin
 pg_catalog         | gpadmin
 pg_toast           | gpadmin
 public             | gpadmin
(7 rows)
        以下是每個資料庫中系統級別的模式:
  • pg_catalog:包含系統目錄表,內建資料型別、函式和操作符等。它總是模式查詢路徑的一部分,即使在查詢路徑中沒有顯式命名。
  • information_schema:由一系列標準檢視構成的資料庫物件資訊。用\dv information_schema.*元命令列出該模式下的檢視。這些檢視以標準方式從系統目錄表獲取系統資訊
  • pg_toast:儲存大小超過頁尺寸的大物件。這個模式被HAWQ系統內部使用。
  • pg_bitmapindex:儲存點陣圖索引物件,如值列表。該模式被HAWQ系統內部使用。
  • hawq_toolkit:管理模式,包含可以從SQL命令訪問的外部表、檢視和函式。所有資料庫使用者可以訪問hawq_toolkit查詢系統日誌檔案或系統指標。
  • pg_aoseg:儲存AO(Append-optimized)型別表物件的資訊。該模式被HAWQ系統內部使用。
6. 模式示例
# 修改master的pg_hba.conf檔案,增加三個使用者u1、u2、u3的認證
[[email protected] ~]$ vi /data/hawq/master/pg_hba.conf
...
host  all     u1         172.16.1.0/24         md5
host  all     u2         172.16.1.0/24         md5
host  all     u3         172.16.1.0/24         md5

# 使認證檔案生效
[[email protected] ~]$ more /data/hawq/master/pg_hba.conf

# 建立資料庫db1
[[email protected] ~]$ createdb db1

# 使用gpadmin建立兩個使用者u1、u2,授予超級使用者許可權,
[[email protected] ~]$ psql -c "create role u1 with superuser password 'mypassword' login;create role u2 with superuser password 'mypassword' login;"

# 使用gpadmin在db1資料庫中建立兩個與使用者u1、u2同名的schema,並指定對應的屬主。此情況模擬Oracle的使用者模式。
[[email protected] ~]$ psql -d db1 -c "create schema u1 authorization u1; create schema u2 authorization u2;"

# 用u1使用者執行
[[email protected] ~]$ psql -d db1 -U u1 -h hdp3 -c "create table t1 (a int); insert into t1 values(1);"

# 用u2使用者執行
[[email protected] ~]$ psql -d db1 -U u2 -h hdp3 -c "create table t1 (a int); insert into t1 values(2);"

# 用u1使用者執行
[[email protected] ~]$ psql -d db1 -U u1 -h hdp3 -c "select *,current_schema() from t1;"
Password for user u1: 
 a | current_schema 
---+----------------
 1 | u1
(1 row)

# 用u2使用者執行
[[email protected] ~]$ psql -d db1 -U u2 -h hdp3 -c "select *,current_schema() from t1;"
Password for user u2: 
 a | current_schema 
---+----------------
 2 | u2
(1 row)

# 用gpadmin使用者執行
[[email protected] ~]$ psql -d db1 -h hdp3 -c "create table t1(a int);insert into t1 values(3);"
INSERT 0 1
[[email protected] ~]$ psql -d db1 -h hdp3 -c "select * from pg_tables where tablename='t1';"
 schemaname | tablename | tableowner | tablespace | hasindexes | hasrules | hastriggers 
------------+-----------+------------+------------+------------+----------+-------------
 u1         | t1        | u1         |            | f          | f        | f
 u2         | t1        | u2         |            | f          | f        | f
 public     | t1        | gpadmin    |            | f          | f        | f
(3 rows)

[[email protected] ~]$ psql -d db1
psql (8.2.15)
Type "help" for help.

db1=# show search_path;
  search_path   
----------------
 "$user",public
(1 row)

db1=# select * from t1;
 a 
---
 3
(1 row)

db1=# set search_path='u1';
SET
db1=# select * from t1;
 a 
---
 1
(1 row)

db1=# set search_path='u2';
SET
db1=# select * from t1;
 a 
---
 2
(1 row)

# 建立只有login許可權的使用者u3
[[email protected] ~]$ psql -c "create role u3 with password 'mypassword' login;"
NOTICE:  resource queue required -- using default resource queue "pg_default"
CREATE ROLE
# 用u3使用者執行
[[email protected] ~]$ psql -d db1 -U u3 -h hdp3
Password for user u3: 
psql: FATAL:  password authentication failed for user "u3"
[[email protected] ~]$ psql -d db1 -U u3 -h hdp3
Password for user u3: 
psql (8.2.15)
Type "help" for help.

db1=> set search_path='u1';
SET
db1=> db1=> \dt
No relations found.
db1-> 

# 可以看到,u3看不到表u1.t1。

# 賦予usage許可權
[[email protected] ~]$ psql -d db1 -c "grant usage on schema u1 to u3;"
GRANT
# 用u3使用者執行
[[email protected] ~]$ psql -d db1 -U u3 -h hdp3
Password for user u3: 
psql (8.2.15)
Type "help" for help.

db1=> set search_path='u1';
SET
db1=> \dt
              List of relations
 Schema | Name | Type  | Owner |   Storage   
--------+------+-------+-------+-------------
 u1     | t1   | table | u1    | append only
(1 row)

db1=> select * from t1;
ERROR:  permission denied for relation t1
db1=> 

# 可以看到,u3可以看到表u1.t1,但不能查詢。

# 賦予select許可權
[[email protected] ~]$ psql -d db1 -c "grant select on u1.t1 to u3;"
GRANT
# 用u3使用者執行
[[email protected] ~]$ psql -d db1 -U u3 -h hdp3 -c "set search_path='u1';select *,current_schema(),current_schemas(true) from t1;"
Password for user u3: 
 a | current_schema | current_schemas 
---+----------------+-----------------
 1 | u1             | {pg_catalog,u1}
(1 row)

# u3現在可以查詢u1.t1。

# 用u3使用者執行
[[email protected] ~]$ psql -d db1 -U u3 -h hdp3 -c "create table t2(a int);"
Password for user u3: 
CREATE TABLE

# 刪除模式
[[email protected] ~]$ psql -h hdp3 -d db1
psql (8.2.15)
Type "help" for help.

db1=# drop schema u1;
NOTICE:  append only table u1.t1 depends on schema u1
ERROR:  cannot drop schema u1 because other objects depend on it
HINT:  Use DROP ... CASCADE to drop the dependent objects too.
db1=# drop schema u1 cascade;
NOTICE:  drop cascades to append only table u1.t1
DROP SCHEMA
db1=# drop schema u2 cascade;
NOTICE:  drop cascades to append only table u2.t1
DROP SCHEMA
        說明:
  • 搜尋路徑引數search_path控制查詢表時所屬schema的搜尋順序。
  • 建立的表存放哪個schema跟search_path有關。
  • 系統預設將PUBLIC模式的usage、create許可權授權給所有使用者。
  • usage許可權的含義是,可以“看到”模式中的物件,但是沒有物件上的任何許可權。
  • pg_catalog存放了各系統表、內建函式等等。它總是在搜尋路徑中,需要通過current_schemas看到。
四、建立和管理表
        這裡所說的表是HAWQ資料庫內部儲存的表。除了錶行是分佈在系統中不同的segment上,HAWQ中的表與關係資料庫中的表類似。關於外部表,將在後面“外部資料”中討論。

1. 建立表
CREATE TABLE命令建立表並定義表結構,當建立一個表時,可以定義:
  • 表列及其資料型別。
  • 表或列包含的限定資料的約束。
  • 表的分佈策略,決定HAWQ如何在segment中劃分資料。
  • 表在磁碟上的儲存方式。
  • 大表分割槽策略,指定資料如何劃分。
(1)選擇列的資料型別
        列的資料型別決定了列中可以包含何種型別的資料。選擇資料型別時應遵循以下通用原則:
  • 選擇可以容納資料的最小可能空間,並能最好約束資料的資料型別。例如,如果可以使用INT或SMALLINT表示資料,那麼就不要使用BIGINT,因為這會浪費儲存空間。
  • 在HAWQ中,字元型別CHAR、VARCHAR和TEXT除了使用空間不同,它們在效能上並無差異。在大多數情況下,應該使用TEXT或VARCHAR而不是CHAR。
  • 考慮資料擴充套件。資料會隨著時間的推移而不斷擴充套件。在已經裝載大量資料後,從小型別變為大型別的操作代價是很昂貴的。因此,如果當前的資料值可以用SMALLINT,但是考慮到資料擴充套件性,那麼出於長期需要,INT是可能更好的選擇。
  • 為表連線的列使用相同的資料型別。如果資料型別不同,為了正確比較資料值,資料庫必須進行資料型別轉換,這將增加不必要的系統消耗。
        HAWQ內建的資料型別參見http://hawq.incubator.apache.org/docs/userguide/2.1.0.0-incubating/reference/HAWQDataTypes.html

(2)設定約束
        可以定義約束限制表中的資料。HAWQ支援與PostgreSQL相同的約束,但是有一些限制,包括:
  • CHECK約束只能引用它定義所屬的表。
  • 外來鍵約束允許,但不起作用。
  • 分割槽表上的約束作用於整個表。不能在一個表的單獨部分上定義約束。
        Check約束
        Check約束允許指定特定列中儲存的資料值必須滿足一個布林表示式。例如,產品價格必須為正值:
db1=# create table products
        ( product_no integer,
          name text,
          price numeric check (price > 0) );
db1=# insert into products values (1,'a',10);
INSERT 0 1
db1=# insert into products values (1,'a',10.5);
INSERT 0 1
db1=# insert into products values (1,'a',10.5111);
INSERT 0 1
db1=# insert into products values (1,'a',-10.5111);
ERROR:  One or more assertions failed  (seg0 hdp3:40000 pid=731975)
DETAIL:  Check constraint products_price_check for table products was violated
db1=# insert into products values (1,'a',0);
ERROR:  One or more assertions failed  (seg0 hdp3:40000 pid=731988)
DETAIL:  Check constraint products_price_check for table products was violated
db1=# select * from products;
 product_no | name |  price  
------------+------+---------
          1 | a    |      10
          1 | a    |    10.5
          1 | a    | 10.5111
(3 rows)

        非空約束
        非空約束指定一個列不能有空值。非空約束總是一個列約束。
db1=# create table products
        ( product_no integer not null,
          name text not null,
          price numeric );	   
db1=# insert into products values(1,'a',10.51);
INSERT 0 1
db1=# insert into products (price) values(10.51);
ERROR:  null value in column "product_no" violates not-null constraint (CTranslatorUtils.cpp:2726)
db1=#
  
        主鍵與外來鍵
        HAWQ不支援主鍵與外來鍵約束。因為主鍵是用唯一索引實現,而HAWQ不支援索引,因此不支援主鍵。根據外來鍵的定義,既然沒有主鍵,也就談不上外來鍵了。
db1=# create table t2(a int);
CREATE TABLE
db1=# create table t3(a int primary key);
ERROR:  Cannot support create index statement yet

2. 刪除表
        DROP TABLE命令從資料庫中刪除表。DROP TABLE總是刪除表上的約束。指定CASCADE將刪除引用表的檢視。
db1=# create table t1 (a int);
CREATE TABLE
db1=# insert into t1 values (1);
INSERT 0 1
db1=# create view v1 as select * from t1;
CREATE VIEW
db1=# select * from v1;
 a 
---
 1
(1 row)

db1=# drop table t1;
NOTICE:  rule _RETURN on view v1 depends on append only table t1
NOTICE:  view v1 depends on rule _RETURN on view v1
ERROR:  cannot drop append only table t1 because other objects depend on it
HINT:  Use DROP ... CASCADE to drop the dependent objects too.
db1=# drop table t1 cascade;
NOTICE:  drop cascades to rule _RETURN on view v1
NOTICE:  drop cascades to view v1
DROP TABLE
        如果要清空表中的資料,但保留表定義,使用TRUNCATE <tablename>。

3. 查看錶對應的HDFS檔案

        假設在資料庫db1中建立了表public.t2,使用以下步驟檢視t2所在的HDFS檔案。
(1)確定HAWQ在HDFS上的根目錄
db1=# select * from pg_filespace_entry;
 fsefsoid | fsedbid |        fselocation         
----------+---------+----------------------------
    16384 |       0 | hdfs://mycluster/hawq_data
(1 row)
        可以看到,HAWQ在HDFS上的根目錄/hawq_data。我的Hadoop叢集配置了HA,所以檔案位置欄位中的值使用Nameservice ID(mycluster)代替了NameNode FQDN(Fully Qualified Domain Name)。

(2)檢查HAWQ系統目錄表中t1的相關資訊
db1=# select d.dat2tablespace tablespace_id, d.oid database_id, c.relfilenode table_id
db1-#   from pg_database d, pg_class c, pg_namespace n 
db1-#  where c.relnamespace = n.oid
db1-#    and d.datname = current_database()
db1-#    and n.nspname = 'public'
db1-#    and c.relname = 't2';
 tablespace_id | database_id | table_id 
---------------+-------------+----------
         16385 |       25270 |   156634
(1 row)
        一個數據庫中不同schema下的表可能重名,但對應的表ID不同,因此需要關聯pg_namespace系統表。d.oid是一個系統的隱藏列,表示行的物件識別符號(物件ID)。該列只有在建立表的時候使用了WITH OIDS ,或者是設定了default_with_oids配置引數時出現。用\d pg_database命令是看不到oid列的。系統表pg_class的relhasoids列是布林型別,true表示物件具有OID。
        為了簡化對錶的管理,每個表中的資料都被儲存在一個HDFS目錄中。HAWQ資料庫表在HDFS上的目錄結構為“檔案空間根目錄/表空間ID/資料庫ID/表物件(分割槽表物件)ID”,例如表public.t2所對用的HDFS目錄為/hawq_data/16385/25270/156634,該目錄下是實際儲存表資料的HDFS檔案。

(3)查看錶對應的HDFS檔案
[[email protected] ~]$ hdfs dfs -ls /hawq_data/16385/25270/156634
Found 1 items
-rw-------   3 gpadmin gpadmin          0 2017-03-30 11:05 /hawq_data/16385/25270/156634/1

五、建立和管理檢視
        檢視使能夠儲存經常使用的或者複雜的查詢,然後將它們看做表,在SELECT語句中訪問它們。檢視並不物化到磁碟,當訪問檢視時,查詢作為一個子查詢執行。HAWQ不支援WITH子句的內嵌檢視和物化檢視。

1. 建立檢視
db1=# create table t1 (a int);
CREATE TABLE
db1=# insert into t1 values (10);
INSERT 0 1
db1=# insert into t1 values (1);
INSERT 0 1
db1=# select * from t1;
 a  
----
 10
  1
(2 rows)

db1=# create view v1 as select * from t1 order by a;
CREATE VIEW
db1=# select * from v1;
 a  
----
  1
 10
(2 rows)

db1=# drop view v1;
DROP VIEW
db1=# create view v1 as select * from t1 order by a desc;
CREATE VIEW
db1=# select * from v1;
 a  
----
 10
  1
(2 rows)
db1=# select * from v1;
 a  
----
 10
  1
(2 rows)

db1=# select * from v1 order by a;
 a  
----
  1
 10
(2 rows)

2. 檢視檢視定義
db1=# \d v1
       View "public.v1"
 Column |  Type   | Modifiers 
--------+---------+-----------
 a      | integer | 
View definition:
 SELECT t1.a
   FROM t1
  ORDER BY t1.a DESC;

3. 刪除檢視
db1=# drop view v1;

六、其它物件
        HAWQ還支援自定義資料型別、自定義函式、序列等物件。如果用過Oracle,對這些物件一定不會陌生。
        自定義資料型別的例子:
gpadmin=# \c db1
You are now connected to database "db1" as user "gpadmin".
db1=# create type compfoo as (f1 int, f2 text);
CREATE TYPE
db1=# create table big_objs (
db1(#     id integer,
db1(#     obj compfoo
db1(# );
CREATE TABLE
db1=# insert into big_objs values (1,(1,'a'));
INSERT 0 1
        更多自定義資料型別資訊參見http://hawq.incubator.apache.org/docs/userguide/2.1.0.0-incubating/reference/sql/CREATE-TYPE.html

        序列的例子:
db1=# create sequence myseq start 101;
CREATE SEQUENCE
db1=# select currval('myseq'), nextval('myseq');
ERROR:  currval() not supported
db1=# select nextval('myseq');
 nextval 
---------
     101
(1 row)

db1=# select nextval('myseq');
 nextval 
---------
     102
(1 row)
        更多序列資訊參見http://hawq.incubator.apache.org/docs/userguide/2.1.0.0-incubating/reference/sql/CREATE-SEQUENCE.html

        自定義函式將在後面“過程語言”詳細描述。