创建数据库和表

创建数据库

使用 database 函数来创建新的数据库或获取已有数据库的句柄。

database函数的语法:

database(directory, [partitionType], [partitionScheme], [locations], [engine='OLAP'], [atomic='TRANS'])

若配置项 enableChunkGranularityConfig = true:

database(directory, [partitionType], [partitionScheme], [locations], [engine='OLAP'], [atomic='TRANS'], [chunkGranularity='TABLE'])

directory 是保存数据库的目录的路径。如果需要创建分布式文件系统中的数据库,directory应该以“dfs://”开头。

partitionType 有六种类型:顺序分区(SEQ),范围分区(RANGE),哈希分区(HASH),数值分区(VALUE),列表分区(LIST)和组合分区(COMPO)。

partitionScheme 描述了分区是如何创建的。它通常是一个向量,在序列域是一个整型标量。分区方案的说明决定了分区类型。partitionScheme支持以下数据类型:CHAR, SHORT, INT, DATE, MONTH, TIME, MINUTE, SECOND, DATETIME和SYMBOL。

分区类型

分区符号

分区方案

顺序分区

SEQ

整型标量。表示分区的数量。

范围分区

RANGE

向量。向量的任意两个相邻元素定义分区的范围。

哈希分区

HASH

元组。第一个元素是分区列的数据类型,第二个元素是分区的数量。

值分区

VALUE

向量。向量的每个元素定义了一个分区。

列表分区

LIST

向量。向量的每个元素定义了一个分区。

组合分区

COMPO

向量。向量的每个元素是一个数据库句柄。

locations 是元组,指定分区的位置。元组中元素的数量应该与partitionType和partitionScheme共同决定的分区数量相同。若要在多个节点上保存分区时,可以使用分布式文件系统或使用locations参数指定每个分区在哪些节点。如果没有指定locations参数,所有分区属于当前节点。我们不能指定分层域的分区。

engine 设置数据库存储引擎。取值为:'OLAP'或'TSDB',默认值为'OLAP'。关于 OLAP 和 TSDB 存储引擎的介绍,请参见 数据模型

注意:TSDB 引擎只支持创建分布式数据库。

atomic 表示是否允许并发写入同一分区。可选值为'TRANS' 和 'CHUNK',默认值为 'TRANS'。

  • 设置为'TRANS',不允许并发写入同一个分区。此时能够保证写入事务的原子性,即一个事务并发写入多个分区时,若存在分区被其他事务锁定而出现写入冲突,则该事务的写入全部失败。

  • 设置为'CHUNK',允许并发写入同一个分区。若一个事务并发写入多个分区时,某分区被其它事务锁定,系统不会直接放弃本次写入,而是会完成未冲突分区的数据写入,同时不断尝试继续写入冲突的分区,直到10秒后仍无法写入,才放弃写入。此配置因不能完全保证事务的原子性,可能出现部分分区写入成功而部分分区写入失败的情况,同时由于采用了重试机制,不能保证写入的效率。

chunkGranularity 是一个字符串,用于指定分区的粒度。可选值为:

  • ‘TABLE’:表级分区,设置后支持同时写入同一分区的不同表。

  • ‘DATABASE’:数据库级分区,设置后只支持同时写入不同分区。

注意:该参数只有在配置 enableChunkGranularityConfig = true 时启用。

数据库创建后,不可修改分区类型。分区方案一般亦不可修改,仅有的例外为使用 addValuePartitionsaddRangePartitions 函数增加值分区或范围分区。

创建维度表

维度表是分布式数据库中没有分区的表,一般用于存储不频繁更新的小数据集。我们可以使用 createTable 函数来创建维度表。

$ db=database("dfs://db1",VALUE,1 2 3)
$ timestamp = [09:34:07,09:36:42,09:36:51,09:36:59,09:32:47,09:35:26,09:34:16,09:34:26,09:38:12]
$ sym = `C`MS`MS`MS`IBM`IBM`C`C`C
$ price= 49.6 29.46 29.52 30.02 174.97 175.23 50.76 50.32 51.29
$ qty = 2200 1900 2100 3200 6800 5400 1300 2500 8800
$ t = table(timestamp, sym, qty, price)

$ dt=db.createTable(t,`dt).append!(t)
$ select * from dt;

timestamp

sym

qty

price

09:34:07

C

2200

49.6

09:36:42

MS

1900

29.46

09:36:51

MS

2100

29.52

09:36:59

MS

3200

30.02

09:32:47

IBM

6800

174.97

09:35:26

IBM

5400

175.23

09:34:16

C

1300

50.76

09:34:26

C

2500

50.32

09:38:12

C

8800

51.29

创建分区表

使用 createPartitionedTable 函数来创建分区表。

createPartitionedTable 函数的语法:createPartitionedTable(dbHandle, table, tableName, [partitionColumns], [compressMethods], [sortColumns], [keepDuplicates=ALL])

创建分区表时,我们需要提供一个高阶表,系统会在数据库中创建一个与高阶表结构相同的分区表。createPartitionedTable 函数的第二个参数用于指定模板表。除了顺序分区以外,创建其他分区类型的分区表时必须指定partitionColumns,系统会根据partitionColumns来划分分区。若存储引擎为TSDB时,需指定sortColumns.

范围分区

$ n=1000000
$ ID=rand(10, n)
$ x=rand(1.0, n)
$ t=table(ID, x)
$ db=database("dfs://rangedb", RANGE,  0 5 10)
$ pt=db.createPartitionedTable(t, `pt, `ID)
$ pt.append!(t)
$ select count(x) from pt;

count_x

1000000

在上面的例子中,数据库"dfs://rangedb"有两个根据范围划定的分区:[0,5)和[5,10)。内存表 t 根据 ID 列的值,分别存入这两个分区中。

数据库的操作需要数据库的句柄。要获取数据库的句柄,使用 database 函数并且只指定数据库路径即可。例如,要获取数据库"dfs://rangedb"的句柄:

$ db=database("dfs://rangedb")

值分区

$ n=1000000
$ month=take(2000.01M..2016.12M, n)
$ x=rand(1.0, n)
$ t=table(month, x)
$ db=database("dfs://valuedb", VALUE, 2000.01M..2016.12M)
$ pt = db.createPartitionedTable(t, `pt, `month)
$ pt.append!(t)
$ select count(x) from pt;

count_x

1000000

上例创建的数据库 dfs://valuedb 一共有17*12=204个分区,每个分区对应2000年1月到2016年12月之间的每个月。

哈希分区

$ n=1000000
$ ID=rand(10, n)
$ x=rand(1.0, n)
$ t=table(ID, x)
$ db=database("dfs://hashdb", HASH,  [INT, 2])
$ pt = db.createPartitionedTable(t, `pt, `ID)
$ pt.append!(t)
$ select count(x) from pt;

count_x

1000000

数据库 dfs://hashdb 根据ID列划分为两个分区。

列表分区

$ n=1000000
$ ticker = rand(`MSFT`GOOG`FB`ORCL`IBM,n);
$ x=rand(1.0, n)
$ t=table(ticker, x)
$ db=database("dfs://listdb", LIST, [`IBM`ORCL`MSFT, `GOOG`FB])
$ pt = db.createPartitionedTable(t, `pt, `ticker)
$ pt.append!(t)
$ select count(x) from pt;

count_x

1000000

数据库 dfs://listdb 包含两个分区,第一个分区包含3只股票,第二个分区包含2只股票。

组合分区

组合分区类型的数据库和表可以按照2-3个分区列来划分分区。

$ n=1000000
$ ID=rand(100, n)
$ dates=2017.08.07..2017.08.11
$ date=rand(dates, n)
$ x=rand(10.0, n)
$ t=table(ID, date, x)

$ dbDate = database(, VALUE, 2017.08.07..2017.08.11)
$ dbID = database(, RANGE, 0 50 100)
$ db = database("dfs://compodb", COMPO, [dbDate, dbID])
$ pt = db.createPartitionedTable(t, `pt, `date`ID)
$ pt.append!(t)
$ select count(x) from pt;

count_x

1000000

上面的例子中,数据库 dfs://compodb 包含两层分区,第一层按照日期分区,每天一个分区,第二层按照ID的范围划分成两个分区,因此数据库一共有5*2个分区。

指定TSDB引擎时,必须指定sortColumns.

$ dbName = "dfs://tsdb_value_int"
$ if(existsDatabase(dbName)){
$     dropDatabase(dbName)
$ }
$ db = database(directory=dbName, partitionType=VALUE, partitionScheme=1..10,engine="TSDB")
$ n = 10000
$ t = table(n:n, [`int,`long,`short,`float,`double,`string,`char,`bool,`timestamp], [INT, LONG, SHORT,FLOAT, DOUBLE, STRING, CHAR, BOOL, TIMESTAMP])
$ pt1 = db.createPartitionedTable(table=t, tableName=`pt1, partitionColumns=`int,sortColumns=`short`int,keepDuplicates=ALL)
$ t[`int] = rand(100,n)
$ t[`long] = rand(100000l,n)
$ t[`short] = rand(10h,n)
$ t[`float] = rand(100.0f,n)
$ t[`double] = rand(100.0,n)
$ t[`string] = rand("A"+string(1..1000),n)
$ t[`char] = rand(100,n)
$ t[`bool] = rand([true,false],n)
$ tem = 2012.06.13T13:30:10.000
$ ts = array(timestamp,0,n)
$ for(i in 1..n){
$     tem=temporalAdd(tem, 1, `s)
$     ts.append!(tem)
$ }
$ t[`timestamp] = ts
$ pt1.append!(t)