在上一篇關於物化視圖的文章中, 我們介紹了一種構造ClickHouse物化視圖的方法, 該視圖使用SummingMergeTree引擎計算總和和計數. SummingMergeTree可以為這兩種類型的聚合使用普通的SQL語法. 我們還讓物化視圖定義自動為數據創建基礎表(.inner表). 這兩種技術都很快速, 但對生產系統有限制(都不太適用於生產環境).
在本篇文章中, 我們將展示如何在現有的表上創建一個具有一系列聚合類型的物化視圖. 當您需要計算的不僅僅是簡單的總和時, 此方法非常適合. 對於表中有大量正在插入的數據(針對Part 1)中的 POPULATE
, 使用POPULATE會填充歷史數據, 但這期間向原表中新插入數據會被忽略掉而不會寫入物化視圖中)或必須處理表結構變更的情況, 這也非常方便.
使用State函數和To Tables創建更靈活的物化視圖
在線面的例子中, 我們將測量設備的讀數. 讓我們從表定義開始.
1 2 3 4 5 6 7
|
CREATE TABLE counter ( when DateTime DEFAULT now(), device UInt32, value Float32 ) ENGINE=MergeTree PARTITION BY toYYYYMM(when) ORDER BY (device, when)
|
接下來, 我們添加足夠的數據, 以使查詢速度變得足夠慢: 10個設備的10億行合成數據. 注意: 如果您要嘗試這些操作, 只需輸入100萬行即可. 無論數據量如何, 示例都可以工作.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
INSERT INTO counter SELECT toDateTime('2015-01-01 00:00:00') + toInt64(number / 10) AS when, (number % 10) + 1 AS device, ((device * 3) + (number / 10000)) + ((rand() % 53) * 0.1) AS value FROM system.numbers LIMIT 1000000000
↓ Progress: 1.00 billion rows, 8.00 GB (5.13 million rows/s., 41.07 MB/s.) Ok.
0 rows in set. Elapsed: 194.814 sec. Processed 1.00 billion rows, 8.00 GB (5.13 million rows/s., 41.07 MB/s.)
SELECT count(*) FROM counter
┌────count()─┐ │ 1000000000 │ └────────────┘
SELECT * FROM counter LIMIT 1
┌────────────────when─┬─device─┬─value─┐ │ 2015-01-01 00:00:00 │ 1 │ 3.6 │ └─────────────────────┴────────┴───────┘
[root@bj2-all-clickhouse-test-02 11:21:30 /data/clickhouse/node2/data/duyalan] #du -sh counter/ 13G counter/
[root@bj2-all-clickhouse-test-02 11:21:35 /data/clickhouse/node2/data/duyalan] #du -sh counter/ 12G counter/
[root@bj2-all-clickhouse-test-02 11:26:04 /data/clickhouse/node2/data/duyalan] #du -sh counter/ 6.5G counter/ 數據慢慢被壓實
|
現在, 讓我們看一下我們希望定期運行的示例查詢. 它匯總了整個采樣期間所有設備的所有數據. 在這種情況下, 這意味着表中3.25年的數據, 都是在2019年之前.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
SELECT device, count(*) AS count, max(value) AS max, min(value) AS min, avg(value) AS avg FROM counter GROUP BY device ORDER BY device ASC
┌─device─┬─────count─┬────────max─┬─────min─┬────────────────avg─┐ │ 1 │ 100000000 │ 100008.15 │ 3.077 │ 50005.599374785554 │ │ 2 │ 100000000 │ 100011.164 │ 6.0761 │ 50008.59962170133 │ │ 3 │ 100000000 │ 100014.1 │ 9.0022 │ 50011.599634214646 │ │ 4 │ 100000000 │ 100017.17 │ 12.0063 │ 50014.59989124005 │ │ 5 │ 100000000 │ 100020.164 │ 15.0384 │ 50017.59997032414 │ │ 6 │ 100000000 │ 100023.19 │ 18.1045 │ 50020.60019940771 │ │ 7 │ 100000000 │ 100026.055 │ 21.0566 │ 50023.60046194672 │ │ 8 │ 100000000 │ 100029.14 │ 24.0477 │ 50026.60002471252 │ │ 9 │ 100000000 │ 100032.17 │ 27.0218 │ 50029.60008679837 │ │ 10 │ 100000000 │ 100035.02 │ 30.0629 │ 50032.60051765903 │ └────────┴───────────┴────────────┴─────────┴────────────────────┘
10 rows in set. Elapsed: 12.036 sec. Processed 1.00 billion rows, 8.00 GB (83.08 million rows/s., 664.67 MB/s.)
bj2-all-clickhouse-test-02 :) select min(when),max(when) from counter;
SELECT min(when), max(when) FROM counter
┌───────────min(when)─┬───────────max(when)─┐ │ 2015-01-01 00:00:00 │ 2018-03-03 09:46:39 │ └─────────────────────┴─────────────────────┘
1 rows in set. Elapsed: 9.941 sec. Processed 1.00 billion rows, 4.00 GB (100.59 million rows/s., 402.36 MB/s.)
|
前面的查詢很慢, 因為它必須讀取表中的所有數據才能獲得答案. 我們想要設計一個物化視圖, 該視圖讀取的數據要少得多. 事實證明, 如果我們定義了一個每天匯總數據的視圖, 則ClickHouse將正確地在整個時間間隔內匯總每天的數據.
與前面的簡單示例(Part 1)不同, 我們將自己定義目標(.inner表)表. 這樣做的好處是, 該表現在可見, 這使得加載數據以及進行模式遷移(表結構變更)更加容易. 下面是目標表的定義.
1 2 3 4 5 6 7 8 9 10 11
|
CREATE TABLE counter_daily ( day DateTime, device UInt32, count UInt64, max_value_state AggregateFunction(max, Float32), min_value_state AggregateFunction(min, Float32), avg_value_state AggregateFunction(avg, Float32) ) ENGINE = SummingMergeTree() PARTITION BY tuple() ORDER BY (device, day)
|
該表定義引入了一種新的數據類型, 稱為AggregateFunction, 該數據類型保存部分聚合的數據(which holds partially aggregated data). 這個數據類型用於sum和count以外的聚合需求. 接下來, 我們創建相應的物化視圖. 它從counter(源表)中選擇數據, 並使用CREATE語句中的特殊TO語法將數據發送到counter_daily(目標表). 該表有聚合函數, SELECT語句有與之相匹配的函數, 如’ maxState ‘. 我們將在詳細討論聚合函數時討論它們之間的關系.
1 2 3 4 5 6 7 8 9 10 11 12 13
|
CREATE MATERIALIZED VIEW counter_daily_mv TO counter_daily AS SELECT toStartOfDay(when) as day, device, count(*) as count, maxState(value) AS max_value_state, minState(value) AS min_value_state, avgState(value) AS avg_value_state FROM counter WHERE when >= toDate('2019-01-01 00:00:00') GROUP BY device, day ORDER BY device, day
|
TO關鍵字使我們可以指向目標表(存儲物化視圖數據的表, 在本例中即是counter_daily表), 但有一個缺點. ClickHouse不允許在TO中使用POPULATE關鍵字. 因此, 物化視圖創建后沒有任何數據. 我們將手動加載數據. 但是, 我們還將使用一個不錯的技巧, 使我們可以避免在同時進行活動數據加載的情況下出現問題.
注意, 視圖定義有一個WHERE子句. 這意味着2019年之前的任何數據都應該被忽略. 我們現在有了一種不丟失數據的方法來處理數據加載. 該視圖將處理2019年到達的新數據. 同時, 我們可以通過插入加載2018年及之前的舊數據.
讓我們通過將新數據加載到counter表中來演示它是如何工作的. 新數據將於2019年開始, 並將自動加載到視圖中.
1 2 3 4 5 6
|
INSERT INTO counter SELECT toDateTime('2019-01-01 00:00:00') + toInt64(number/10) AS when, (number % 10) + 1 AS device, (device * 3) + (number / 10000) + (rand() % 53) * 0.1 AS value FROM system.numbers LIMIT 100000000
|
現在, 使用以下INSERT手動加載舊數據. 它會加載2018年及之前的所有數據.
1 2 3 4 5 6 7 8 9 10 11 12
|
INSERT INTO counter_daily SELECT toStartOfDay(when) as day, device, count(*) AS count, maxState(value) AS max_value_state, minState(value) AS min_value_state, avgState(value) AS avg_value_state FROM counter WHERE when < toDateTime('2019-01-01 00:00:00') GROUP BY device, day ORDER BY device, day
|
我們終於可以從視圖中查詢數據了. 與目標表和物化化視圖一樣, ClickHouse使用專用語法從視圖中進行選擇.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
|
物化視圖目標表 SELECT device, sum(count) AS count, maxMerge(max_value_state) AS max, minMerge(min_value_state) AS min, avgMerge(avg_value_state) AS avg FROM counter_daily GROUP BY device ORDER BY device ASC
┌─device─┬─────count─┬────────max─┬─────min─┬────────────────avg─┐ │ 1 │ 110000000 │ 100008.15 │ 3.051 │ 45914.69035234097 │ │ 2 │ 110000000 │ 100011.164 │ 6.0291 │ 45917.69056040798 │ │ 3 │ 110000000 │ 100014.1 │ 9.0022 │ 45920.690478928045 │ │ 4 │ 110000000 │ 100017.17 │ 12.0063 │ 45923.69086044358 │ │ 5 │ 110000000 │ 100020.164 │ 15.0114 │ 45926.69083122718 │ │ 6 │ 110000000 │ 100023.19 │ 18.0475 │ 45929.691088042426 │ │ 7 │ 110000000 │ 100026.055 │ 21.0566 │ 45932.69135215635 │ │ 8 │ 110000000 │ 100029.14 │ 24.0107 │ 45935.690912335944 │ │ 9 │ 110000000 │ 100032.17 │ 27.0218 │ 45938.69098338585 │ │ 10 │ 110000000 │ 100035.02 │ 30.0429 │ 45941.69140548378 │ └────────┴───────────┴────────────┴─────────┴────────────────────┘
10 rows in set. Elapsed: 0.019 sec. Processed 13.69 thousand rows, 1.12 MB (729.14 thousand rows/s., 59.84 MB/s.)
物化視圖 SELECT device, sum(count) AS count, maxMerge(max_value_state) AS max, minMerge(min_value_state) AS min, avgMerge(avg_value_state) AS avg FROM counter_daily_mv GROUP BY device ORDER BY device ASC
┌─device─┬─────count─┬────────max─┬─────min─┬────────────────avg─┐ │ 1 │ 110000000 │ 100008.15 │ 3.051 │ 45914.69035234097 │ │ 2 │ 110000000 │ 100011.164 │ 6.0291 │ 45917.69056040798 │ │ 3 │ 110000000 │ 100014.1 │ 9.0022 │ 45920.690478928045 │ │ 4 │ 110000000 │ 100017.17 │ 12.0063 │ 45923.69086044358 │ │ 5 │ 110000000 │ 100020.164 │ 15.0114 │ 45926.69083122718 │ │ 6 │ 110000000 │ 100023.19 │ 18.0475 │ 45929.691088042426 │ │ 7 │ 110000000 │ 100026.055 │ 21.0566 │ 45932.69135215635 │ │ 8 │ 110000000 │ 100029.14 │ 24.0107 │ 45935.690912335944 │ │ 9 │ 110000000 │ 100032.17 │ 27.0218 │ 45938.69098338585 │ │ 10 │ 110000000 │ 100035.02 │ 30.0429 │ 45941.69140548378 │ └────────┴───────────┴────────────┴─────────┴────────────────────┘
10 rows in set. Elapsed: 0.003 sec. Processed 13.69 thousand rows, 1.12 MB (3.99 million rows/s., 327.87 MB/s.)
源表 SELECT device, count(*) AS count, max(value) AS max, min(value) AS min, avg(value) AS avg FROM counter GROUP BY device ORDER BY device ASC
┌─device─┬─────count─┬────────max─┬─────min─┬────────────────avg─┐ │ 1 │ 110000000 │ 100008.15 │ 3.051 │ 45914.69035234098 │ │ 2 │ 110000000 │ 100011.164 │ 6.0291 │ 45917.69056040798 │ │ 3 │ 110000000 │ 100014.1 │ 9.0022 │ 45920.69047892806 │ │ 4 │ 110000000 │ 100017.17 │ 12.0063 │ 45923.69086044358 │ │ 5 │ 110000000 │ 100020.164 │ 15.0114 │ 45926.690831227155 │ │ 6 │ 110000000 │ 100023.19 │ 18.0475 │ 45929.69108804243 │ │ 7 │ 110000000 │ 100026.055 │ 21.0566 │ 45932.691352156355 │ │ 8 │ 110000000 │ 100029.14 │ 24.0107 │ 45935.690912335944 │ │ 9 │ 110000000 │ 100032.17 │ 27.0218 │ 45938.69098338586 │ │ 10 │ 110000000 │ 100035.02 │ 30.0429 │ 45941.69140548378 │ └────────┴───────────┴────────────┴─────────┴────────────────────┘
10 rows |