19_clickhouse,数据查询与写入优化,分布式子查询优化,外部聚合/排序优化,基于JOIN引擎的优化,SQL优化案例,物化视图提速,查询优化常用经验法则,选择和主键不一样的排序键,数据入库优化
25.數據查詢與寫入優化
25.1.分布式子查詢優化
25.1.1.分布式表的IN查詢示例1(普通IN子查詢、IN子查詢為本地表)
25.1.2.分布式表的IN查詢示例2(普通IN子查詢、IN子查詢為分布式表)
25.1.3.分布式表的IN查詢示例3(GLOBAL IN子查詢、IN子查詢為分布式表)
25.1.4.使用GLOBAL IN/GLOBAL JOIN注意事項
25.2.外部聚合/排序優化
25.3.基于JOIN引擎的優化
25.4.SQL優化案例
25.4.1.物化視圖提速
25.4.2.查詢優化常用經驗法則
25.4.3.選擇和主鍵不一樣的排序鍵
25.4.4.數據入庫優化
25.數據查詢與寫入優化
25.1.分布式子查詢優化
帶子查詢的IN和JOIN有兩個選項:普通的IN/JOIN、GLOBAL IN / GLOBAL JOIN。
1、 普通的IN/JOIN : 查詢發送到遠程的server,在每個遠程的server上運行IN子查詢或JOIN子句。
2、 GLOBAL IN/GLOBAL JOIN : 首先為GLOBAL IN/GLOBAL JOIN運行所有子查詢,將結果收集在臨時表中。然后將臨時表發送到每個遠端server,并在其中使用此臨時數據運行查詢。
25.1.1.分布式表的IN查詢示例1(普通IN子查詢、IN子查詢為本地表)
SELECT uniq(UserID) FROM distributed_tableWHERE UserID IN (SELECT UserID FROM local_table_in WHERE CounterID = 34);上面的查詢語句將被發送到所有遠程服務器上, 并在遠程服務器使用本地表運行:
SELECT uniq(UserID) FROM local_table WHERE UserID IN (SELECT UserID FROM local_table_in WHERE CounterID=34);上面的語句需要保證該local_table_in表的所有USERID完全駐留在單個服務器上,否則,數據可能會不準確。
25.1.2.分布式表的IN查詢示例2(普通IN子查詢、IN子查詢為分布式表)
SELECT uniq(UserID) FROM distributed_tableWHERE UserID IN (SELECT UserID FROM distributed_table_in WHERE CounterID = 34);1.上面的查詢語句將被發送到所有遠程服務器上(假設100臺服務器),并被遠程服務器使用本地表運行:
SELECT uniq(UserID) FROM local_table WHERE UserID IN (SELECT UserID FROM distributed_table_in WHERE CounterID = 34);2.由于子查詢是分布式表,每個子查詢分發至100臺服務器,運行如下查詢:
SELECT UserID FROM local_table_in WHERE CounterID = 34;執行整個查詢需要100 * 100 = 10000個請求。這將導致嚴重性能問題。
考慮使用GLOBAL IN。
25.1.3.分布式表的IN查詢示例3(GLOBAL IN子查詢、IN子查詢為分布式表)
SELECT uniq(UserID) FROM distributed_table WHERE UserID GLOBAL IN (SELECT UserID FROM distributed_table_in WHERE CounterID = 34);1.在請求服務器上運行子查詢,并將結果存儲在RAM的臨時表_data1中。
SELECT UserID FROM distributed_table_in WHERE CounterID = 34;2.請求服務器將臨時表_data1發送到每個遠程的服務器上,并在每個服務器執行如下查詢:
SELECT uniq(UserID) FROM local_table WHERE UserID IN _data1;避免了普通IN導致的連鎖響應請求。
25.1.4.使用GLOBAL IN/GLOBAL JOIN注意事項
1.使用GLOBAL IN創建臨時表,數據沒有去重。若要減少網絡傳輸的數據量, 在子查詢中指定 DISTINCT。
2.使用GLOBAL時,應盡量避免使用大數據集。臨時表將發送所有遠程的主機,特別是在多機房容災的集群架構下,數據發送至遠程數據中心性能低下。
3.GLOBAL可能會導致網絡超載。不會限制網絡帶寬。
4.使用GLOBAL時,盡量保證副本組駐留在同一個數據中心,保證快速的網絡數據傳輸。
5.為避免GLOBAL導致的數據傳輸,可提前將全量的數據發至每個節點,并使用普通JOIN/IN。
25.2.外部聚合/排序優化
聚合查詢消耗的內存超過max_memory_usage(默認10G)設置的值,導致內存溢出。
ClickHouse支持將臨時數據轉儲到磁盤以限制GROUP BY期間的內存使用。
當GROUP BY消耗超過max_bytes_before_external_group_by設置的閾值,ClickHouse將中間數據轉儲到磁盤。默認值為0,表示禁用磁盤溢寫。
聚合有兩個階段,第一階段讀取數據并形成中間數據。第二階段合并中間數據。中間臨時數據轉儲到磁盤是發生在第一階段,如果沒有數據轉儲,則兩個階段使用的內存相同。
在設置max_bytes_before_external_group_by值時,建議將其設置為max_memory_usage的一半。
當使用分布式查詢,為了保證外部聚合時在遠程的server端執行,設置 distributed_aggregation_memory_efficient為1。
開啟外部排序設置max_bytes_before_external_sort,否則可能會內存不足導致查詢異常終止。
當啟用外部聚合,如果數據沒有轉儲到磁盤,此時,查詢的運行速度和沒有外部聚合時一樣快。 如果中間數據轉儲到磁盤,則運行時間將延長數倍(大約3倍)。
而外部排序,數據轉儲到磁盤,性能將明顯下降。
三個參數分別設置為20GB、10GB和40GB。
1.在命令行界面設置:
set max_bytes_before_external_group_by=20000000000; set max_bytes_before_external_sort=10000000000; set max_memory_usage=40000000000;2.JDBC設置,在URL添加參數:
url?max_bytes_before_external_group_by=20000000000&max_memory_usage=4000000000025.3.基于JOIN引擎的優化
如果多次使用相同的表(子查詢),每次都需要重新計算運行子查詢。為此,可使用Join表引擎將數據緩存在 RAM中。
語法:
JOIN引擎使用示例:
創建表:
插入表數據:
INSERT INTO id_val VALUES (1,11)(2,12)(3,13);創建右連接的JOIN引擎表:
DROP TABLE id_val_join; CREATE TABLE id_val_join(`id` UInt32, `val` UInt8) ENGINE = Join(ANY, LEFT, id);插入數據:
INSERT INTO id_val_join VALUES (1,21)(1,22)(3,23);表數據關聯:
SELECT * FROM id_val ANY LEFT JOIN id_val_join USING (id) SETTINGS join_use_nulls = 1;
25.4.SQL優化案例
25.4.1.物化視圖提速
在用于插入數據的表上,創建多個物化視圖,每個物化視圖根據業務需求對數據做轉換。
1.物化視圖存儲通過由相應的SELECT查詢轉換的數據。
2.在數據插入期間做查詢轉換,壓力分散。
3.僅在插入的單個數據塊中聚合,數據不會進一步聚合。
4.數據表的引擎可為NULL。
25.4.2.查詢優化常用經驗法則
1.小表放在JOIN的右邊
2.使用子查詢顯示設置數據處理的順序
3.使用IN替換JOIN操作
4.使用字典替換JOIN操作。
5.設置單射屬性。
6.使用Join引擎緩存表。
7.禁用分布式表的子查詢,使用GLOBAL IN/JOIN替換或者將子查詢的表提前分發至所有的server作為本地表。
8.使用PREWHERE
9.避免使用SELECT *查詢
10.盡量少用或不用多表關聯。
25.4.3.選擇和主鍵不一樣的排序鍵
默認情況下,主鍵(由PRIMARY KEY指定)跟排序鍵(ORDER BY)相同,因此,大部分情況下,不需要專門指定一個PRIMARY KEY子句。
當使用SummingMergeTree 和 AggregatingMergeTree時,可考慮選擇和主鍵不一樣的排序鍵。
CREATE TABLE t_merge_sum (id UInt32, name String, value UInt32 )ENGINE = SummingMergeTree() PRIMARY KEY id ORDER BY (id,name);1.排序鍵可以修改,主鍵不能修改。
2.預聚合/增量聚合的key是由排序鍵指定的。業務邏輯后期可能會更改。
3.查詢條件無需包括排序鍵的所有字段。
添加排序鍵需要注意的:
1.主鍵字段是排序鍵字段的子集。
例如主鍵為(A,B),則排序鍵以(A,B)開頭,排序鍵可為(A,B)或(A,B,C)等。
2.舊的排序鍵是新的排序鍵的前綴。
修改排序鍵只能增加排序字段,不能減少排序鍵字段,例如可修改排序鍵(A,B)為(A,B,C),但不能修改為(A,C)或(A,C,B)等。
3.排序鍵只能添加新加入表的列,表中已存在的數據的列不能添加到排序鍵中。
25.4.4.數據入庫優化
| 簡單 | 數據通過各節點的本地表導入 |
| 異步發送 | 壓力分散 |
| 無一致性校驗 | 原子寫入 |
| ZooKeeper壓力大 |
1.使用復制表,能夠保證數據原子寫入和去重。
2.限制單個復制表INSERT語句執行的頻率(建議每秒不超過1個)
3.以相當大的數據塊插入數據(默認為1048576)。
4.將數據INSERT到ClickHouse之前,通過分區鍵對數據進行分組。
5.增加入庫的并發,入庫性能線性提升。
6.自定義負載均衡策略,控制數據均衡。
總結
以上是生活随笔為你收集整理的19_clickhouse,数据查询与写入优化,分布式子查询优化,外部聚合/排序优化,基于JOIN引擎的优化,SQL优化案例,物化视图提速,查询优化常用经验法则,选择和主键不一样的排序键,数据入库优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 五菱宏光的车门子锁住了为什么还能打?
- 下一篇: Sqoop(一)安装及基本使用