DolphinDB的內存數據表能夠是非分區的,也能夠是分區的。除了組合分區之外的全部分區方式都適用於內存數據表。使用分區內存表進行運算能充分發揮多核CPU並行計算的優點。sql
1. 建立內存數據表
1.1 建立非分區內存表數據庫
使用table函數能夠建立非分區內存表。table函數的用法很是靈活:服務器
- 第一種用法:table(X, [X1], [X2], .....)
這裏的X, X1, X2能夠是向量、矩陣或元組,其中每一個向量、矩陣和元組中每一個元素的長度必須相同。app
例1. 若是X是向量,那麼每一個向量對應表中一列。函數
id=`XOM`GS`AAPL x=102.1 33.4 73.6 table(id, x) id x ---- ----- XOM 102.1 GS 33.4 AAPL 73.6 table(`XOM`GS`AAPL as id, 102.1 33.4 73.6 as x) id x ---- ----- XOM 102.1 GS 33.4 AAPL 73.6
例2. 若是X是矩陣,table函數將矩陣轉換爲表。性能
m1=1..6$3:2 table(m1) C0 C1 -- -- 1 4 2 5 3 6 m2=7..12$3:2 table(m1,m2) C0 C1 C2 C3 -- -- -- -- 1 4 7 10 2 5 8 11 3 6 9 12
例3. 若是X是元組,那麼元組中的每一個元素對應表中的一列。spa
x=(["a","b","c"],[4,5,6]) table(x) C0 C1 -- -- a 4 b 5 c 6
例4. table函數的輸入是向量、矩陣和元組。code
x=1..6 y=11..22$6:2 z=(101..106, 201..206) x C1 C2 C3 C4 - -- -- --- --- 1 11 17 101 201 2 12 18 102 202 3 13 19 103 203 4 14 20 104 204 5 15 21 105 205 6 16 22 106 206
- 第二種用法:table(capacity:size, colNames, colTypes)
咱們能夠經過指定表的容量和初始大小、列名以及每列的數據類型來建立內存表。若是表中實際的記錄行數超出的capacity,它會自動擴展。若是要建立一個空的表,能夠把size設置爲0,若是size>0,建立表時會使用默認值填充。例如,blog
table(200:0, `name`id`value, [STRING,INT,DOUBLE]) name id value ---- -- ----- table(200:10, `name`id`value, [STRING,INT,DOUBLE]) name id value ---- -- ----- 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1.2 建立分區內存表排序
經過createPartitionedTable函數能夠建立分區內存表。在建立分區內存表以前,須要建立內存的分區數據庫,而且分區數據庫的路徑爲空字符串。
n=10000 t=table(rand(1..10,n) as id,rand(10.0,n) as val) db=database("",VALUE,1..10) pt=db.createPartitionedTable(t,`pt,`id).append!(t) typestr(pt) SEGMENTED IN-MEMORY TABLE
對於內存分區表,不能直接訪問,須要使用SQL語句訪問。
select * from pt
2. 加載數據到內存表
咱們經過如下腳本,生成一個模擬數據集,用於後續例子。
n=30000000 workDir = "C:/DolphinDB/Data" if(!exists(workDir)) mkdir(workDir) trades=table(rand(`IBM`MSFT`GM`C`FB`GOOG`V`F`XOM`AMZN`TSLA`PG`S,n) as sym, 2000.01.01+rand(365,n) as date, 10.0+rand(2.0,n) as price1, 100.0+rand(20.0,n) as price2, 1000.0+rand(200.0,n) as price3, 10000.0+rand(2000.0,n) as price4, 10000.0+rand(3000.0,n) as price5, 10000.0+rand(4000.0,n) as price6, rand(10,n) as qty1, rand(100,n) as qty2, rand(1000,n) as qty3, rand(10000,n) as qty4, rand(10000,n) as qty5, rand(10000,n) as qty6) trades.saveText(workDir + "/trades.txt");
2.1 加載數據到未分區內存表
使用loadText函數將文本文件數據導入到未分區的內存表。
trades=loadText(workDir + "/trades.txt")
2.2 加載數據到內存分區表
2.2.1 使用ploadText函數將文本文件導入爲順序分區的內存表
這是將數據導入到內存分區表最簡單的方法,但缺少其它導入方法的某些優勢及靈活性。例如,須要導入的文本文件必須小於可用內存;沒法使用函數sortBy!
進行分區內有意義的排序,等等。
trades = ploadText(workDir + "/trades.txt");
2.2.2 使用loadTextEx函數將文本文件導入爲指定分區方式的表
這種方法適合下列狀況:
- 常常須要在各個分區內部進行排序
- 常常須要根據分區字段進行group by與context by的計算
使用這種方法時,database函數的directory參數以及loadTextEx函數的tableName參數需使用空字符串("")。
db = database("", VALUE, `IBM`MSFT`GM`C`FB`GOOG`V`F`XOM`AMZN`TSLA`PG`S) trades = db.loadTextEx("", `sym, workDir + "/trades.txt"); trades.sortBy!(`qty1); trades.sortBy!(`date`qty1, false true); trades.sortBy!(<qty1 * price1>, false);
請注意,對內存分區表使用函數 sortBy! 時,是在每一個分區內部進行排序,並非對全表進行排序。
咱們分別對未分區內存表、順序分區內存表以及本節中的VALUE分區內存表進行相同的分組聚合運算。SQL語句以下:
timer(10) select std(qty1) from trades group by sym;
這裏的 "timer(10)" 指的是此語句被連續執行10次的總耗時。
結果以下表所致。能夠看到,當分組列和分區列相同時,分組計算性能最優。
2.2.3 使用loadTable函數導入磁盤分區表的所有或部分分區
這種方法適合下列狀況:
- 文本文件比服務器可用內存更大,而且每次只須要用到其中的一部分數據。
- 須要重複使用數據。加載一個數據庫表比導入一個文本文件要快得多。
使用loadTextEx在磁盤上創建一個分區表:(亦可以使用createPartitionedTable和append!函數)
db = database(workDir+"/tradeDB", RANGE, ["A","G","M","S","ZZZZ"]) db.loadTextEx(`trades, `sym, workDir + "/trades.txt");
若只須要加載兩個分區(["A","G")與["M","S"))到內存時:
db = database(workDir+"/tradeDB") trades=loadTable(db, `trades, ["A", "M"], 1);
請注意,這裏須要將函數loadTable的可選參數memoryMode設爲1,不然將只會加載表的元數據。
2.2.4 使用loadTableBySQL函數導入磁盤分區表指定的行/列
這是最靈活的產生內存分區表的方法,可使用SQL語句選擇磁盤分區表中指定的行/列以載入內存分區表。需與函數loadTable結合使用。
db = database(workDir+"/tradeDB") trades=loadTable(db, `trades); sample=loadTableBySQL(<select * from trades where date between 2000.03.01 : 2000.05.01>); sample=loadTableBySQL(<select sym, date, price1, qty1 from trades where date between 2000.03.01 : 2000.05.01>); dates = 2000.01.16 2000.02.14 2000.08.01 st = sql(<select sym, date, price1, qty1>, trades, expr(<date>, in, dates)) sample = loadTableBySQL(st); colNames =`sym`date`qty2`price2 st= sql(sqlCol(colNames), trades) sample = loadTableBySQL(st);
3. 內存表的數據處理
以2.2.3中的分區內存表trades爲例,介紹內存表的用法。
trades = ploadText(workDir + "/trades.txt");
3.1 插入數據
能夠經過如下方法往內存表中插入數據:
- SQL insert 語句
//往指定列插入數據,其餘列爲空 insert into trades(sym,date) values(`S,2000.12.31) //往全部列插入數據 insert into trades values(`S`IBM,[2000.12.31,2000.12.30],[10.0,20.0],[10.0,20.0],[10.0,20.0],[10.0,20.0],[10.0,20.0],[10.0,20.0],[10,20],[10,20],[10,20],[10,20],[10,20],[10,20])
2. append!函數
若是使用 append! 函數往表中插入數據,新數據必須是以表的形式表示。例如:
tmp=table(`S`IBM as col1,[2000.12.31,2000.12.30] as col2,[10.0,20.0] as col3,[10.0,20.0] as col4,[10.0,20.0] as col5,[10.0,20.0] as col6,[10.0,20.0] as col7,[10.0,20.0] as col8,[10,20] as col9,[10,20] as col10,[10,20] as col11,[10,20] as col12,[10,20] as col13,[10,20] as col14) trades.append!(tmp)
3. tableInsert 函數
tableInsert 函數會返回插入的行數。
對於分區表,若是使用 tableInsert 函數往表中插入數據,新數據必須是以表的形式表示。
tmp=table(`S`IBM as col1,[2000.12.31,2000.12.30] as col2,[10.0,20.0] as col3,[10.0,20.0] as col4,[10.0,20.0] as col5,[10.0,20.0] as col6,[10.0,20.0] as col7,[10.0,20.0] as col8,[10,20] as col9,[10,20] as col10,[10,20] as col11,[10,20] as col12,[10,20] as col13,[10,20] as col14) trades.tableInsert(tmp) 2
對於未分區表,若是使用tableInsert 函數往表中插入數據,新數據能夠用元組的形式表示。
a=(`S`IBM,[2000.12.31,2000.12.30],[10.0,20.0],[10.0,20.0],[10.0,20.0],[10.0,20.0],[10.0,20.0],[10.0,20.0],[10,20],[10,20],[10,20],[10,20],[10,20],[10,20]) trades.tableInsert(a)
3.2 增長列
能夠經過如下三種方法爲內存表增長列:
- SQL update 語句
update trades set logPrice1=log(price1), newQty1=double(qty1);
2. update! 函數
trades.update!(`logPrice1`newQty1, <[log(price1), double(qty1)]>);
3. 賦值語句
trades[`logPrice1`newQty1] = <[log(price1), double(qty1)]>;
3.3 更新已存在的列
能夠經過如下三種方法爲內存表更新列:
- SQL update 語句
update trades set qty1=qty1+10; update trades set qty1=qty1+10 where sym=`IBM;
2. update! 函數
trades.update!(`qty1, <qty1+10>); trades.update!(`qty1, <qty1+10>, <sym=`IBM>);
3. 賦值語句
trades[`qty1] = <qty1+10>; trades[`qty1, <sym=`IBM>] = <qty1+10>;
3.4 刪除行
能夠經過如下三種方法爲內存表刪除行:
- SQL delete 語句
delete from trades where qty3<20;
2. erase 語句
trades.erase!(< qty3<30 >);
3.5 刪除列
經過 drop! 函數刪除列:
trades.drop!("qty1");
3.6 重命名列
經過 rename! 函數重命名列:
trades.rename!("qty2", "qty2New");
3.7 查看錶結構
經過schema函數查看錶的結構:
schema(trades) partitionSchema->[XOM,V,TSLA,S,PG,MSFT,IBM,GOOG,GM,FB,...] partitionSites-> partitionColumnIndex->0 chunkPath-> colDefs-> name typeString typeInt comment ------ ---------- ------- ------- sym SYMBOL 17 date DATE 6 price1 DOUBLE 16 price2 DOUBLE 16 price3 DOUBLE 16 price4 DOUBLE 16 price5 DOUBLE 16 price6 DOUBLE 16 qty1 INT 4 qty2 INT 4 qty3 INT 4 qty4 INT 4 qty5 INT 4 qty6 INT 4 partitionType->1 partitionColumnName->sym
3.8 刪除內存表
能夠經過如下兩種方法刪除內存表:
- undef函數
undef(`trades)
2. 把變量賦值爲NULL
trades=NULL
undef 函數會將命名空間刪除,而把變量賦值爲NULL仍然保留命名空間。
3.9 修改列的數據類型
經過replaceColumn! 函數能夠修改列的數據類型。目前只有未分區的內存表才支持修改列的數據類型,分區內存表不支持該功能。以未分區的內存表trades爲例,將price1的數據類型修改成FLOAT(目前是DOUBLE):
NewPrice1=float(exec price1 from trades) replaceColumn!(trades,`price1,NewPrice1) schema(trades) partitionColumnIndex->-1 chunkPath-> colDefs-> name typeString typeInt comment ------ ---------- ------- ------- sym SYMBOL 17 date DATE 6 price1 `FLOAT` 15 price2 DOUBLE 16 price3 DOUBLE 16 price4 DOUBLE 16 price5 DOUBLE 16 price6 DOUBLE 16 qty1 INT 4 qty2 INT 4 qty3 INT 4 qty4 INT 4 qty5 INT 4 qty6 INT 4
3.10 修改列的順序
經過reorderColumns! 函數能夠修改列的順序。目前只有未分區的內存表才支持修改列的數據類型,分區內存表不支持該功能。以未分區的內存表trades爲例,將列的順序調整爲sym,date,price6,price5,...,price1,qty6,qty5,...,qty1。
reorderColumns!(trades,`sym`date`price6`price5`price4`price3`price2`price1`qty6`qty5`qty4`qty3`qty2`qty1)