高頻交易里,1毫秒的延遲可能意味著47萬的滑點損失。但比延遲更隱蔽的殺手,是你選錯了數據庫類型。
Bhaskar Das在Medium上發了一篇技術復盤,講一個真實場景:某交易團隊用文檔型數據庫存儲分鐘級行情,結果回測時查詢速度比預期慢了兩個數量級。問題不在代碼,在數據模型與查詢模式的錯配。
這不是個案。2024年某頭部私募的技術負責人跟我聊過,他們花了3個月才把核心系統從MongoDB遷到專用時序數據庫,遷移成本占當年技術預算的18%。
文檔型 vs 時序型:交易場景的分水嶺
文檔型數據庫(如MongoDB)把數據存成JSON-like的靈活結構,適合訂單詳情、賬戶配置這類半結構化數據。一條訂單記錄可能包含20個字段,不同交易所的字段還不一樣,文檔型能直接吞進去,不用改表結構。
時序數據庫(如InfluxDB、TimescaleDB)則專門為時間戳數據優化。行情tick、技術指標(RSI、ATR這些)、傳感器流數據——這些按時間順序瘋狂涌入的數據,時序型能用列式存儲+時間分區,把寫入吞吐量拉滿。
Das在文章里打了個比方:文檔型像瑞士軍刀,時序型像手術刀。交易場景里,你用軍刀做手術,不是不能做,是血會流得比較多。
具體數字很能說明問題。某測試環境下,單節點InfluxDB處理100萬條tick數據的寫入延遲是12毫秒,同配置MongoDB要到340毫秒。查詢30天分鐘線時,時序型的聚合查詢快17倍。
但反過來,如果你要查"某用戶過去3個月所有止盈訂單的詳細字段",文檔型一條查詢搞定,時序型得跨多個分區做關聯,性能直接崩盤。
索引策略:藏在查詢計劃里的利潤
選對了數據庫類型,下一步是索引。Das提到一個細節:很多團隊在建索引時照搬關系型數據庫的經驗,結果在NoSQL里踩坑。
文檔型數據庫的復合索引有前綴匹配規則。你建了{symbol: 1, timestamp: 1}的索引,查詢時如果只帶timestamp條件,索引會失效。高頻策略里這種查詢很常見——比如"查所有品種在14:30的盤口",索引失效意味著全表掃描。
時序數據庫的索引邏輯完全不同。它們通常自動按時間分區,但對標簽(tag)的索引需要手動設計。InfluxDB里,把高頻變化的字段(如價格)設成tag會導致索引爆炸,寫入性能斷崖下跌。正確的做法是把symbol、exchange這類低基數字段設tag,價格放field。
某量化團隊的技術日志顯示,他們曾因把order_id設成tag,導致單日寫入從50萬條降到8萬條,排查了兩天才發現是索引設計問題。
查詢模式:你的策略代碼在偷偷燒錢
交易系統的查詢模式決定了數據庫的選型權重。Das梳理了三種典型場景:
實時信號生成:需要亞毫秒級的最新值查詢,時序型的內存緩存+預聚合是剛需。某CTA策略用Redis+InfluxDB組合,把信號延遲從23毫秒壓到1.8毫秒。
歷史回測:需要批量拉取長時間序列,列式存儲的壓縮率和順序讀取優勢巨大。1年的分鐘線數據,時序型存儲占用通常是文檔型的1/5到1/10。
合規審計:需要隨機訪問特定訂單的完整生命周期,文檔型的靈活Schema更適合。監管要求保留5年交易記錄,文檔型的查詢穩定性比時序型高40%(某券商2023年壓測數據)。
沒有銀彈。大多數成熟團隊采用混合架構:時序庫存行情,文檔庫存訂單,中間用消息隊列同步。但這也帶來一致性問題——某次網絡分區后,兩個庫的同一筆訂單狀態不一致,風控系統誤觸發平倉。
Das在文章結尾提了一個被忽略的細節:某開源時序數據庫的默認配置,會在內存不足時丟棄最新寫入的數據,而不是阻塞等待。這對交易系統是災難性的——你以為是數據延遲,其實是數據丟失。
你的生產環境檢查過這個配置嗎?
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.