--1.SELECT語句語法
[WITH expr_list|(subquery)] SELECT [DISTINCT] expr_list [FROM [db.]table | (subquery) | table_function] [FINAL] [SAMPLE sample_coeff] [ARRAY JOIN ...] [GLOBAL] [ANY|ALL|ASOF] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI] JOIN (subquery)|table (ON <expr_list>)|(USING <column_list>) [PREWHERE expr] [WHERE expr] [GROUP BY expr_list] [WITH ROLLUP|WITH CUBE] [WITH TOTALS] [HAVING expr] [ORDER BY expr_list] [WITH FILL] [FROM expr] [TO expr] [STEP expr] [LIMIT [offset_value, ]n BY columns] [LIMIT [n, ]m] [WITH TIES] [SETTINGS ...] [UNION ...] [INTO OUTFILE filename] [FORMAT format]
--2.with子句
--示例1:使用常量表達式作為“變量”
WITH '2019-08-01 15:23:00' as ts_upper_bound SELECT * FROM hits WHERE EventDate = toDate(ts_upper_bound) AND EventTime <= ts_upper_bound; --示例2:從SELECT子句列列表中逐出一個sum(bytes)表達式結果 WITH sum(bytes) as s SELECT formatReadableSize(s), table FROM system.parts GROUP BY table ORDER BY s; --示例3:使用標量子查詢的結果 /* this example would return TOP 10 of most huge tables */ WITH ( SELECT sum(bytes) FROM system.parts WHERE active ) AS total_disk_usage SELECT (sum(bytes) / total_disk_usage) * 100 AS table_disk_usage, table FROM system.parts GROUP BY table ORDER BY table_disk_usage DESC LIMIT 10; --示例4:在子查詢中重用表達式 WITH test1 AS (SELECT i + 1, j + 1 FROM test1) SELECT * FROM test1;
--3.sample子句
(1) sample k
k表示因子系數,采樣因子,取值范圍[0,1],若在0--1之間的小數則表示采樣,若為0或者1則等同於不采樣。
select CounterID from clicks sample 0.1 等同於: select CounterID from clicks sample 1/10
(2)sample n
n表示采樣的樣本數量。n表示至少采樣多少行數據。n=1表示不使用采樣,n的范圍從2到表的總行數。
select count() from clicks sample 10000;
(3)sample k offset n
表示按照因子系數和偏移量采樣。
select CounterID,_sample_factor from clicks sample 0.4 offset 0.5 limit 1; -- 讀取后半部分數據,從中抽樣40%,結果只顯示出1條 offset 0.5表示查詢從數據序號偏移一半開始 sample 0.4表示采樣40%的數據 limit 1 結果只顯示一條
注意:
sample子句提供了近似計算的功能,能夠實現數據采樣的功能,使查詢僅僅返回采樣數據而不是全部數據,從而有效減少查詢負載。
sample子句的采樣設計是一種冪等設計,即在數據發生變化的時候使用相同的采樣規則能返回相同的數據。這種特性非常適合那些可以接受近似查詢結果的場景。
--4.join子句
所有標准 SQL JOIN 支持類型:
INNER JOIN,只返回匹配的行。
LEFT OUTER JOIN,除了匹配的行之外,還返回左表中的非匹配行。
RIGHT OUTER JOIN,除了匹配的行之外,還返回右表中的非匹配行。
FULL OUTER JOIN,除了匹配的行之外,還會返回兩個表中的非匹配行。
CROSS JOIN,產生整個表的笛卡爾積, “join keys” 是 不 指定。
ClickHouse中提供的其他聯接類型:
LEFT SEMI JOIN 和 RIGHT SEMI JOIN,白名單 “join keys”,而不產生笛卡爾積。
LEFT ANTI JOIN 和 RIGHT ANTI JOIN,黑名單 “join keys”,而不產生笛卡爾積。
LEFT ANY JOIN, RIGHT ANY JOIN and INNER ANY JOIN, partially (for opposite side of LEFT and RIGHT) or completely (for INNER and FULL) disables the cartesian product for standard JOIN types.
ASOF JOIN and LEFT ASOF JOIN, joining sequences with a non-exact match.
使用SEMI LEFT JOIN時,使用右表中存在的key去過濾左表中的key,如果左表存在與右表相同的key,則輸出。
使用SEMI RIGHT JOIN時,使用左表中存在的key去過濾右表中的key,如果右表中存在與左表相同的key,則輸出。
換句話說,SEMI JOIN返回key在另外一個表中存在的記錄行。
ANTI JOIN和SEMI JOIN相反,他返回的是key在另外一個表中不存在的記錄行。
SEMI JOIN和ANTI JOIN都允許從兩個表中獲取數據。對於被過濾的表,返回的是與key相同的記錄行。對於ANTI JOIN,另外一個表返回的是默認值,比如空值或0。
--5.into outfile子句
實現導出數據至本地文件
樣例:
SELECT * FROM test.table_name INTO OUTFILE '/data/t_city.csv' FORMAT CSVWithNames;
只能在 command-line client and clickhouse-local 情景下使用,默認輸出格式為TabSeparated
通出 format 命令可指定輸出格式
--6.PREWHERE子句
prewhere 目前只適用於*MergeTree系列的表引擎,可以看做是對where的一種優化,和where語句的作用相同,用來過濾數據。
不同之處在於prewhere首先會讀取指定的列數據,來判斷數據過濾,等待數據過濾之后再讀取select 聲明的列字段來補全其余屬性。
在某些場合下,prewhere語句比where語句處理的數據量更少性能更高。
樣例:
select * from test.table_name prewhere col1='us';
不能自動優化情景:
使用常量表達式
使用默認值為alias類型的字段
包含了arrayJOIN,globalIn,globalNotIn或者indexHint的查詢
select查詢的列字段和where的謂詞相同
使用了主鍵字段
--7.union子句
包括union all / union distinct / union 3命令格式,union all對結果不去重,union distinct對結果去重;
當只用 union 命令時,到底實現union all 或是 union distinct,由union_default_mode 決定,SET union_default_mode = 'DISTINCT' 模式
--8.limit子句
limit m : 顯示前m條數據
limit n , m : 相當 LIMIT m OFFSET n , 即從n+1條數據開始,共返回m條
--9.limit by子句
兩種格式:
limit m by expressions limit n,m by expressions SELECT * FROM limit_by ORDER BY id, val LIMIT 2 BY id; -- 每個id只顯示前兩條數據 SELECT * FROM limit_by ORDER BY id, val LIMIT 1, 2 BY id; --每個id跳過第1條數據,顯示第2,3條數據 --以下查詢返回每domain, device_type對的前5個引薦來源網址,總共最多包含100行(LIMIT n BY + LIMIT)。 SELECT domainWithoutWWW(URL) AS domain, domainWithoutWWW(REFERRER_URL) AS referrer, device_type, count() cnt FROM hits GROUP BY domain, referrer, device_type ORDER BY cnt DESC LIMIT 5 BY domain, device_type LIMIT 100
--10.order by
NaN和NULL排序順序:
默認情況下或使用NULLS LAST修飾符:首先是值,然后是NaN,然后是NULL。
使用NULLS FIRST修飾符:首先NULL,然后是NaN,然后是其他值。
對於按字符串值排序,可以指定排序規則(比較)。示例:ORDER BY SearchPhrase COLLATE 'tr'-假設字符串是UTF-8編碼的,則使用土耳其字母按升序按關鍵字排序,不區分大小寫。
COLLATE可以為ORDER BY中的每個表達式分別指定或不指定。如果指定ASC或DESC,COLLATE則在其后指定。使用時COLLATE,排序始終不區分大小寫
SELECT * FROM collate_test ORDER BY s ASC COLLATE 'en';
運行示例:
--測試表: CREATE TABLE test.tmp_uid_info ( `uid` Int32, `alias` Int32, `sex` String, `totalDate` Date, `source` String, `name` String ) ENGINE = ReplicatedMergeTree('/clickhouse/test/tables/{shard}/tmp_uid_info', '{replica}') PARTITION BY totalDate ORDER BY uid SETTINGS index_granularity = 8192 --添加新字段 --語法格式 alter table tb_name add column [IF NOT EXISTS] name [type] [default_expr] [alter name_after] -- 給測試表的末尾增加新字段.,對於數據表中已經存在舊數據⽽⾔,新追加的字段會使⽤默認值補全 alter table tmp_uid_info on cluster ck_cluster add column age String default '0' --刪除已有字段 -- 語法格式 alter table tb_name drop column [IF EXISTS] name -- 刪除測試表的age字段,注意字段被刪除后,它的數據也會被連帶刪除 alter table default.tmp_uid_info on cluster ck_cluster drop column age; --修改字段類型 -- 語法格式 alter table tmp_uid_info MODIFY COLUMN [IF EXISTS] name [type] [default_expr] -- 修改uid的字段類型,由int32改成Int64,注意,使用String轉成Int會報錯 alter table default.tmp_uid_info on cluster ck_cluster modify column uid Int64; --修改字段名 -- 語法格式 ALTER TABLE table_name RENAME COLUMN column_name TO new_column_name -- 修改uid的字段類型,由int32改成Int64,注意,使用String轉成Int會報錯 alter table tmp_uid_info on cluster ck_cluster rename column name to username; --給字段添加注釋 -- 語法格式 alter table tb_name comment column [IF EXISTS] name 'comment' -- 給測試表的name字段添加注釋 alter table default.tmp_uid_info on cluster ck_cluster comment column name '姓名' -- 即可查看到name的注釋 DESCRIBE TABLE tmp_uid_info ┌─name──────┬─type───┬─default_type─┬─default_expression─┬─comment─┬─codec_expression─┬─ttl_expression─┐ │ uid │ Int32 │ │ │ │ │ │ │ alias │ Int32 │ │ │ │ │ │ │ sex │ String │ │ │ │ │ │ │ totalDate │ Date │ │ │ │ │ │ │ source │ String │ │ │ │ │ │ │ name │ String │ │ │ 姓名 │ │ │ │ age │ String │ DEFAULT │ '0' │ │ │ │ └───────────┴────────┴──────────────┴────────────────────┴─────────┴──────────────────┴────────────────┘ --清空數據表,只是表內的數據全部清空,⽽不是直接刪除這張表 --語法格式 truncate table [IF EXISTS] [db_name.]tb_name -- 清空測試表數據 truncate table default.tmp_uid_info on cluster ck_cluster --同步zk刪除表 drop table if EXISTS default.ods_user_test on cluster ck_cluster sync; drop table if EXISTS default.ods_user_test_all on cluster ck_cluster sync; --通過system系統庫的Parts表來查詢分區信息 SELECT partition_id, name, table, database FROM system.parts WHERE (table = 'tmp_uid_info') AND (database = 'test') ┌─partition_id─┬─name─────────────┬─table────────┬─database─┐ │ 20101027 │ 20101027_0_0_0_2 │ tmp_uid_info │ test │ │ 20121027 │ 20121027_0_0_0_2 │ tmp_uid_info │ test │ │ 20131127 │ 20131127_0_0_0_2 │ tmp_uid_info │ test │ │ 20141127 │ 20141127_0_0_0_2 │ tmp_uid_info │ test │ │ 20161027 │ 20161027_0_0_0_2 │ tmp_uid_info │ test │ │ 20161127 │ 20161127_0_0_0_2 │ tmp_uid_info │ test │ │ 20171127 │ 20171127_0_0_0_2 │ tmp_uid_info │ test │ │ 20180127 │ 20180127_0_0_0_2 │ tmp_uid_info │ test │ │ 20181027 │ 20181027_2_2_0_4 │ tmp_uid_info │ test │ │ 20181227 │ 20181227_0_0_0_2 │ tmp_uid_info │ test │ │ 20190127 │ 20190127_0_0_0_2 │ tmp_uid_info │ test │ │ 20190227 │ 20190227_0_0_0_2 │ tmp_uid_info │ test │ │ 20191027 │ 20191027_2_2_0_4 │ tmp_uid_info │ test │ │ 20191127 │ 20191127_0_0_0_2 │ tmp_uid_info │ test │ │ 20201027 │ 20201027_0_0_0_2 │ tmp_uid_info │ test │ └──────────────┴──────────────────┴──────────────┴──────────┘ --根據條件刪除測試表的數據: alter table default.tmp_uid_info on cluster ck_cluster delete where totalDate='2020-10-28' --根據分區刪除測試表的數據: -- 根據分區鍵刪除,測試表按日期分區 alter table default.tmp_uid_info on cluster ck_cluster drop partition '2020-10-27' --手動合並數據表的分區 -- 單機 optimize table default.tmp_uid_info partition '2020-10-27' final -- zk分發 optimize table default.tmp_uid_info on cluster ck_cluster partition '2020-10-27' final --修改表名字 RENAME TABLE database.table1TO database.table2 on cluster ck_cluster;
--11.分區表操作
目前只有MergeTree系列的表引擎支持數據分區
create table test_partition( id String, ctime DateTime )engine=MergeTree() partition by toYYYYMM(ctime) order by (id) ;
1)查看表中的分區
SELECT partition_id,name,table,partition,active FROM system.parts WHERE table = 'test_partition' AND active = 1 ;
2)添加/刪除分區
--刪除分區:刪除分區以后,分區中的所有的數據全部刪除 alter table test_partition drop partition '202105' ;
3)合並分區
optimize table test_partition final;
4)復制分區
clickHouse支持將A表的分區數據復制到B表,這項特性可以用於快速數據寫入、多表間數據同步和備份等場景
復制分區需要滿足兩個前提條件:
- 兩張表需要擁有相同的分區鍵
- 它們的表結構完全相同。
--創建表 create table test_partition1 as test_partition ; --復制一張表的分區到另一張表中 alter table test_partition1 replace partition '202106' from test_partition
5)重置分區數據
如果數據表某一列的數據有誤,需要將其重置為初始值,如果設置了默認值那么就是默認值數據,如果沒有設置默認值,系統會給出默認的初始值
注意:不能重置主鍵和分區字段
alter table test_partition1 clear column name in partition '202105';
6)卸載/裝載分區
使用場景:分區數據的遷移和備份
①卸載分區detach
分區被卸載后,它的物理數據並沒有刪除,而是被轉移到了當前數據表目錄的detached子目錄下。該目錄已經脫離了clickhouse的管理,clickhouse並不會主動清理這些文件。
alter table test_partition detach partition '202105';
②裝載分區attach
將detached子目錄的某個分區重新裝載回去。
alter table test_partition attach partition '202105';
--12.視圖
1)普通視圖
不會存儲任何數據,只是一層簡單的select查詢映射,對查詢性能不會有任何增強
create view test_view as select id,upper(name),role from tb_test;
2)物化視圖
- 支持表引擎,數據保存形式由它的表引擎決定
- 物化視圖創建好之后,如果源表被寫入新數據,那么物化視圖也會同步更新
- populate修飾符決定物化視圖的初始化策略,如果使用了POPULATE修飾符,那么在創建視圖的過程中,會連帶將源表中已存在的數據一並導入,如同執行了INTO SELECT一般。
- 物化視圖目前並不支持同步刪除,如果在源表中刪除了數據,物化視圖的數據會保留
create materialized view mater_test_view engine=Log populate as select * from tb_test;