乾貨丨DolphinDB內存分區表的加載和操做

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 插入數據

能夠經過如下方法往內存表中插入數據:

  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 增長列

能夠經過如下三種方法爲內存表增長列:

  1. 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 更新已存在的列

能夠經過如下三種方法爲內存表更新列:

  1. 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 刪除行

能夠經過如下三種方法爲內存表刪除行:

  1. 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 刪除內存表

能夠經過如下兩種方法刪除內存表:

  1. 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)
相關文章
相關標籤/搜索