DolphinDB的内存数据表可以是非分区的,也可以是分区的。除了组合分区以外的所有分区方式都适用于内存数据表。使用分区内存表进行运算能充分发挥多核CPU并行计算的优势。 1. 创建内存数据表 …
DolphinDB的内存数据表可以是非分区的,也可以是分区的。除了组合分区以外的所有分区方式都适用于内存数据表。使用分区内存表进行运算能充分发挥多核CPU并行计算的优势。
1. 创建内存数据表 1.1 创建非分区内存表 使用table函数可以创建非分区内存表。table函数的用法非常灵活:
1 第一种用法:table(X, [X1], [X2], .....)
这里的X, X1, X2可以是向量、矩阵或元组,其中每个向量、矩阵和元组中每个元素的长度必须相同。 例1. 如果X是向量,那么每个向量对应表中一列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 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) `例2. 如果X是矩阵,table函数将矩阵转换为表。```java 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是元组,那么元组中的每个元素对应表中的一列。```java x=(["a" ,"b" ,"c" ],[4 ,5 ,6 ]) table(x) C0 C1 -- -- a 4 b 5 c 6 `例4. table函数的输入是向量、矩阵和元组。```java 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
1 第二种用法:table(capacity:size, colNames, colTypes)
1 我们可以通过指定表的容量和初始大小、列名以及每列的数据类型来创建内存表。如果表中实际的记录行数超出的capacity,它会自动扩展。如果要创建一个空的表,可以把size设置为0,如果size>0,创建表时会使用默认值填充。例如,
1 table(200:0, `name`id`value, [STRING,INT,DOUBLE])
name id value
1 table(200:10, `name`id`value, [STRING,INT,DOUBLE])
0 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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语句访问。```sql SELECT * from pt
2. 加载数据到内存表 我们通过以下脚本,生成一个模拟数据集,用于后续例子。
1 2 3 4 5 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");
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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语句如下:
1 timer(10 ) select std(qty1) from trades group by sym;
1 这里的 "timer(10)" 指的是此语句被连续执行10次的总耗时。
结果如下表所致。可以看到,当分组列和分区列相同时,分组计算性能最优。 2.2.3 使用loadTable函数导入磁盘分区表的全部或部分分区
文本文件比服务器可用内存更大,并且每次只需要用到其中的一部分数据。 需要重复使用数据。加载一个数据库表比导入一个文本文件要快得多。
使用loadTextEx在磁盘上建立一个分区表:(亦可使用createPartitionedTable和append!函数)
1 2 db = database(workDir+"/tradeDB", RANGE, ["A","G","M","S","ZZZZ"]) db.loadTextEx(`trades, `sym, workDir + "/trades.txt");
`若只需要加载两个分区([“A”,”G”)与[“M”,”S”))到内存时:```java
1 2 db = database(workDir+"/tradeDB") trades=loadTable(db, `trades, ["A", "M"], 1);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 请注意,这里需要将函数loadTable的可选参数memoryMode设为1,否则将只会加载表的元数据。 2.2.4 使用loadTableBySQL函数导入磁盘分区表指定的行/列 这是最灵活的产生内存分区表的方法,可以使用SQL语句选择磁盘分区表中指定的行/列以载入内存分区表。需与函数loadTable结合使用。 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)
3. 内存表的数据处理 1 以2.2.3中的分区内存表trades为例,介绍内存表的用法。 `trades = ploadText(workDir + "/trades.txt");` 3.1 插入数据
可以通过以下方法往内存表中插入数据:
SQL insert 语句
1 2 / / 往指定列插入数据,其他列为空 insert into trades(sym,date ) values (`S,2000.12 .31 )
1 2 / / 往所有列插入数据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 ])
1 2 3 4 5 6 7 8 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)
tableInsert 函数 tableInsert 函数会返回插入的行数。 对于分区表,如果使用 tableInsert 函数往表中插入数据,新数据必须是以表的形式表示。 2 `对于未分区表,如果使用tableInsert 函数往表中插入数据,新数据可以用元组的形式表示。```java
1 2 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)
1 2 3 4 5 6 7 8 9 10 3.2 增加列 可以通过以下三种方法为内存表增加列: SQL update 语句 UPDATE trades set logPrice1=log(price1), newQty1=double(qty1);
update! 函数 1 trades.update! (`logPrice1`newQty1, < [log (price1), double (qty1)]> );
`3. 赋值语句```java
1 trades[`logPrice1`newQty1] = <[log(price1), double(qty1)]>;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 3.3 更新已存在的列 可以通过以下三种方法为内存表更新列: UPDATE trades set qty1=qty1+10; update trades set qty1=qty1+10 where sym=`IBM; `2. update! 函数```java trades.update!(`qty1, <qty1+10>); trades.update!(`qty1, <qty1+10>, <sym=`IBM>); trades[`qty1] = <qty1+10>; trades[`qty1, <sym=`IBM>] = <qty1+10>;
3.4 删除行 可以通过以下三种方法为内存表删除行:
1 2 3 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函数查看表的结构:
1 2 3 4 5 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
1 2 partitionType->1 partitionColumnName->sym
1 2 3 4 5 6 7 8 9 10 11 3.8 删除内存表 可以通过以下两种方法删除内存表: undef函数 undef(`trades) `2. 把变量赋值为NULL```java trades=NULL
undef 函数会将命名空间删除,而把变量赋值为NULL仍然保留命名空间。 3.9 修改列的数据类型 通过replaceColumn! 函数可以修改列的数据类型。目前只有未分区的内存表才支持修改列的数据类型,分区内存表不支持该功能。以分区的内存表trades为例,将price1的数据类型修改为FLOAT(目前是DOUBLE):
1 2 NewPrice1=float (exec price1 from trades) replaceColumn!(trades,`price1,NewPrice1)
1 partitionColumnIndex->-1
price1 FLOAT 15
1 2 3 4 5 6 7 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)
本文标题: DolphinDB内存分区表的加载和操作
发布时间: 2025年01月26日 00:00
最后更新: 2025年12月30日 08:54
原始链接: https://haoxiang.eu.org/f3972efa/
版权声明: 本文著作权归作者所有,均采用CC BY-NC-SA 4.0 许可协议,转载请注明出处!