時間序列:SQL 還是 NoSQL?
我不關心 SQL 和 NoSQL 之間的一般差異(或它們的傳統差異)。
我目前正在考慮改變我們內部時間序列的儲存。它們都包含來自多個不同來源的財務數據。目前,我們將數據儲存在專有數據庫中。它非常像 NoSQL,有自己的查詢語言。
我對社區的意見很感興趣:您將如何將數據儲存在 SQL 數據庫中?在 NoSQL 上使用 SQL 有什麼優點,特別是對於時間序列?考慮將其儲存在 SQL 中,我瘋了嗎?
我們的數據集由數百萬個時間序列組成,其中大約 10% 包含數百萬條記錄。時間序列按層次組織:/Market/Instrument/Value/Frequency,其中:
- 市場是證券交易所等,基本上是工具的集合,通常是類似的工具。
- 儀器是儀器。這可能是指標(布倫特原油)、股票(GOOG)等
- 值是一種工具的多種數據類型之一。這可能是收盤價、最高價、最低價等
- 頻率是特定時間序列值的頻率。每週,每天,每月,滴答,任意等。
數據將如何儲存在 SQL 數據庫中?一張大表(可能被某些東西分區),每個市場或工具一張表,每個時間序列一張表。
先感謝您。
一般來說,對於這樣一個結構化數據集,我懷疑您可以編寫一種自定義數據格式,該格式對於大多數日常操作來說更快(即從任意時間提取小數據)。遷移到標準數據庫工具的好處可能在於一些附加功能,例如即席查詢、多路訪問、複製、可用性等。還更容易聘請幫助來維護基於標準的數據儲存。
如果我被要求建立一個數據庫來儲存該數據,我會執行以下操作:
提議的模式
(1) 核心數據被放入大量(1000 個)單獨的表中,每個表包含兩列:
- 時間:SQL DATETIME 數據類型或某個時期的數字類型(這是主鍵)
- 值:根據您的數據鍵入。我會預設使用單精度浮點數,但是定點數據類型可能更適合金融交易。這可能是未索引的。
這些表將變得非常大,您可能希望按(例如)年份手動對它們進行分區。但是您必須檢查系統性能並酌情調整。
這些表需要唯一的名稱,並且有幾個選項。它們可以是人類可讀的(例如 nyse_goog_dailyhighs_2010)或(我的偏好)隨機的。無論哪種方式,都需要一組元數據表,並且隨機表名稱可防止開發人員將任何不應該被推斷的名稱推斷出來。
(2) 元數據根據應用程序的要求儲存在單獨的表中:
需要一個額外的表或一組表來跟踪元數據。這些表格將包含有關交易所、工具、價值、頻率、日期範圍、出處(數據來自哪裡)以及您需要的任何其他數據。這些映射到數據表名稱。
如果有足夠的數據,這個查找實際上可以提供一個表名和數據庫名,允許一種自我實現的數據分片(如果這是正確使用該術語的話)。但我會保留它。
然後在應用層我會查詢元數據表來確定我的數據在哪裡,然後在大數據表上執行相對簡單的查詢來獲取我的數據。
優點:
- 我的(相對有限的)經驗是,數據庫通常比處理少量大表更容易處理大量小表。這種方法還使維護更容易(例如清除舊數據、重建損壞的表、從備份創建/重新載入、添加新實體)。這完全解耦了不同類型的數據,例如,如果您有不同速率的數據,或者需要不同的數據類型。
- 這個瘦表概念還應該允許對我懷疑是最常見的查詢(來自單個實體的連續數據范圍)進行快速磁碟訪問。大多數數據應用程序都受磁碟 I/O 限制,因此值得考慮。正如評論者已經暗示的那樣,這對於面向列的數據庫來說是一個理想的應用程序,但是我還沒有找到一個足夠主流的面向列的產品,可以讓我將我的職業生涯押在上面。這個模式非常接近。
缺點:
- 大約一半的磁碟空間專門用於儲存時間戳,坦率地說,100 或 1000 個表將在時間戳列中具有完全相同的數據。(事實上,如果您想執行簡單的表連接,這是一個要求)。
- 儲存表名和執行動態查找需要大量的應用程序複雜性和字元串操作,這讓我感到畏縮。但它似乎仍然比替代品更好(下面討論)。
注意事項:
- 請注意在您的時間欄位中四捨五入。您希望您的值足夠圓以啟用連接(如果合適),但足夠精確以明確。
- 注意時區和夏令時。這些很難測試。我將對數據儲存強制執行 UTC 要求(這可能會讓我不受歡迎)並處理應用程序中的轉換。
變化:
我考慮過的一些變化是:
數據折疊: 如果時間序列等距,則使用一個時間戳列和(例如)10 個數據列。時間戳現在指的是第一個數據列的時間,並且假設其他數據列在該時間戳和下一個時間戳之間等間距。這樣可以節省大量以前用於儲存時間戳的儲存空間,但代價是查詢和/或應用程序的複雜性很高。連續範圍、單實體查詢現在需要更少的磁碟訪問。
多路復用: 如果已知多個時間序列使用相同的時間序列,則如上所述使用一個時間戳和(例如)10 個數據列。但現在每一列代表一個不同的時間序列。這需要更新元數據表,而不是查找表和列名。儲存空間減少。查詢仍然很簡單。無論範圍如何連續,單實體查詢現在都需要更多的磁碟訪問。
Mega-table: 將“多路復用”的概念發揮到極致,將所有數據放在一個表中,每列一個時間序列。這需要對連續範圍、單個實體查詢進行大量磁碟訪問,並且是維護的噩夢。例如,現在添加一個新實體需要對多 TB 表執行 MODIFY TABLE 命令。
有關此格式的更多討論,請參閱以下內容中的各種答案: MySQL 中的列太多
完全規範化的表: 您可以使用一個三列表,而不是使用許多 2 列表,其中列是 time、dataid 和 value。現在您的元數據表只需要查找 ID 值,而不是表名或列名,這樣就可以將更多邏輯推送到 SQL 查詢中,而不是應用程序層。
規範化列現在消耗了大約 2/3 的儲存空間,因此這將使用大量磁碟空間。
您可以使用 (dataid, timestamp) 的主鍵順序進行快速連續的單實體查詢。或者,您可以使用 (timestamp.dataid) 的主鍵順序來加快插入速度。
然而,即使在考慮了這些變化之後,我的下一個開發計劃還是有很多表,每個表有兩列。那,或者比我更聰明的人很快就會發布的方法:)。