應用程序日誌數據庫的設計
我們正在生成如下範例的日誌(這是一個沒有實際管道的表):
2014-06-10 09:00:03.457 | Channel1 | Operation3 | Function15 | 15ms 2014-06-10 09:00:08.245 | Channel2 | Operation5 | Function10 | 22ms 2014-06-10 09:00:22.005 | Channel1 | Operation3 | Function15 | 48ms
考慮至少 25-30 列時間序列應用程序日誌數據。每一行都是一個事務。所以我聚合相同的並得到總和(也是持續時間的平均值)。聚合後,我唯一的聚集鍵是除事務持續時間或總和等指標之外的所有列。
在 2014-06-10 09:00:00 - 2014-06-10 09:01:00 之間的範例中,我們的範例將是:
2014-06-10 09:00:00 | Channel1 | Operation3 | Function15 | 2 | 31,5ms 2014-06-10 09:00:00 | Channel2 | Operation5 | Function10 | 1 | 22ms
有一個更好的方法嗎?處理這些數據也花費了我很多,同時將其展示給使用者進行監控和分析。
更新-1
我認為這個問題需要進一步澄清。原始日誌數據與第一個範例類似。我正在執行一個 ETL 代理,它按分鐘間隔獲取它並聚合到另一個表,如第二個範例中所示。
第二個表具有除指標列(計數,響應時間)之外的所有列的主鍵。因為歸根結底
2014-06-10 09:00:00 | Channel1 | Operation3 | Function15
是唯一能給我獨特性的東西。當使用者想要分析它時。他/她從我命名為“維度”的每一列中選擇值。他/她想查看“Channel1 上的 Function15 事務”或“Channel1 上的 Operation5 響應時間”等。我正在儲存這樣的數據以實現使用者的這些請求。
問候
我做了以下
CREATE TABLE L( Time_Series_TS TIMESTAMP, Channel VARCHAR(10), Operation VARCHAR(10), Function VARCHAR(10), Duration INT);
然後
INSERT INTO L VALUES('2014-06-10 09:00:03.457', 'Channel1', 'Operation3', 'Function15', 15); INSERT INTO L VALUES('2014-06-10 09:00:08.245', 'Channel2', 'Operation5', 'Function10', 22); INSERT INTO L VALUES('2014-06-10 09:00:22.005', 'Channel1', 'Operation3', 'Function15', 48); INSERT INTO L VALUES('2014-06-10 09:01:03.457', 'Channel2', 'Operation3', 'Function15', 296); INSERT INTO L VALUES('2014-06-10 09:01:08.245', 'Channel2', 'Operation5', 'Function10', 225); INSERT INTO L VALUES('2014-06-10 09:01:22.005', 'Channel1', 'Operation3', 'Function15', 7); INSERT INTO L VALUES('2014-06-10 09:01:16.245', 'Channel2', 'Operation5', 'Function10', 10); INSERT INTO L VALUES('2014-06-10 09:01:47.005', 'Channel1', 'Operation3', 'Function15', 20);
我在您的樣本中添加了一些記錄以供檢查。然後執行此查詢
SELECT MINUTE(Time_Series_TS) AS Minute, Channel, Operation, Function, COUNT(*) AS "Count/min", SUM(Duration) AS Duration FROM L GROUP BY Minute, Channel, Operation, Function ORDER By Minute, Channel, Operation, Function;
這給了
+--------+----------+------------+------------+-----------+----------+ | Minute | Channel | Operation | Function | Count/min | Duration | +--------+----------+------------+------------+-----------+----------+ | 0 | Channel1 | Operation3 | Function15 | 2 | 63 | | 0 | Channel2 | Operation5 | Function10 | 1 | 22 | | 1 | Channel1 | Operation3 | Function15 | 2 | 27 | | 1 | Channel2 | Operation3 | Function15 | 1 | 296 | | 1 | Channel2 | Operation5 | Function10 | 2 | 235 | +--------+----------+------------+------------+-----------+----------+
這似乎是您想要的結果(根據我之前的評論,註釋 63 是第一個持續時間)。這是你想要的結果嗎?然後,您可以使用 HOUR() 和 DAYOFMONTH() 甚至 YEAR() 來聚合這些查詢。
為了性能,我確實創建了一個索引
CREATE INDEX L_Index ON L(Channel, Operation, Function) using BTREE;
並在創建它之前和之後解釋了查詢,但沒有區別。這不足為奇,因為優化器可能會說對這麼小的表使用一個是沒有意義的。顯然,我無法用您的數據進行測試,但有幾點。如果您對大量編號較大的記錄執行此操作。欄位,您可能會遇到問題,如果您創建許多索引,您的插入性能會降低。您是否可以以某種方式對數據進行分類以減少欄位數量 - 即將您的大表拆分為欄位數量較少的表?查看不同的場景,測試並查看您的數據、查詢、應用程序和硬體會發生什麼。
$$ EDIT $$ 對於更易於閱讀的內容,您可能想嘗試類似
SELECT TIME(FROM_UNIXTIME(UNIX_TIMESTAMP(Time_Series_TS) - MOD(UNIX_TIMESTAMP(Time_Series_TS), 60))) AS Minute, .. ..
對於你的第一個領域。
$$ EDIT - Response to UPDATE-1 $$ 好的 - 所以在我的模式中,您是按(分鐘、通道、操作、函式)索引的嗎?有關MySQL 中復合索引的文件,請參見此處。如果您的查詢主要是左右方向,即您
$$ always | usually $$先查詢Channel,再查詢Operation,再查詢Function,你可以試試Minute+的索引(通常三個)。如果它相當隨意,那麼您可以嘗試使用 6 個索引,但這會影響插入性能。多少,我不能說,但如果這是一個執行分析的 DW 類型的應用程序,你可以批量插入,只是偶爾會受到打擊。您必須使用真實數據進行一些測試並解釋您的查詢 - 使用真實的樣本數據,正如我之前所說,只有幾條記錄的優化器會忽略索引,因為表太小了。有趣的是,在上面給出的 MySQL 手冊頁上,有一個看起來很有趣的散列策略 - 使用 CONCAT(Your_Column_List_Here) 的 MD5 散列。我可以建議的另一件事是,不要使用
SELECT TIME(FROM_UNIXTIME(UNIX_TIMESTAMP(Time_Series_TS) - MOD(UNIX_TIMESTAMP(Time_Series_TS), 60))) AS Minute,...
只需刪除 TIME() 函式,然後您將儲存似乎比 DATETIMES 上的索引更好的 INT - 請參閱此處以獲取基準。同樣如前所述,您應該從生產中刪除數據並在另一台機器上執行 OLAP/DW。您還可以測試我建議的 InfiniDB 解決方案。它與 MySQL 兼容(沒有學習曲線)。然後是所有的 NoSQL 解決方案——我們可以整天在這裡 :-)。看看幾個場景,評估和測試,然後選擇最適合您的預算和要求的方案。忘記了:讓您的 OLAP/DW 系統只讀以執行查詢 - 沒有事務成本!將 OLAP/DW 表設為 MyISAM?最後一個是有爭議的- 再次測試並查看。