2012-03-22 52 views
70

我有一個數據集,自1998年以來有1分鐘1000股的數據,總計約爲(2012-1998)*(365*24*60)*1000 = 7.3 Billion行。如何存儲73億行市場數據(優化後可讀取)?

大部分(99.9%)的時間我只會執行讀取請求。

將數據存儲在數據庫中的最佳方式是什麼?

  • 1個7.3B行的大表?
  • 1000個表格(每個股票代碼一個)每個有7.3M行?
  • 數據庫引擎的任何建議? (我正計劃使用Amazon RDS的MySQL)

我不習慣處理這麼大的數據集,所以這是一個很好的學習機會。我會很感激你的幫助和建議。

編輯:

這是一個示例行:

'XX',20041208,938,43.7444,43.7541,43.735,43.7444,35116.7,1,0,0

第1欄是股票代號,第2欄是日期,第3欄是分鐘,其餘是開高 - 低收盤價,成交量和3個整數欄。

大部分的查詢會像「給我AAPL的價格2012年4月12日12:15和2012年4月13日12:52之間的」

關於硬件:我打算使用Amazon RDS讓我」 m靈活

+5

描述預期的典型查詢 – 2012-03-22 01:30:40

+7

「我認爲你應該使用MongoDB,因爲它的網絡規模。」 – 2012-03-22 01:31:41

+7

您可能需要一張大桌子,由股票代碼分割。 – 2012-03-22 01:32:10

回答

24

告訴我們關於查詢和你的硬件環境。

我會非常想去NoSQL,使用Hadoop或類似的東西,只要你可以利用並行性。

更新

好了,爲什麼呢?

首先,請注意我詢問了有關查詢。你不能 - 我們當然不能 - 在不知道工作量是什麼的情況下回答這些問題。 (我會共同順帶對這個即將出現的文章,但今天我不能聯繫起來。)但問題的規模讓我考慮從大的舊數據庫移開,因爲

  • 我對類似系統的使用經驗表明,訪問要麼是大序列(計算某種時間序列分析),要麼是非常靈活的數據挖掘(OLAP)。順序數據可以按順序更好更快地處理; OLAP意味着計算大量和大量的索引,這會佔用大量時間或大量空間。

  • 但是,如果您正在對OLAP領域的許多數據進行有效的大規模運行,那麼面向列的方法可能是最好的。

  • 如果你想要做的隨機查詢,尤其是在進行交叉比較,一個Hadoop系統可能是有效的。爲什麼?因爲

    • 您可以更好地利用相對較小的商品硬件的並行性。
    • 您還可以更好地實現高可靠性和冗餘性
    • 許多這些問題自然適用於MapReduce範例。

但事實是,直到我們知道你的工作量,它不可能把話說絕。

+5

「NoSQL」在這裏提供什麼優勢?爲什麼不在一個傳統的RDBMS *中的單個大表? (使用正確的索引等)每個人都去「NoSQL」,「NoSQL」,「NoSQL」,但是...... *爲什麼*? – 2012-03-22 01:45:06

+1

@pst MongoDB是網絡規模 – 2012-03-22 02:30:14

+5

我不得不說我的建議也是使用Apache Accumulo的NoSQL方法(這是個人喜好)。數據集很小(對於Accumulo)和所需查詢類型似乎完全適合使用其分佈式迭代器堆棧。 – 2012-03-22 04:57:35

14

這是我的理解是HDF5是用時間序列存儲庫存數據作爲一個潛在的應用而設計的。研究人員表示,HDF5適用於大量數據:chromosomes,physics

+2

對於特定的解決方案。不過,我確實喜歡SQL DQL(大部分)以及它提供的靈活性......不確定HDF5需要什麼來移出「分層視圖」。 – 2012-03-22 01:48:10

15

好了,所以這是從其他的答案有點遠,但是......那感覺對我來說,如果你在一個文件系統中的數據(每個文件一個股票,也許)有固定的記錄大小,你可以獲得數據真的容易:給予特定的股票和時間範圍查詢,你可以尋求到合適的位置,獲取你所需要的(你就會知道到底有多少個字節)的數據,將數據轉換成您需要的格式(根據您的存儲格式可能會非常快),並且您不在。

我對亞馬遜存儲沒有任何瞭解,但是如果您沒有任何類似直接文件訪問的功能,您基本上可以使用斑點 - 您需要平衡大斑點(更少記錄,但可能讀取更多數據比你需要的每一次)小塊(更多的記錄提供更多的開銷和可能更多的請求來獲得它們,但每次返回的無用數據較少)。

接下來需要添加緩存 - 我建議給不同的服務器不同的股票來處理 - 例如,你可以非常簡單,只是從內存服務。如果您能夠在足夠的服務器上負擔足夠的內存,請繞過「按需加載」部分,並在啓動時加載所有文件。這樣做會簡化一些工作,但代價是啓動速度較慢(這顯然會影響故障切換,除非您可以承擔任何特定庫存始終具有的服務器數量,這將有所幫助)。

請注意,您不需要商店股票代碼,每個記錄的日期或分鐘 - 因爲它們隱含在您正在加載的文件和文件中的位置。您還應該考慮每個值需要多少準確性,以及如何有效存儲這些數據 - 您已經爲您的問題提供了6SF,您可以用20位存儲該數據。可能將三個20位整數存儲在64位存儲中:將其讀取爲long(或任何您的64位整數值)並使用掩碼/移位將其恢復爲三個整數。當然,你需要知道使用什麼樣的規模 - 如果你不能使其保持恆定,你可能需要在備用4位中進行編碼。

你還沒有說什麼其他三個整數列都喜歡,但如果你能逃脫64位的這三個,以及,你可以一整個記錄存儲在16個字節。對於整個數據庫來說,這只是〜110GB,這並不是真的很...

編輯:另一件要考慮的事情是,大概在週末 - 甚至一夜之間股票不會改變。如果股票市場每週只開放8個小時,每週5天,那麼每週只需要40個值,而不是168個。那時,您的文件中只有大約28GB的數據......這聽起來很不錯比你原本想的要小很多。有這麼多的數據在內存中是非常合理的

編輯:我想我已經錯過了的解釋爲什麼這種方法在這裏是不錯的選擇:你有一個非常明確的方面爲您的數據的很大一部分 - 的股票代碼,日期和時間。通過表示一次(作爲文件名)並將日期/時間完全隱含在數據的位置中,您將刪除大量工作。這有點像String[]Map<Integer, String>之間的區別 - 知道你的數組索引總是從0開始,以1爲增量增加到數組的長度,允許快速訪問和更有效的存儲。

+0

這又取決於他如何使用數據。如果他的查詢是要在整個板上提供一個特定數據(股票代碼明智),那麼這將導致閱讀每個文件並具有特定的日期編碼從每個文件中提取正確的數據。或者如果他希望每週表現最好的股票,那麼這將是一個噩夢與這種設置不得不閱讀所有記錄進行排序和比較。如果沒有這些信息,我們只能猜測這是針對固定存儲的 - 可能是一個批量數據倉庫,它將在某個時間點(ETL源)提供一個報告數據倉庫。 – Wolf5370 2012-03-30 06:01:45

+2

@ Wolf5370:是的,我們當然需要知道這些查詢會是什麼,但我們至少從問題中可以看出一些跡象:「大部分查詢都會像」給我AAPL的價格2012年4月12日12:15和2012年4月13日12:52',這將是很高興知道*其他*查詢將是什麼,以及相對頻率和性能要求 – 2012-03-30 06:04:25

+0

@JonSkeet它真的取決於工作量,但我有一些域這種系統的知識很少,只是「在一個範圍內選擇一隻股票」:它更經常地「在這個範圍內選擇這個投資組合中的股票,計算β然後嘗試這個可能的股票列表,然後看看什麼是β。 「這就是爲什麼它促使你走向類似OLAP的東西。 – 2012-03-31 09:29:28

3

讓我推薦你看看apache solr,我認爲這對你的特定問題是很理想的。基本上,你會首先索引你的數據(每一行都是一個「文檔」)。 Solr針對搜索進行了優化,並本地支持日期範圍查詢。您的名義查詢,

"Give me the prices of AAPL between April 12 2012 12:15 and April 13 2012 12:52"

將轉化爲類似:

?q=stock:AAPL AND date:[2012-04-12T12:15:00Z TO 2012-04-13T12:52:00Z] 

假設「股票」是股票的名稱和「日期」是「的DateField」,從「日期」創建索引中輸入數據的「分鐘」列。 Solr非常靈活,我真的不能說足夠多的好東西。因此,例如,如果您需要維護原始數據中的字段,則可以找到一種方法來動態創建「DateField」作爲查詢(或過濾器)的一部分。

+0

您也可以使用Amazon EC2設置您的solr實例... http://www.lucidimagination.com/blog/2010/02/01/solr-shines-through-the-cloud-lucidworks-solr-on- ec2/ – aliasmrchips 2012-03-28 23:10:59

+3

SOLR適用於搜索,但仍然需要將數據存儲在某處,以填充索引。 – 2012-03-29 02:39:10

+0

是的。我假設維克多P有數據的地方,它將需要索引。這將需要額外的資源......但是,所有提議的方法都是如此。 – aliasmrchips 2012-03-31 01:44:07

2

我認爲任何主要的關係型數據庫管理系統都可以解決這個問題。在原子級別上,具有正確分區的一張表似乎是合理的(如果修復了基於數據使用的分區 - 這可能是符號或日期)。

您還可以查看構建聚合表以便在原子級別之上更快地訪問。例如,如果您的數據是在白天,但您經常會將數據恢復到wekk或甚至月份的水平,那麼可以在聚合表中預先計算。在一些數據庫中,這可以通過緩存視圖完成(不同的DB解決方案的不同名稱 - 但基本上它是對原子數據的一個視圖,但是一旦運行該視圖就被緩存/強化到固定的臨時表中 - 查詢子查詢匹配查詢這可以在間隔時間內釋放以釋放內存/磁盤空間)。

我想我們可以幫助您更多地瞭解數據使用情況。

2

您應該將緩慢的解決方案與簡單優化的內存模型進行比較。未壓縮,適合256 GB RAM內存服務器。快照適用於32 K,您只需在日期時間和庫存中對其進行位置索引。然後你可以製作專門的快照,因爲開放的快照通常等於關閉前一個。

爲什麼你認爲使用數據庫(rdbms或nosql)是有意義的?這些數據不會改變,它適合內存。這不是dbms可以增加值的用例。

+0

實際上,有幾個原因,最重要的是,如果你有256 GB的內存,它會很好,如果有臨時空間的空間,操作系統,等等。然後就有檢查點,記錄和容錯等問題 - 一旦你開始計算任何中間結果,你就需要管理存儲。我同意RDBMS不是最好的選擇 - 但比「將大數組加載到內存中」更聰明是絕對需要的。 – 2012-03-31 09:33:52

+0

點校驗,日誌和容錯對於近似靜態數據來說非常簡單。這聽起來像是適合prevayler風格解決方案的理想選擇 – 2012-04-01 13:06:55

+0

再一次地,如果沒有對應用程序的更好的瞭解,就不可能肯定地說,但總的來說,應用程序並不像您想象的那樣靜態,因爲您要維護結果集以及因爲您正在進行成本高昂的計算,而且計算檢查點和預先計算的部分結果。 – 2012-04-02 13:35:36

2

如果您有硬件,我推薦MySQL Cluster。您可以獲得您熟悉的MySQL/RDBMS接口,並且可以快速並行寫入數據。由於網絡延遲,讀取速度比普通MySQL慢,但由於MySQL簇和NDB存儲引擎的工作方式,您可以並行查詢和讀取。

請確保您擁有足夠的MySQL Cluster機器和足夠的內存/內存用於這些 - 但MySQL Cluster是一個面向內存的高度數據庫體系結構。

Redis,如果您不介意讀/寫的鍵/值/ NoSQL接口。確保Redis具有足夠的內存 - 它的讀寫速度超快,您可以使用它進行基本查詢(儘管非RDBMS),但也是內存數據庫。

像其他人一樣說,瞭解更多關於您將運行的查詢將有所幫助。

37

因此,數據庫適用於需要不斷變化的大型複雜模式的情況。你只有一個帶有簡單數字字段的「表」。我會做這種方式:

準備一個C/C++結構以保存記錄格式:

struct StockPrice 
{ 
    char ticker_code[2]; 
    double stock_price; 
    timespec when; 
    etc 
}; 

然後計算的sizeof(StockPrice [N])其中N是記錄數。 (在64位系統上)它應該只有幾百兆,並且可以安裝在50美元的硬盤上。

然後截斷文件到的大小和MMAP(在Linux上,或在Windows上使用的CreateFileMapping)到內存:

//pseduo-code 
file = open("my.data", WRITE_ONLY); 
truncate(file, sizeof(StockPrice[N])); 
void* p = mmap(file, WRITE_ONLY); 

鑄mmaped指針StockPrice *,使您的數據填充的通出陣列。關閉mmap,現在你可以將數據放在一個文件中的一個大的二進制數組中,以後再進行配置。

StockPrice* stocks = (StockPrice*) p; 
for (size_t i = 0; i < N; i++) 
{ 
    stocks[i] = ParseNextStock(stock_indata_file); 
} 
close(file); 

現在你可以的mmap再次只讀從任何程序和數據將是現成的:

file = open("my.data", READ_ONLY); 
StockPrice* stocks = (StockPrice*) mmap(file, READ_ONLY); 

// do stuff with stocks; 

所以,現在你可以把它就像一個內存陣列結構的。您可以根據您的「查詢」來創建各種索引數據結構。內核將處理將數據透明地交換到磁盤或從磁盤交換數據,所以它會非常快速。

如果您希望具有某種訪問模式(例如連續日期),最好按照該順序對數組進行排序,以便順序地訪問磁盤。

+7

花幾百把它放在SSD而不是硬盤上。隨機讀取大約快一百倍。或者在公羊上花10K。更快 – 2012-04-01 07:47:05

+0

@Andrew Tomazos感謝哥們另一個百倍,這個人是 「該」 回答 – 2016-09-17 17:08:32

+1

StockPrice的sizeof將是 炭[4] = 4字節 INT = 4個字節 短= 2個字節 浮子= 4個字節 浮= 4個字節 浮子= 4個字節 浮子= 4個字節 浮子= 4個字節 INT = 4個字節 INT = 4個字節 INT = 4個字節 ------------ 42字節 約306. 6億字節=〜285.5435013771057 GB內存... 祝你好運 – ZagNut 2016-09-21 14:21:43

4

這裏是試圖建立在Microsoft SQL Server 2012的數據庫之上的市場數據服務器,該服務器應該是不錯的OLAP分析,一個免費的開源項目:

http://github.com/kriasoft/market-data

+0

Yeh。不確定該特定項目是否適用,但肯定會建議OP考慮OLAP或數據倉庫事實表結構,這兩種方法(有時一起使用)都旨在解決這類數據量非常大的行。這實際上取決於他們打算執行什麼樣的分析。 – AaronLS 2014-08-20 21:37:14

4

首先,ISN今年365天的交易日,假期52週末(104)= 250 x實際的日間市場開放時間像某人所說的那樣,並且使用該符號作爲主鍵不是一個好主意,因爲符號發生變化,使用帶符號(char)的k_equity_id(數字),因爲符號可以像這樣A,或者GAC-DB-B.TO,那麼在價格信息的數據表中,你有,所以你估計有73億是遠遠超過CALCULAT因爲它在14年內每個符號只有大約170萬行。

k_equity_id k_date k_minute

和排爆表(將在其他數據被視爲1000倍)

k_equity_id k_date

其次,不要用存放分鐘,向您OHLC數據在同一個數據庫表中作爲EOD表(日期結束),因爲任何想在一年中查看pnf或折線圖的人都對分鐘信息沒有興趣。

19

我有1000股[...]大多數(99.9%)1個數據的數據集的時間,我將僅執行請求。

存儲一次和讀取多次基於時間的數值數據是一個稱爲「時間序列」的用例。其他常見的時間序列在物聯網傳感器數據,服務器監測統計,應用事件等

這個問題被問在2012年,從那時起,一些數據庫引擎已專門開發的功能,用於管理時間序列。 InfluxDB這個開放源代碼,使用Go編寫,並且MIT許可。

InfluxDB專門針對時間序列數據的存儲和查詢進行了優化。 Much more so than Cassandra,其通常吹捧存儲時序一樣大:

InfluxDB vs Cassandra query speed

優化處理時間序列涉及某些權衡。例如:

對現有數據的更新很少發生,並且永遠不會發生有爭議的更新。時間序列數據主要是從未更新的新數據。

臨:限制對更新的訪問允許增加查詢和寫入性能

缺點:更新功能顯著限制

open sourced benchmarks

InfluxDB在所有三個測試跑贏的MongoDB其寫入吞吐量提高了27倍,同時使用的磁盤空間減少了84倍,並且在查詢速度方面性能相當平等。

InfluxDB vs. MongoDB on-disk storage requirements and compression

查詢也很簡單。如果你的行看起來像<symbol, timestamp, open, high, low, close, volume>,InfluxDB你可以存儲,然後輕鬆查詢。例如,對於最後10分鐘的數據:

SELECT open, close FROM market_data WHERE symbol = 'AAPL' AND time > '2012-04-12 12:15' AND time < '2012-04-13 12:52' 

沒有ID,沒有鍵,也沒有連接。你可以做很多interesting aggregations。您不必須vertically partition the table as with PostgreSQLcontort your schema into arrays of seconds as with MongoDB。另外,InfluxDB壓縮得很好,而PostgreSQL won't be able to perform any compression on the type of data you have

1

如果您的用例是簡單地讀取沒有聚合的行,您可以使用Aerospike集羣。它在內存數據庫中支持文​​件系統的持久性。它也是SSD優化的。

如果您的用例需要聚合數據,請使用日期範圍分片的Mongo數據庫集羣。您可以在碎片中使用年份vise數據。

1

您將需要存儲在columnar table/database中的數據。像Vertica和Greenplum這樣的數據庫系統是列式數據庫,我相信SQL Server現在允許列式表格。這些對於非常大的數據集非常有效。它們在導入大型數據集時也很有效。

免費的柱狀數據庫是MonetDB