首页 文章 精选 留言 我的

精选列表

搜索[时序预测],共10000篇文章
优秀的个人博客,低调大师

时序数据库丨DolphinDB内存表详解

内存表是DolphinDB数据库的重要组成部分。内存表不仅可以直接用于存储数据,实现高速数据读写,而且可以缓存计算引擎的中间结果,加速计算过程。本教程主要介绍DolphinDB内存表的分类、使用场景以及各种内存表在数据操作以及表结构(schema)操作上的异同。 1. 内存表类别 根据不同的使用场景以及功能特点,DolphinDB内存表可以分为以下四种: 常规内存表 键值内存表 流数据表 MVCC内存表 1.1 常规内存表 常规内存表是DolphinDB中最基础的表结构,支持增删改查等操作。SQL查询返回的结果通常存储在常规内存表中,等待进一步处理。 创建 使用table函数可创建常规内存表。table函数有两种用法:第一种用法是根据指定的schema(字段类型和字段名称)以及表容量(capacity)和初始行数(size)来生成;第二种用法是通过已有数据(矩阵,表,数组和元组)来生成一个表。 使用第一种方法的好处是可以预先为表分配内存。当表中的记录数超过容量时,系统会自动扩充表的容量。扩充时系统首先会分配更大的内存空间(增加20%到100%不等),然后复制旧表到新的表,最后释放原来的内存。对于规模较大的表,扩容的成本会比较高。因此,如果我们可以事先预计表的行数,建议创建内存表时预先分配一个合理的容量。如果表的初始行数为0,系统会生成空表。如果初始行数不为0,系统会生成一个指定行数的表,表中各列的值都为默认值。例如: //创建一个空的常规内存表 t=table(100:0,`sym`id`val,[SYMBOL,INT,INT]) //创建一个10行的常规内存表 t=table(100:10,`sym`id`val,[SYMBOL,INT,INT]) select*fromt symidval -------- 00 00 00 00 00 00 00 00 00 00 table函数也允许通过已有的数据来创建一个常规内存表。下例是通过多个数组来创建。 sym=`A`B`C`D`E id=54321 val=5264254871 t=table(sym,id,val) 应用 常规内存表是DolphinDB中应用最频繁的数据结构之一,仅次于数组。SQL语句的查询结果,分布式查询的中间结果都存储在常规内存表中。当系统内存不足时,该表并不会自动将数据溢出到磁盘,而是Out Of Memory异常。因此我们进行各种查询和计算时,要注意中间结果和最终结果的size。当某些中间结果不再需要时,请及时释放。关于常规内存表增删改查的各种用法,可以参考另一份教程内存分区表加载和操作。 1.2 键值内存表 键值内存表是DolphinDB中支持主键的内存表。通过指定表中的一个或多个字段作为主键,可以唯一确定表中的记录。键值内存表支持增删改查等操作,但是主键值不允许更新。键值内存表通过哈希表来记录每一个键值对应的行号,因此对于基于键值的查找和更新具有非常高的效率。 创建 使用keyedTable函数可创建键值内存表。该函数与table函数非常类似,唯一不同之处是增加了一个参数指明键值列的名称。 //创建空的键值内存表,主键由sym和id字段组成 t=keyedTable(`sym`id,1:0,`sym`id`val,[SYMBOL,INT,INT]) //使用向量创建键值内存表,主键由sym和id字段组成 sym=`A`B`C`D`E id=54321 val=5264254871 t=keyedTable(`sym`id,sym,id,val) 注意:指定容量和初始大小创建键值内存表时,初始大小必须为0。 我们也可以通过keyedTable函数将常规内存表转换为键值内存表。例如: sym=`A`B`C`D`E id=54321 val=5264254871 tmp=table(sym,id,val) t=keyedTable(`sym`id,tmp) 数据插入和更新的特点 往键值内存表中添加新纪录时,系统会自动检查新记录的主键值。如果新记录中的主键值不存在于表中,那么往表中添加新的记录;如果新记录的主键值与已有记录的主键值重复时,会更新表中该主键值对应的记录。请看下面的例子。 首先,往空的键值内存表中插入新记录,新记录中的主键值为AAPL, IBM和GOOG。 t=keyedTable(`sym,1:0,`sym`datetime`price`qty,[SYMBOL,DATETIME,DOUBLE,DOUBLE]); insertintotvalues(`APPL`IBM`GOOG,2018.06.08T12:30:002018.06.08T12:30:002018.06.08T12:30:00,50.345.658.0,520048007800); t; symdatetimepriceqty -------------------------------- APPL2018.06.08T12:30:0050.35200 IBM2018.06.08T12:30:0045.64800 GOOG2018.06.08T12:30:00587800 再次往表中插入一批主键值为AAPL, IBM和GOOG的新记录。 insertintotvalues(`APPL`IBM`GOOG,2018.06.08T12:30:012018.06.08T12:30:012018.06.08T12:30:01,65.845.278.6,580087004600); t; symdatetimepriceqty -------------------------------- APPL2018.06.08T12:30:0165.85800 IBM2018.06.08T12:30:0145.28700 GOOG2018.06.08T12:30:0178.64600 可以看到,表中记录条数没有增加,但是主键对应的记录已经更新。 继续往表中插入一批新记录,新记录本身包含了重复的主键值MSFT。 可以看到,表中有且仅有一条主键值为MSFT的记录。 应用场景 (1)键值表对单行的更新和查询有非常高的效率,是数据缓存的理想选择。与redis相比,DolphinDB中的键值内存表兼容SQL的所有操作,可以完成根据键值更新和查询以外的更为复杂的计算。 (2)作为时间序列聚合引擎的输出表,实时更新输出表的结果。具体请参考教程使用DolphinDB计算K线。 1.3 流数据表 流数据表顾名思义是为流数据设计的内存表,是流数据发布和订阅的媒介。流数据表具有天然的流表对偶性(Stream Table Duality),发布一条消息等价于往流数据表中插入一条记录,订阅消息等价于将流数据表中新到达的数据推向客户端应用。对流数据的查询和计算都可以通过SQL语句来完成。 创建 使用streamTable函数可创建流数据表。streamTable的用法和table函数完全相同。 //创建空的流数据表 t=streamTable(1:0,`sym`id`val,[SYMBOL,INT,INT]) //使用向量创建流数据表 sym=`A`B`C`D`E id=54321 val=5264254871 t=streamTable(sym,id,val) 我们也可以使用streamTable函数将常规内存表转换为流数据表。例如: sym=`A`B`C`D`E id=54321 val=5264254871 tmp=table(sym,id,val) t=streamTable(tmp) 流数据表也支持创建单个键值列,可以通过函数keyedStreamTable来创建。但与keyed table的设计目的不同,keyedstreamtable的目的是为了在高可用场景(多个发布端同时写入)下,避免重复消息。通常key就是消息的ID。 数据操作特点 由于流数据具有一旦生成就不会发生变化的特点,因此流数据表不支持更新和删除记录,只支持查询和添加记录。流数据通常具有连续性,而内存是有限的。为解决这个矛盾,流数据表引入了持久化机制,在内存中保留最新的一部分数据,更旧的数据持久化在磁盘上。当用户订阅旧的数据时,直接从磁盘上读取。启用持久化,使用函数enableTableShareAndPersistence,具体参考流数据教程。 应用场景 共享的流数据表在流计算中发布数据。订阅端通过subscribeTable函数来订阅和消费流数据。 1.4 MVCC内存表 MVCC内存表存储了多个版本的数据,当多个用户同时对MVCC内存表进行读写操作时,互不阻塞。MVCC内存表的数据隔离采用了快照隔离模型,用户读取到的是在他读之前就已经存在的数据,即使这些数据在读取的过程中被修改或删除了,也对之前正在读的用户没有影响。这种多版本的方式能够支持用户对内存表的并发访问。需要说明的是,当前的MVCC内存表实现比较简单,更新和删除数据时锁定整个表,并使用copy-on-write技术复制一份数据,因此对数据删除和更新操作的效率不高。在后续的版本中,我们将实现行级的MVCC内存表。 创建 使用mvccTable函数创建MVCC内存表。例如: //创建空的流数据表 t=mvccTable(1:0,`sym`id`val,[SYMBOL,INT,INT]) //使用向量创建流数据表 sym=`A`B`C`D`E id=54321 val=5264254871 t=mvccTable(sym,id,val) 我们可以将MVCC内存表的数据持久化到磁盘,只需创建时指定持久化的目录和表名即可。例如, t=mvccTable(1:0,`sym`id`val,[SYMBOL,INT,INT],"/home/user1/DolphinDB/mvcc","test") 系统重启后,我们可以通过loadMvccTable函数将磁盘中的数据加载到内存中。 loadMvccTable("/home/user1/DolphinDB/mvcc","test") 我们也可以使用mvccTable函数将常规内存表转换为MVCC内存表。 sym=`A`B`C`D`E id=54321 val=5264254871 tmp=table(sym,id,val) t=mvccTable(tmp) 应用场景 当前的MVCC内存表适用于读多写少,并有持久化需要的场景。譬如动态的配置系统,需要持久化配置项,配置项的改动不频繁,已新增和查询操作为主,非常适合MVCC表。 2. 共享内存表 DolphinDB中的内存表默认只在创建内存表的会话中使用,不支持多用户多会话的并发操作,当然对别的会话也不可见。如果希望创建的内存表能被别的用户使用,保证多用户并发操作的安全,必须共享内存表。4种类型的内存表均可共享。在DolphinDB中,我们使用share命令将内存表共享。 t=table(1..10asid,rand(100,10)asval) sharetasst //或者share(t,`st) 上面的代码将表t共享为表st。 使用undef函数可以删除共享表。 undef(`st,SHARED) 2.1 保证对所有会话可见 内存表仅在当前会话可见,在其他会话中不可见。共享之后,其他会话可以通过访问共享变量来访问内存表。例如,我们在当前会话中把表t共享为表st。 t=table(1..10asid,rand(100,10)asval) sharetasst 我们可以在其他会话中访问变量st。例如,往共享表st插入一条数据。 insertintostvalues(11,200) select*fromst idval ----- 11 253 313 440 561 692 736 833 946 1026 11200 切换到原来的会话,我们可以发现,表t中也增加了一条记录。 select*fromt idval ----- 11 253 313 440 561 692 736 833 946 1026 11200 2.2 保证线程安全 在多线程的情况下,内存表中的数据很容易被破坏。共享则提供了一种保护机制,能够保证数据安全,但同时也会影响系统的性能。 常规内存表、流数据表和MVCC内存表都支持多版本模型,允许多读一写。具体说,读写互不阻塞,写的时候可以读,读的时候可以写。读数据时不上锁,允许多个线程同时读取数据,读数据时采用快照隔离(snapshot isolation)。写数据时必须加锁,同时只允许一个线程修改内存表。写操作包括添加,删除或更新。添加记录一律在内存表的末尾追加,无论内存使用还是CPU使用均非常高效。常规内存表和MVCC内存表支持更新和删除,且采用了copy-on-write技术,也就是先复制一份数据(构成一个新的版本),然后在新版本上进行删除和修改。由此可见删除和更新操作无论内存和CPU消耗都比较高。当删除和更新操作很频繁,读操作又比较耗时(不能快速释放旧的版本),容易导致OOM异常。 键值内存表写入时需维护内部索引,读取时也需要根据索引获取数据。因此键值内存表共享采用了不同的方法,无论读写都必须加锁。写线程和读线程,多个写线程之间,多个读线程之间都是互斥的。对键值内存表尽量避免耗时的查询或计算,否则会使其它线程长时间处于等待状态。 3. 分区内存表 当内存表数据量较大时,我们可以对内存表进行分区。分区后一个大表有多个子表(tablet)构成,大表不使用全局锁,锁由每个子表独立管理,这样可以大大增加读写并发能力。DolphinDB支持对内存表进行值分区、范围分区、哈希分区和列表分区,不支持组合分区。在DolphinDB中,我们使用函数createPartitionedTable创建内存分区表。 创建分区常规内存表 t=table(1:0,`id`val,[INT,INT]) db=database("",RANGE,0101201301) pt=db.createPartitionedTable(t,`pt,`id) 创建分区键值内存表 kt=keyedTable(1:0,`id`val,[INT,INT]) db=database("",RANGE,0101201301) pkt=db.createPartitionedTable(t,`pkt,`id) 创建分区流数据表 创建分区流数据表时,需要传入多个流数据表作为模板,每个流数据表对应一个分区。写入数据时,直接往这些流表中写入;而查询数据时,需要查询分区表。 st1=streamTable(1:0,`id`val,[INT,INT]) st2=streamTable(1:0,`id`val,[INT,INT]) st3=streamTable(1:0,`id`val,[INT,INT]) db=database("",RANGE,1101201301)pst=db.createPartitionedTable([st1,st2,st3],`pst,`id) st1.append!(table(1..100asid,rand(100,100)asval)) st2.append!(table(101..200asid,rand(100,100)asval)) st3.append!(table(201..300asid,rand(100,100)asval)) select*frompst 创建分区MVCC内存表 与创建分区流数据表一样,创建分区MVCC内存表,需要传入多个MVCC内存表作为模板。每个表对应一个分区。写入数据时,直接往这些表中写入;而查询数据时,需要查询分区表。 mt1=mvccTable(1:0,`id`val,[INT,INT]) mt2=mvccTable(1:0,`id`val,[INT,INT]) mt3=mvccTable(1:0,`id`val,[INT,INT]) db=database("",RANGE,1101201301) pmt=db.createPartitionedTable([mt1,mt2,mt3],`pst,`id) mt1.append!(table(1..100asid,rand(100,100)asval)) mt2.append!(table(101..200asid,rand(100,100)asval)) mt3.append!(table(201..300asid,rand(100,100)asval)) select*frompmt 由于分区内存表不使用全局锁,创建以后不能再动态增删子表。 3.1 增加查询的并发性 分区表增加查询的并发性有三层含义:(1)键值表在查询时也需要加锁,分区表由子表独立管理锁,相当于把锁的粒度变细了,因此可以增加读的并发性;(2)批量计算时分区表可以并行处理每个子表;(3)如果SQL查询的过滤指定了分区字段,那么可以缩小分区范围,避免全表扫描。 以键值内存表为例,我们对比在分区和不分区的情况下,并发查询的性能。首先,创建模拟数据集,一共包含500万行数据。 n=5000000 id=shuffle(1..n) qty=rand(1000,n) price=rand(1000.0,n) kt=keyedTable(`id,id,qty,price) sharektasskt id_range=cutPoints(1..n,20) db=database("",RANGE,id_range) pkt=db.createPartitionedTable(kt,`pkt,`id).append!(kt) sharepktasspkt 我们在另外一台服务器上模拟10个客户端同时查询键值内存表。每个客户端查询10万次,每次查询一条数据,统计每个客户端查询10万次的总耗时。 defqueryKeyedTable(tableName,id){ for(iinid){ select*fromobjByName(tableName)whereid=i } } conn=xdb("192.168.1.135",18102,"admin","123456") n=5000000 jobid1=array(STRING,0) for(iin1..10){ rid=rand(1..n,100000) s=conn(submitJob,"evalQueryUnPartitionTimer"+string(i),"",evalTimer,queryKeyedTable{`skt,rid}) jobid1.append!(s) } time1=array(DOUBLE,0) for(jinjobid1){ time1.append!(conn(getJobReturn,j,true)) } jobid2=array(STRING,0) for(iin1..10){ rid=rand(1..n,100000) s=conn(submitJob,"evalQueryPartitionTimer"+string(i),"",evalTimer,queryKeyedTable{`spkt,rid}) jobid2.append!(s) } time2=array(DOUBLE,0) for(jinjobid2){ time2.append!(conn(getJobReturn,j,true)) } time1是10个客户端查询未分区键值内存表的耗时,time2是10个客户端查询分区键值内存表的耗时,单位是毫秒。 time1 [6719.266848,7160.349678,7271.465094,7346.452625,7371.821485,7363.87979,7357.024299,7332.747157,7298.920972,7255.876976] time2 [2382.154581,2456.586709,2560.380315,2577.602019,2599.724927,2611.944367,2590.131679,2587.706832,2564.305815,2498.027042] 可以看到,每个客户端查询分区键值内存表的耗时要低于查询未分区内存表的耗时。 查询未分区的内存表,可以保证快照隔离。但查询一个分区内存表,不再保证快照隔离。如前面所说分区内存表的读写不使用全局锁,一个线程在查询时,可能另一个线程正在写入而且涉及多个子表,从而可能读到一部分写入的数据。 3.2 增加写入的并发性 以分区的常规内存表为例,我们可以同时往不同的分区写入数据。 t=table(1:0,`id`val,[INT,INT]) db=database("",RANGE,1101201301) pt=db.createPartitionedTable(t,`pt,`id) defwriteData(mutablet,id,batchSize,n){ for(iin1..n){ idv=take(id,batchSize) valv=rand(100,batchSize) tmp=table(idv,valv) t.append!(tmp) } } job1=submitJob("write1","",writeData,pt,1..100,1000,1000) job2=submitJob("write2","",writeData,pt,101..200,1000,1000) job3=submitJob("write3","",writeData,pt,201..300,1000,1000) 上面的代码中,同时有3个线程对pt的3个不同的分区进行写入。需要注意的是,我们要避免同时对相同分区进行写入。例如,下面的代码可能会导致系统崩溃。 job1=submitJob("write1","",writeData,pt,1..300,1000,1000) job2=submitJob("write2","",writeData,pt,1..300,1000,1000) 上面的代码定义了两个写入线程,并且写入的分区相同,这样会破坏内存。为了保证每个分区数据的安全性和一致性,我们可将分区内存表共享。这样即可定义多个线程同时对相同分区分入。 shareptasspt job1=submitJob("write1","",writeData,spt,1..300,1000,1000) job2=submitJob("write2","",writeData,spt,1..300,1000,1000) 4. 数据操作比较 4.1 增删改查 下表总结了4种类型内存表在共享/分区的情况下支持的增删改查操作。 说明: 常规内存表、键值内存表、MVCC内存表都支持增删改查操作,流数据表仅支持增加数据和查询,不支持删除和更新操作。 对于键值内存表,如果查询的过滤条件中包含主键,查询的性能会得到明显提升。 对于分区内存表,如果查询的过滤条件中包含分区列,系统能够缩小要扫描的分区范围,从而提升查询的性能。 4.2 并发性 在没有写入的情况下,所有内存表都允许多个线程同时查询。在有写入的情况下,4种内存表的并发性有所差异。下表总结了4种内存表在共享/分区的情况下支持的并发读写情况。 说明: 共享表允许并发读写。 对于没有共享的分区表,不允许多线程对相同分区同时写入的。 4.3 持久化 常规内存表和键值内存表不支持数据持久化。一旦节点重启,内存中的数据将全部丢失。 只有空的流数据表才支持数据持久化。要对流数据表进行持久化,首先要配置流数据持久化的目录persistenceDir,再使用enableTableShareAndPersistence使用将流数据表共享,并持久化到磁盘上。例如,将流数据表t共享并持久化到磁盘上。 t=streamTable(1:0,`id`val,[INT,INT]) enableTableShareAndPersistence(t,`st) 流数据表启用了持久化后,内存中仍然会保留流数据表中部分最新的记录。默认情况下,内存会保留最新的10万条记录。我们也可以根据需要调整这个值。 流数据表持久化可以设定采用异步/同步、压缩/不压缩的方式。通常情况下,异步模式能够实现更高的吞吐量。 系统重启后,再次执行enableTableShareAndPersistence函数,会将磁盘中的所有数据加载到内存。 MVCC内存表支持持久化。在创建MVCC内存表时,我们可以指定持久化的路径。例如,创建持久化的MVCC内存表。 t=mvccTable(1:0,`id`val,[INT,INT],"/home/user/DolphinDB/mvccTable") t.append!(table(1..10asid,rand(100,10)asval)) 系统重启后,我们可以使用loadMvccTable函数将磁盘中的数据加载到内存中。例如: t=loadMvccTable("/home/user/DolphinDB/mvccTable","t") 5. 表结构操作比较 内存表的结构操作包括新增列、删除列、修改列(内容和数据类型)以及调整列的顺序。下表总结了4种类型内存表在共享/分区的情况下支持的结构操作。 说明: 分区表以及MVCC内存表不能通过addColumn函数新增列。 分区表可以通过update语句来新增列,但是流数据表不允许修改,因此流数据表不能通过update语句来新增列。 6. 小结 DolphinDB支持4种类型内存表,还引入了共享和分区的概念,基本能够满足内存计算和流计算的各种需求。

优秀的个人博客,低调大师

干货丨时序数据库分区教程(一)

1.为什么对数据进行分区? 对数据库进行分区可以极大的降低系统响应延迟同时提高数据吞吐量。具体来说,分区有以下几个好处: 分区使得大型表更易于管理。对数据子集的维护操作也更加高效,因为这些操作只针对需要的数据而不是整个表。一个好的分区策略将通过只读取满足查询所需的相关数据来减少要扫描的数据量。当所有的数据都在同一个分区上,对数据库的查询,计算,以及其它操作都会被限制在磁盘访问IO这个瓶颈上。 分区使得系统可以充分利用所有资源。一个良好的分区方案搭配并行计算,分布式计算就可以充分利用所有节点来完成通常要在一个节点上完成的任务。 当一个任务可以拆分成几个分散的子任务,每个子任务访问不同的分区,就可以达到提升效率的目的。 分区增加了系统的可用性。由于分区的副本通常是存放在不同的物理节点的。所以一旦某个分区不可用,系统依然可以调用其它副本分区来保证作业的正常运转。 2.分区方式 DolphinDBdatabase支持多种分区方式: 范围分区(RANGE),哈希分区(HASH),值分区(VALUE),列表分区(LIST),复合分区(COMPO)。 范围分区每个区间创建一个分区,是最常用的也是推荐的一种分区方式。可以把数值在一个区间内的所有记录放置到一个分区。 哈希分区利用哈希函数对分区列操作,方便建立指定数量的分区。 值分区每个值创建一个分区,例如股票交易日期,股票交易月。 列表分区是根据用户枚举的列表来进行分区,比值分区更加灵活。 复合分区适用于数据量特别大而且查询经常涉及两个或以上的分区列。每个分区选择都可以采用区间,值或列表分区。例如按股票交易日期进行值分区, 同时按股票代码进行范围分区。 我们可以使用database函数创建数据库。 语法:database(directory, [partitionType], [partitionScheme], [locations]) 参数 directory:数据库保存的目录。DolphinDB有三种类型的数据库,分别是内存数据库、磁盘上的数据库和分布式文件系统上的数据库。创建内存数据库,directory为空;创建本地数据库,directory应该是本地文件系统目录;创建分布式文件系统上的数据库,directory应该以“dfs://”开头。本教程以创建Windows本地数据库为例。 partitionType:分区方式,有5种方式: 范围分区(RANGE),哈希分区(HASH),值分区(VALUE),列表分区(LIST),复合分区(COMPO)。 partitionScheme:分区方案。各种分区方式对应的分区方案如下: locations:指定每个分区所在的节点位置。如果是分布式文件系统的数据库或者复合分区(COMPO)类型的数据库,不能使用locations参数。 2.1 范围分区 范围分区是由分区向量决定。分区向量表示区间,包含起始值,不包含结尾值。 在下面的例子中,数据库db有两个分区:[0,5)和[5,10)。使用函数append!在数据库db中保存表t为分区表pt,并使用ID作为分区列。 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); pt=loadTable(db,`pt) select count(x) from pt 2.2 哈希分区 哈希分区对分区列使用哈希函数以产生分区。哈希分区是产生指定数量的分区的一个简便方法。但是要注意,哈希分区不能保证分区的大小一致,尤其当分区列的值的分布存在偏态的时候。此外,若要查找分区列上一个连续区域的数据时,哈希分区的效率比区域分区或值分区要低。 在下面的例子中,数据库db有两个分区。使用函数append!在数据库db中保存表t为分区表pt,并使用ID作为分区列。 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); pt=loadTable(db,`pt) select count(x) from pt 2.3 值分区 值分区用一个值代表一个分区。下面的例子定义了204个分区。每个分区表示2000年1月到2016年12月之间的一个月。 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) pt=loadTable(db,`pt) select count(x) from pt 2.4 列表分区 在列表(LIST)分区中,我们用一个包含多个元素的列表代表一个分区。下面的例子有两个分区,第一个分区包含3个股票代码,第二个分区包含2个股票代码。 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) pt=loadTable(db,`pt) select count(x) from pt 2.5 组合分区 组合(COMPO)分区可以定义2或3个分区列。每列可以独立采用范围(RANGE),值(VALUE)或列表(LIST)分区。组合分区的多个列在逻辑上是并列的,不存在从属关系或优先级关系。 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) pt=loadTable(db,`pt) select count(x) from pt 上面的例子创建了5个值分区。 在20170807这个分区,有2个范围分区。 DolphinDB分区数据库教程(二)将会介绍DolphinDB分区原则以及特殊的分区方案。

优秀的个人博客,低调大师

Apache IoTDB 0.9.1 发布,时序数据管理引擎

Apache IoTDB 0.9.1 发布了。IoTDB 是针对时间序列数据收集、存储与分析一体化的数据管理引擎。它具有体量轻、性能高、易使用的特点,完美对接 Hadoop 与 Spark 生态,适用于工业物联网应用中海量时间序列数据高速写入和复杂分析查询的需求。 此版本修复了一些 bug: 修复 SeqTsFileRecoverTest 和 UnseqTsFileRecoverTest 中的 NullPointerException 修复了“刷新+错误的聚合查询”导致查询失败的错误 修复批量编写时不正确的统计信息 修复了由错误的页面跳过逻辑引起的 groupBy-without-value-filter 查询错误 当 axisOrigin-startTimeOfWindow 是间隔的整数倍时,修复groupBy 查询错误 修复 ActiveTimeSeriesCounter 中的 NullPointerException 修复 TsFileSketchTool 中的错误数据类型错误 修复 CompressionRatio 中死锁的错误 修复 Development-Contributing.md 中的链接错误,并添加 Development-Document.md 修复 CSV 导出工具中的错误 修复某些文件中的 Apache Rat 标头格式错误 详情见发布公告。

优秀的个人博客,低调大师

Apache IoTDB 0.8.2 发布,时序数据管理引擎

Apache IoTDB 0.8.2 发布了。IoTDB 是针对时间序列数据收集、存储与分析一体化的数据管理引擎。它具有体量轻、性能高、易使用的特点,完美对接 Hadoop 与 Spark 生态,适用于工业物联网应用中海量时间序列数据高速写入和复杂分析查询的需求。 此版本修复了 2 个 bug: IOTDB-264 - 在写入 WAL 之前缺少检查数据类型 IOTDB-317 - 修复“刷新+错误聚合”导致的 v0.8.x 中的查询失败 更新说明

优秀的个人博客,低调大师

Apache IoTDB 0.9.0 发布,时序数据管理引擎

Apache IoTDB 0.9.0 发布了。IoTDB 是针对时间序列数据收集、存储与分析一体化的数据管理引擎。它具有体量轻、性能高、易使用的特点,完美对接 Hadoop 与 Spark 生态,适用于工业物联网应用中海量时间序列数据高速写入和复杂分析查询的需求。 此版本更新内容包括: IOTDB-143 压缩数据文件 IOTDB-151 支持时间序列路径中的数字格式 IOTDB-158 新增metrics web 服务 IOTDB-173 在会话中添加批处理写接口 IoTDB-174添加用于查询设备或时间序列号的接口 IOTDB-187 可选择存储在本地文件系统或 HDFS 中 IOTDB-188 删除存储组 IOTDB-193 插入时自动创建 schema IOTDB-198 添加同步模块(在 IoTDB 实例之间同步 TsFiles) IOTDB-199 添加日志可视化工具 IOTDB-203 添加“按设备分组”功能 IOTDB-205 支持存储组级别的 Time To Live(TTL) IOTDB-208 TsFile 中添加 Bloom 过滤器 IOTDB-223 添加TsFile草图工具 IoTDB-226 Hive-TsFile 连接器 IOTDB-239 新增显示设备的界面 IOTDB-241 在会话中添加查询和非查询接口 IOTDB-249 create_timeseries sql 中允许小写 IOTDB-253 支持时间表达式 IOTDB-259 路径级别查询 IOTDB-282 新增“show version” IOTDB-294 从 0.8.0 在线升级到0.9.0 Spark-iotdb-connector 在 service-rpc 下生成 cpp、go 和 python thrift 文件 通过 jconsole 显示缓存命中率 支持插入 time < 0 的数据 会话中添加删除时间序列的接口 新增工具打印 tsfileResources 支持水印功能 增加微米和纳米时间戳精度 详情查看: http://mail-archives.apache.org/mod_mbox/www-announce/201912.mbox/%3cCAP2xrr4CvdmS8UCiMsuTM=aMVU616214EtrCDToJNF+RzO22_Q@mail.gmail.com%3e

优秀的个人博客,低调大师

TimescaleDB 2.29.1 发布,基于 PostgreSQL 的时序数据库

TimescaleDB 2.29.0 现已发布,此版本包含自 2.29.0 版本以来的性能改进和错误修复,以及安全漏洞修复(#10360、#10379、#10386)。可以查看安全公告,了解有关漏洞和受影响平台的更多信息。官方建议用户尽快升级。 错误修复 #10327当 hypertable 参数为NULL时,add_dimension()中的断言失败 #10339修复从压缩的连续聚合源中删除数据时发生的崩溃问题 #10340在compact_chunk()中验证max_batches验证 #10352在attach_chunk()期间重置块上的继承列和约束标志 #10360修复因格式错误的压缩数据导致解压缩器崩溃的问题 #10369修复有关压缩超表支持MERGE的错误信息中的拼写错误 #10379使用有序扫描读取超表最大时间值 #10386为内部 chunk functions 添加缺失的权限检查 更新说明:https://github.com/timescale/timescaledb/releases/tag/2.29.1

优秀的个人博客,低调大师

TimescaleDB 2.29.0 发布,基于 PostgreSQL 的时序数据库

TimescaleDB 2.29.0 现已发布,此版本较 2.28.3 版本进行了性能改进和错误修复。官方建议用户尽快升级。 发布亮点 对 DML 操作进行 Chunk exclusion可显著提升超表上UPDATE和DELETE语句的性能。通过仅对正在修改的特定块而非整个超表获取独占锁,此增强功能消除了大规模的锁争用,并确保高并发工作负载平稳运行,避免不必要的性能下降。 智能逐行解压缩使查询规划器能够在操作优先考虑快速初始响应时(例如带有LIMIT子句的查询),逐行解压缩数据,而不是批量解压缩。这显著降低了内存开销和查询延迟,从而确保在仅需从压缩超表中检索少量记录时,能够实现闪电般的性能。 重要提示: TimescaleDB 2.29.0 已移除对 PostgreSQL 15 的支持。此版本支持 PostgreSQL 16、17 和 18。如果你仍在运行 PostgreSQL 15,建议先升级 PostgreSQL,然后再升级到 TimescaleDB 2.29.0。 向后不兼容的变更 #10041移除对 PostgreSQL 15 的支持 更多详情可查看:https://github.com/timescale/timescaledb/releases/tag/2.29.0

优秀的个人博客,低调大师

TimescaleDB 2.28.3 发布,基于 PostgreSQL 的时序数据库

TimescaleDB 2.28.3 现已发布,此版本较 2.28.2 版本进行了性能改进和错误修复。官方建议用户尽快升级。 错误修复 #10082在列式查询执行管道中评估返回NULL的函数时出现错误结果 #10178修复排序键表达式中包含负常量时排序转换使用不当的问题 #10179允许在启用列存储的超表上启用和禁用触发器 #10182修复列存储排序下推以检查不同的查询排序键排序规则 #10209修复在列式查询执行管道中,stddev(float4)和stddev(float8)与avg()结合使用时可能产生的错误结果`and`时可能出现的错误结果 #10212修复启用超表压缩时出现的竞态条件 #10230压缩DML的批量过滤应遵循排序规则 #10254直接删除操作无法处理带有NULL值的数组谓词,删除的行数超过了预期(#10129) #10257尽可能重用现有dimension_sliceID #10265在尝试重命名之前截断约束名称 更新说明:https://github.com/timescale/timescaledb/releases/tag/2.28.3

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册