TDengine踩坑随记(最后一次更新:2021-12-110:43)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
TDengine踩坑随记(最后⼀次更新:2021-12-110:43)
==背景==
在搭建⼯业物联⽹的数据平台,⽤来完成设备连接以及数据存储等,
以⽀持上层的应⽤及数据分析等。
⽬前使⽤的是mq→flink→influxdb的基本套路。
虽然说InfluxDB的性能和功能都⾮常的棒,特别是连续查询对性能的⽀撑,
不过由于influxdb使⽤的是社区版,存在单点故障的问题,总之不是长久直接。
于是打算尝试验证⼀下陶⽼师的TDEngine。
祝⾃⼰⼀切顺利。
==环境==
服务器节点数:3个(VMware虚拟机)
操作系统:Linux Centos8 64位
TDengine版本:2.0.4(2020年10⽉16⽇,使⽤版本换成了2.0.5.1)
JDK:1.8.0_77
JDBC客户端版本建议:
tdengine:2.0.10.0,jdbc版本:2.0.15
tdengine:2.0.15.0,jdbc版本:2.0.18
2021年12⽉1⽇补充:
最终确认的稳定版本:2.2.0.5
==下载==
TDengine-server-2.0.4.0-Linux-x64.rpm
TDengine-client-2.0.4.0-Linux-x64.tar.gz
TDengine-alert-2.0.4.0-Linux-x64.tar.gz
==测试代码==
所有程序的测试代码放到了git上,需要的⾃取。
==集群部署==
参考官⽹:
PS:中⽂⽂档是真的很爽,⽐看英⽂省⼼多了。
1、安装server
上传到服务器,并复制到各个节点,在各个节点执⾏rpm安装命令
命令:rpm -ivh TDengine-server-2.0.4.0-Linux-x64.rpm
【⼩插曲】
在另⼀个集群上安装新的版本(2.0.7.0)的时候,发现如论如何也⽆法使新增加的节点上线,
后来看了新版本的⽂档,上⾯提⽰:在增加新的节点时,先不要启动taosd,安装时,提⽰输⼊是否要加⼊⼀个已经存在的TDengine集群时,第⼀个物理节点直接回车创建新集群,后续物理节点则输⼊该集群任何⼀个在线的物理节点的FQDN:端⼝号(默认6030);
2、修改配置
配置⽂件路径:/etc/taos/taos.cfg
配置⽂件说明:
按照官⽹的提⽰,修改了⼏个配置:firstEp、secondEp、fqdn、serverPort、logDir、dataDir、replica。
根据官⽹的说明,我罗列了配置的中⽂,供参考。
没有写的是在这个版本的官⽹上没有找到的了。
########################################################
# #
# TDengine Configuration #
# Any questions, please email support@ #
# #
########################################################
# first fully qualified domain name (FQDN) for TDengine system
# taosd启动时,主动连接的集群中第⼀个dnode的end point, 默认值为localhost:6030。
firstEp vm1:6030
# second fully qualified domain name (FQDN) for TDengine system, for cluster only
# taosd启动时,如果first连接不上,尝试连接集群中第⼆个dnode的end point, 默认值为空。
secondEp vm2:6030
# local fully qualified domain name (FQDN)
# 数据节点的FQDN,缺省为操作系统配置的第⼀个hostname。
如果习惯IP地址访问,可设置为该节点的IP地址。
fqdn vm1
# first port number for the connection (12 continuous UDP/TCP port number are used)
# taosd启动后,对外服务的端⼝号,默认值为6030。
serverPort 6030
# log file's directory
# ⽇志⽂件⽬录,客户端和服务器的运⾏⽇志⽂件将写⼊该⽬录。
默认值:/var/log/taos。
logDir /home/radmin/data/tdengine/log
# data file's directory
# 数据⽂件⽬录,所有的数据⽂件都将写⼊该⽬录。
默认值:/var/lib/taos。
dataDir /home/radmin/data/tdengine/data
# the arbitrator's fully qualified domain name (FQDN) for TDengine system, for cluster only
# 系统中裁决器的end point, 缺省值为空。
# arbitrator arbitrator_hostname:6042
# number of threads per CPU core
# numOfThreadsPerCore 1.0
# number of management nodes in the system
# 系统中管理节点个数。
默认值:3。
# numOfMnodes 3
# enable/disable backuping vnode directory when removing dnode
# vnodeBak 1
# enable/disable load balancing
# 是否启动负载均衡。
0:否,1:是。
默认值:1。
# balance 1
# role for dnode. 0 - any, 1 - mnode, 2 - dnode
# dnode的可选⾓⾊。
0-any; 既可作为mnode,也可分配vnode;1-mgmt;只能作为mnode,不能分配vnode;2-dnode;不能作为mnode,只能分配vnode # role 0
# max timer control blocks
# maxTmrCtrl 512
# time interval of system monitor, seconds
# monitorInterval 30
# number of seconds allowed for a dnode to be offline, for cluster only
# dnode离线阈值,超过该时间将导致该dnode从集群中删除。
单位为秒,默认值:86400*10(即10天)。
# offlineThreshold 8640000
# RPC re-try timer, millisecond
# rpcTimer 300
# RPC maximum time for ack, seconds.
# rpcMaxTime 600
# time interval of dnode status reporting to mnode, seconds, for cluster only
# statusInterval 1
# time interval of heart beat from shell to dnode, seconds
# shellActivityTimer 3
# time of keeping table meta data in cache, seconds
# tableMetaKeepTimer 7200
# minimum sliding window time, milli-second
# minSlidingTime 10
# minimum time window, milli-second
# minIntervalTime 10
# maximum delay before launching a stream compution, milli-second
# maxStreamCompDelay 20000
# maximum delay before launching a stream computation for the first time, milli-second
# maxFirstStreamCompDelay 10000
# retry delay when a stream computation fails, milli-second
# retryStreamCompDelay 10
# the delayed time for launching a stream computation, from 0.1(default, 10% of whole computing time window) to 0.9 # streamCompDelayRatio 0.1
# max number of vgroups per db, 0 means configured automatically
# 每个数据库中能够使⽤的最⼤vnode个数。
# maxVgroupsPerDb 0
# max number of tables per vnode
# 每个vnode中能够创建的最⼤表个数。
默认值:1000000。
# maxTablesPerVnode 1000000
# step size of increasing table number in a vnode
# tableIncStepPerVnode 1000
# cache block size (Mbyte)
# cache 16
# number of cache blocks per vnode
# blocks 6
# number of days per DB file
# ⼀个数据⽂件存储数据的时间跨度,单位为天,默认值:10。
# days 10
# number of days to keep DB file
# 数据库中数据保留的天数,单位为天,默认值:3650。
# keep 3650
# minimum rows of records in file block
# ⽂件块中记录的最⼩条数,单位为条,默认值:100。
# minRows 100
# maximum rows of records in file block
# ⽂件块中记录的最⼤条数,单位为条,默认值:4096。
# maxRows 4096
# enable/disable compression
# ⽂件压缩标志位,0:关闭,1:⼀阶段压缩,2:两阶段压缩。
默认值:2。
# comp 2
# write ahead log (WAL) level, 0: no wal; 1: write wal, but no fysnc; 2: write wal, and call fsync
# WAL级别。
1:写wal, 但不执⾏fsync; 2:写wal, ⽽且执⾏fsync。
默认值:1。
# walLevel 1
# if walLevel is set to 2, the cycle of fsync being executed, if set to 0, fsync is called right away
# 当wal设置为2时,执⾏fsync的周期。
设置为0,表⽰每次写⼊,⽴即执⾏fsync。
单位为毫秒,默认值:3000。
# fsync 3000
# number of replications, for cluster only
# 副本个数,取值范围:1-3。
单位为个,默认值:1
replica 3
# mqtt hostname
# mqttHostName
# mqtt port
# mqttPort 1883
# mqtt topic
# mqttTopic /test
# the compressed rpc message, option:
# -1 (no compression)
# 0 (all message compressed),
# > 0 (rpc message body which larger than this value will be compressed)
# compressMsgSize -1
# max length of an SQL
# 单条SQL语句允许最长限制。
默认值:65380字节。
maxSQLLength 1048576
# the maximum number of records allowed for super table time sorting
# maxNumOfOrderedRes 100000
# system time zone
# 默认值:从系统中动态获取当前的时区设置
# timezone Asia/Shanghai (CST, +0800)
# system locale
# 默认值:系统中动态获取,如果⾃动获取失败,需要⽤户在配置⽂件设置或通过API设置
# locale en_US.UTF-8
# default system charset
# 默认值:系统中动态获取,如果⾃动获取失败,需要⽤户在配置⽂件设置或通过API设置
# charset UTF-8
# max number of connections allowed in dnode
# maxShellConns 5000
# max numerber of connections allowed in client
# maxConnections 5000
# stop writing logs when the disk size of the log folder is less than this value
# minimalLogDirGB 0.1
# stop writing temporary files when the disk size of the log folder is less than this value
# minimalTmpDirGB 0.1
# stop writing data when the disk size of the log folder is less than this value
# minimalDataDirGB 0.1
# enbale/disable http service
# http 1
# enable/disable muqq service
# mqtt 0
# enable/disable system monitor
# monitor 1
# enable/disable recording the SQL statements via restful interface
# httpEnableRecordSql 0
# number of threads used to process http requests
# httpMaxThreads 2
# maximum number of rows returned by the restful interface
# restfulRowLimit 10240
# The following parameter is used to limit the maximum number of lines in log files.
# max number of rows per log filters
# 单个⽇志⽂件允许的最⼤⾏数。
默认值:10,000,000⾏。
# numOfLogLines 10000000
# time of keeping log files, days
# ⽇志⽂件的最长保存时间。
⼤于0时,⽇志⽂件会被重命名为taosdlog.xxx,其中xxx为⽇志⽂件最后修改的时间戳,单位为秒。
默认值:0天。
# logKeepDays 0
# enable/disable async log
# asyncLog 1
# The following parameters are used for debug purpose only.
# debugFlag 8 bits mask: FILE-SCREEN-UNUSED-HeartBeat-DUMP-TRACE_WARN-ERROR
# 131: output warning and error, 135: output debug, warning and error, 143 : output trace, debug, warning and error to log.
# 199: output debug, warning and error to both screen and file
# 207: output trace, debug, warning and error to both screen and file
# debug flag for all log type, take effect when non-zero value
# debugFlag 0
# debug flag for meta management messages
# mDebugFlag 135
# debug flag for dnode messages
# dDebugFlag 135
# debug flag for sync module
# sDebugFlag 135
# debug flag for WAL
# wDebugFlag 135
# debug flag for SDB
# sdbDebugFlag 135
# debug flag for RPC
# rpcDebugFlag 131
# debug flag for TAOS TIMER
# tmrDebugFlag 131
# debug flag for TDengine client
# cDebugFlag 131
# debug flag for JNI
# jniDebugflag 131
# debug flag for ODBC
# odbcDebugflag 131
# debug flag for storage
# uDebugflag 131
# debug flag for http server
# httpDebugFlag 131
# debug flag for mqtt
# mqttDebugFlag 131
# debug flag for monitor
# monitorDebugFlag 131
# debug flag for query
# qDebugflag 131
# debug flag for vnode
# vDebugflag 131
# debug flag for http server
# tsdbDebugFlag 131
# enable/disable recording the SQL in taos client
# tscEnableRecordSql 0
# generate core file when service crash
# enableCoreFile 1
# maximum display width of binary and nchar fields in the shell. The parts exceeding this limit will be hidden
# maxBinaryDisplayWidth 30
PS:到此的感受:
总体感觉TDengine的安装⾮常容易,配置⽂件也简单易懂,到此体验良好。
==启动==
1、启动第1个节点
命令:systemctl start taosd
2、验证第1个节点是否启动成功
命令:taos
命令:show dnodes;
3、启动后续数据节点
先将后两个节点的服务启动起来。
在每个节点执⾏:systemctl start taosd
确认服务状态:systemctl status taosd
如下图,第2个节点的服务正常:
第3个节点的服务正常:
【⼩插曲】
在启动第2个节点的时候报错,
[root@vm2 ~]# systemctl status taosd
● taosd.service - TDengine server service
Loaded: loaded (/etc/systemd/system/taosd.service; enabled; vendor preset: disabled)
Active: failed (Result: start-limit) since Tue 2020-09-2920:38:20 UTC; 2s ago
Process: 5095 ExecStart=/usr/bin/taosd (code=exited, status=1/FAILURE)
Main PID: 5095 (code=exited, status=1/FAILURE)
Sep 2920:38:20 vm2 systemd[1]: taosd.service: main process exited, code=exited, status=1/FAILURE Sep 2920:38:20 vm2 systemd[1]: Unit taosd.service entered failed state.
Sep 2920:38:20 vm2 systemd[1]: taosd.service failed.
Sep 2920:38:20 vm2 systemd[1]: taosd.service holdoff time over, scheduling restart.
Sep 2920:38:20 vm2 systemd[1]: Stopped TDengine server service.
Sep 2920:38:20 vm2 systemd[1]: start request repeated too quickly for taosd.service
Sep 2920:38:20 vm2 systemd[1]: Failed to start TDengine server service.
Sep 2920:38:20 vm2 systemd[1]: Unit taosd.service entered failed state.
Sep 2920:38:20 vm2 systemd[1]: taosd.service failed.
【原因】
没有创建log和data的⽂件路径,在第2个和第3个节点上分别创建两个路径
mkdir -p /home/radmin/data/tdengine/log
mkdir -p /home/radmin/data/tdengine/data
4、添加节点
在第⼀个数据节点,使⽤CLI程序taos, 登录进TDengine系统, 执⾏命令:
CREATE DNODE "vm2:6030";
CREATE DNODE "vm3:6030";
查看新的节点是否加⼊进来。
【⼩插曲】
执⾏show dnodes;之后,发现vm2这个节点处于offline状态。
按照官⽹提⽰的⽅法:
查看⽇志中提⽰如下错误:
09/2920:59:55.0552740x7fcb0aae7700 DND ERROR status rsp is received, error:Cluster cfg inconsistent
09/2920:59:56.0604180x7fcb0aae7700 DND ERROR status rsp is received, error:Cluster cfg inconsistent
09/2920:59:57.0651570x7fcb0aae7700 DND ERROR status rsp is received, error:Cluster cfg inconsistent
【原因】
经过群⾥的咨询,有朋友建议排查⼀下时区是否⼀致,经排查第2个节点的时区确实与另外两个不⼀致。
修改了⼀下时区之后,从新启动第2个节点,发现状态恢复正常。
修改时区命令:
mv /etc/localtime /etc/localtime.bak
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/locaktime
【⼩插曲2】
解决了上⾯的⼩插曲,⾮常的开⼼,合上笔记本电脑回家。
回家之后,重新连接上服务器,查看状态,结果发现第2个节点的状态⼜变成offline了,真是开⼼不过3分钟啊。
【原因】
发现时间貌似不同步。
看来是时候加上NTP时间同步了。
按照以下步骤尝试了⼀下
1)停掉taos服务
2)配置ntp同步(参考我的另⼀篇博客:)
3)重启taos服务
重启之后,第2个节点的状态恢复为ready,开森。
为了以防万⼀,将系统放置了⼀整夜,第2天早上起来查看集群状态,依然是正常的,这下才算放⼼。
【感谢道友】
5、数据节点管理命令
添加数据节点:CREATE DNODE "fqdn:port";
删除数据节点:DROP DNODE "fqdn:port";
查看数据节点:SHOW DNODES;
PS:到此的感受
TDengine的集群部署也⾮常的简单,⽐传统的HBase,MongoDB之类的简单的多,感受不错。
唯⼀⽐较⼤的遗憾是,⽬前的社区版不⽀持多级存储,我们实际项⽬中磁盘是插满的,
如果要利⽤磁盘空间,就必须要加上lvm,但是lvm会影响读写速度,对已经存在的hdfs也有⼀些影响。
6、集群卸载
因为是⽤rpm的格式安装的,⽬前⽤的是yum remove来卸载,不清楚是否为最佳卸载⽅式。
systemctl stop taosd
rpm -qa | grep TD
yum remove TDengine-2.0.5.0-3.x86_64
2020年11⽉10⽇
卸载了2.0.5.0版本,重新安装了2.0.7.0版本,和上⾯的步骤⼀样
1、停⽌集群
2、卸载td
3、冲洗安装
【⼩插曲】
在这次重新安装的时候,遇到了下⾯的问题。
在Git上提了issue:
说是需要安装python环境,可是我⼜没有⽤到python,⽽且2.0.5.0的时候还没有这个问题。
所以,tdengine的版本更新是不是太快了,导致⼀些问题没能充分测试呢?
error: Failed dependencies:
/usr/bin/python is needed by tdengine-2.0.7.0-3.x86_64
解决过程:
按照提⽰,安装了3.8.6版本的python,并确认了python安装没有问题,尝试重新安装tdengine,仍然报了同样的错误,
后来和官⽅的⼈员确认过了,应该是官⽹放的release包有点问题,他们重新更新了⼀个包之后就可以了,
⽽且不需要安装python,不需要安装python,不需要安装python。
==TAOS SQL==
官⽹提供了完整的⽂档,官⽹地址:
我个⼈习惯了逐个尝试验证⼀遍,以加深印象,好记性不如烂笔头。
另外,可以通过官⽅提供的样例数据创建⼀些表供验证。
命令:taosdemo(注意,需要预留⼤约2.1GB的存储空间)
1、数据库管理
#创建库:
#COMP参数是指修改数据库⽂件压缩标志位,取值范围为[0, 2]. 0表⽰不压缩,1表⽰⼀阶段压缩,2表⽰两阶段压缩。
#REPLICA参数是指修改数据库副本数,取值范围[1, 3]。
在集群中使⽤,副本数必须⼩于dnode的数⽬。
#KEEP参数是指修改数据⽂件保存的天数,缺省值为3650,取值范围[days, 365000],必须⼤于或等于days参数值。
#QUORUM参数是指数据写⼊成功所需要的确认数。
取值范围[1, 3]。
对于异步复制,quorum设为1,具有master⾓⾊的虚拟节点⾃⼰确认即可。
对于同步复制,需要⾄少⼤于等于2。
原则上,Quorum >=1 并且 Quorum <= replica(副本数),这个参数#BLOCKS参数是每个VNODE (TSDB) 中有多少cache⼤⼩的内存块,因此⼀个VNODE的⽤的内存⼤⼩粗略为(cache * blocks)。
取值范围[3, 1000]。
#DAYS⼀个数据⽂件存储数据的时间跨度,单位为天,默认值:10。
create database mydb keep 365 days 10 blocks 4;
#创建库(如果不存在):
create database if not exists mydb keep 365 days 10 blocks 4;
#使⽤库:
use mydb;
#删除库:
drop database mydb;
#删除库(如果存在):
drop database if exists mydb;
#显⽰所有数据库:
show databases;
#修改数据库⽂件压缩标志位:
alter database mydb comp 2;
#修改数据库副本数:
alter database mydb replica 2;
#修改数据⽂件保存的天数:
alter database mydb keep 365;
#修改数据写⼊成功所需要的确认数:
alter database mydb quorum 2;
#修改每个VNODE (TSDB) 中有多少cache⼤⼩的内存块:
alter database mydb blocks 100;
2、表管理
#创建表(搞了个包含所有数据类型的表):
create table if not exists mytable(time timestamp, intfield int, bigintfield bigint, floatfield float, doublefield double, binaryfield binary(20), smallintfield smallint, tinyintfield tinyint, boolfield bool, ncharfiel
d nchar(50));
#删除数据表
drop table if exists mytable;
#显⽰当前数据库下的所有数据表信息
show tables;
#显⽰当前数据库下的所有数据表信息
#可在like中使⽤通配符进⾏名称的匹配。
通配符匹配:1)’%’ (百分号)匹配0到任意个字符;2)’_’下划线匹配⼀个字符。
show tables like "%my%";
#获取表的结构信息
describe mytable;
#表增加列
alter table mytable add column addfield int;
#表删除列
alter table mytable drop column addfield;
注意:表名⼀定不要⽤数字开头,官⽅⽂档明确提醒了。
3、超级表管理
#创建超级表
#创建STable, 与创建表的SQL语法相似,但需指定TAGS字段的名称和类型。
说明:
#1) TAGS 列的数据类型不能是timestamp类型;
#2) TAGS 列名不能与其他列名相同;
#3) TAGS 列名不能为预留关键字;
#4) TAGS 最多允许128个,可以0个,总长度不超过16k个字符
create table if not exists mysupertable (time timestamp, intfield int, bigintfield bigint, floatfield float, doublefield double, binaryfield binary(20), smallintfield smallint, tinyintfield tinyint, boolfield bool, nch
arfield nchar(50)) TAGS (product nchar(50), device nchar(100));
#删除超级表
drop table if exists mysupertable;
#显⽰当前数据库下的所有超级表信息
show stables like "%super%";
#获取超级表的结构信息
describe mysupertable;
#超级表增加列
alter table mysupertable add column addfield int;
#超级表删除列
alter table mysupertable drop column addfield;
#添加标签
alter table mysupertable add tag devicetype nchar(60);
#删除标签
alter table mysupertable drop tag devicetype;
#修改标签名
alter table mysupertable change tag product productKey;
#修改⼦表标签值
#说明:除了更新标签的值的操作是针对⼦表进⾏,其他所有的标签操作(添加标签、删除标签等)均只能作⽤于STable,不能对单个⼦表操作。
对STable添加标签以后,依托于该STable建⽴的所有表将⾃动增加了⼀个标签,所有新增标签的默认值alter table mysupertable set tag productkey="abc";
【⼩插曲】
执⾏了⼀个下⾯的创建超级表的语句(通过⾃⼰写的程序⽣成的),结果报错
SQL语句:create table if not exists AI_PICK_UDATA ( time timestamp, data double ) tags ( productKey binary(256),deviceName binary(256),pointId binary(256),name
binary(256),dataType binary(256),min binary(256),max binary(256),step binary(256),unit binary(256),description binary(256) );
提⽰错误:DB error: invalid SQL: invalid tag name
【问题原因】
创建表的语句中有tdengine的保留字段,如min,max。
但是官⽅⽂档上并没有对此进⾏相关介绍,吐槽⼀下⽂档。
4、数据插⼊
#插⼊⼀条数据
insert into mytable values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s");
#插⼊⼀条记录,数据对应到指定的列
insert into mytable(time, intfield, bigintfield, floatfield, doublefield, binaryfield, smallintfield, tinyintfield, boolfield, ncharfield) values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s");
#插⼊多条记录
insert into mytable values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s") (now, 2, 3, 4, 5, 6, 7, 8, 0, "t");
#按指定的列插⼊多条记录
insert into mytable(time, intfield, bigintfield, floatfield, doublefield, binaryfield, smallintfield, tinyintfield, boolfield, ncharfield) values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s") (now, 2, 3, 4, 5, 6, 7, 8, 0, "t"); #向多个表插⼊多条记录(本⼈没有验证此语句)
INSERT INTO tb1_name VALUES (field1_value1, ...)(field1_value2, ...) tb2_name VALUES (field1_value1, ...)(field1_value2, ...);
#同时向多个表按列插⼊多条记录(本⼈没有验证此语句)
INSERT INTO tb1_name (tb1_field1_name, ...) VALUES (field1_value1, ...) (field1_value2, ...) tb2_name (tb2_field1_name, ...) VALUES (field1_value1, ...) (field1_value2, ...);
【⼩插⼊】
插⼊多条记录的时候,语句中写的是两条数据,实际上只插⼊了⼀条
插⼊语句:
insert into mytable(time, intfield, bigintfield, floatfield, doublefield, binaryfield, smallintfield, tinyintfield, boolfield, ncharfield) values(now, 1, 2, 3, 4, 0, 6, 7, 1, "s") (now, 2, 3, 4, 5, 6, 7, 8, 0, "t");
【原因】
需要使⽤不同的时间戳,如果两条语句都使⽤now,时间戳⼀样,最终只能插⼊⼀条。
【感谢道友】
5、数据查询
查询语法:
SELECT select_expr [, select_expr ...]
FROM {tb_name_list}
[WHERE where_condition]
[INTERVAL (interval_val [, interval_offset])]
[FILL fill_val]
[SLIDING fill_val]
[GROUP BY col_list]
[ORDER BY col_list { DESC | ASC }]
[SLIMIT limit_val [, SOFFSET offset_val]]
[LIMIT limit_val [, OFFSET offset_val]]
[>> export_file]
==查询语句==
查询语法:
SELECT select_expr [, select_expr ...]
FROM {tb_name_list}
[WHERE where_condition]
[INTERVAL (interval_val [, interval_offset])]
[FILL fill_val]
[SLIDING fill_val]
[GROUP BY col_list]
[ORDER BY col_list { DESC | ASC }]
[SLIMIT limit_val [, SOFFSET offset_val]]
[LIMIT limit_val [, OFFSET offset_val]]
[>> export_file]
常⽤查询语句样例:
#查询表中的所有字段
select * from t_znsllj001;
#按照时间戳查询表中的所有字段
select * from t_znsllj001 where time > "2020-10-10 22:23:08.728";
#按照时间戳查询超级表中的所有字段
select * from st_znsllj where time > "2020-10-10 22:23:08.728";
#查询超级表中的指定字段
select time, forwardintegratedflow, product from st_znsllj;
#按照标签值查询超级表中的指定字段
select time, forwardintegratedflow, product from st_znsllj where product = "product1";
#查询结果按照时间倒序排序
select time, forwardintegratedflow, product from st_znsllj where product = "product1" order by time desc;
#结果集列名重命名
select time, forwardintegratedflow as ff, product from st_znsllj;
#查询超级表数据并附带表名(TBNAME:在超级表查询中可视为⼀个特殊的标签,代表查询涉及的⼦表名,不区分⼤⼩写)
select tbname, * from st_znsllj;
#查询超级表的表名及第⼀列
select tbname, _c0 from st_znsllj;
#获取当前所在的数据库
select database();
#获取客户端版本号
select client_version()
#获取服务器版本号
select server_version();
#服务器状态检测语句
select server_status()
#统计超级表下辖⼦表数量
select count(tbname) from st_znsllj;
※1:数字后⾯的时间单位可以是 b(纳秒)、u(微秒)、a(毫秒)、s(秒)、m(分)、h(⼩时)、d(天)、w(周)。
==⽤户管理==
#创建⽤户,并指定⽤户名和密码,密码需要⽤单引号引起来,单引号为英⽂半⾓
create user admin pass 'admin123';
#删除⽤户,限root⽤户使⽤
drop user admin;
#修改⽤户密码, 为避免被转换为⼩写,密码需要⽤单引号引⽤,单引号为英⽂半⾓
alter user admin pass 'admin1234';
#修改⽤户权限为:super/write/read。
为避免被转换为⼩写,密码需要⽤单引号引⽤,单引号为英⽂半⾓
#语法:ALTER USER <user_name> PRIVILEGE <super|write|read>;
alter user admin privilege read;
如果修改了root密码之后,进⼊命令⾏的命令就需要加上密码的参数了。
可以通过taos --usage查看命令⾏的参数格式:
如:修改了密码之后,可以通过以下命令来登录命令⾏
taos --user=root -p'RexelRoot!@#'
==Java连接==
官⽹地址:
1、maven配置
<dependency>
<groupId>com.taosdata.jdbc</groupId>
<artifactId>taos-jdbcdriver</artifactId>
<version>2.0.4</version>
</dependency>
2、JDBC连接样例
【TdUtils.java】
单例⼯具类,实现创建连接等通⽤⽅法。
package com.rexel.tdengine.utils;
import com.taosdata.jdbc.TSDBDriver;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* @ClassName TdUtils
* @Description TDengine共通类
* @Author: chunhui.qu
* @Date: 2020/9/30
*/
public class TdUtils {
private Connection connection = null;
/**
* 构造函数
*/
private TdUtils() {
// do nothing
}
/**
* 单例模式
*/
private static class SingletonInstance {
private static final TdUtils INSTANCE = new TdUtils();
}
/**
* 获取对象句柄
*/
public static TdUtils getInstance() {
return SingletonInstance.INSTANCE;
}
public Connection getConnection() {
if (connection != null) {
return connection;
}
try {
Class.forName("com.taosdata.jdbc.TSDBDriver");
String jdbcUrl = "jdbc:TAOS://rexel-ids001:6030/qch_test?user=root&password=taosdata";
Properties connProps = new Properties();
connProps.setProperty(TSDBDriver.PROPERTY_KEY_USER, "root");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_PASSWORD, "taosdata");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_CONFIG_DIR, "C:\\TDengine\\cfg");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "Asia/Shanghai");
connection = DriverManager.getConnection(jdbcUrl, connProps);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return connection;
}
}
【CreateDatabase.java】
创建数据的样例程序。
package com.rexel.tdengine.api;
import com.rexel.tdengine.utils.TdUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
/**
* @ClassName CreateDatabase
* @Description CreateDatabase
* @Author: chunhui.qu
* @Date: 2020/9/30
*/
public class CreateDatabase {
public static void main(String[] args) throws SQLException {
TdUtils tdUtils = TdUtils.getInstance();
Connection conn = tdUtils.getConnection();
if (conn == null) {
return;
}
System.out.println("get connection");
Statement stmt = conn.createStatement();
if (stmt == null) {
return;
}
stmt.executeUpdate("create database if not exists javatestdb");
System.out.println("create database");
stmt.executeUpdate("use javatestdb");
System.out.println("use database");
stmt.executeUpdate("create table if not exists javatesttable (ts timestamp, temperature int, humidity float)"); System.out.println("create table");
}
}
【⼩插曲1】
写完了测试代码,在执⾏的时候报错:
Exception in thread "main" ng.UnsatisfiedLinkError: no taos in java.library.path
at ng.ClassLoader.loadLibrary(ClassLoader.java:1867)
at ng.Runtime.loadLibrary0(Runtime.java:870)
at ng.System.loadLibrary(System.java:1122)
at com.taosdata.jdbc.TSDBJNIConnector.<clinit>(TSDBJNIConnector.java:25)
at com.taosdata.jdbc.TSDBDriver.connect(TSDBDriver.java:133)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:208)
at com.rexel.tdengine.utils.TdUtils.getConnection(TdUtils.java:54)
at com.rexel.tdengine.api.CreateDatabase.main(CreateDatabase.java:17)
Disconnected from the target VM, address: '127.0.0.1:54954', transport: 'socket'
【解决过程】
重新看了⼀下官⽅⽂档,怀疑是没有安装Window客户端,尝试安装客户端程序。
安装⽂件:TDengine-client-2.0.4.0-Windows-x64.exe
重新执⾏程序之后,报了另⼀个错误:
java.sql.SQLException: TDengine Error: Invalid timestamp
at com.taosdata.jdbc.TSDBJNIConnector.connect(TSDBJNIConnector.java:100)
at com.taosdata.jdbc.TSDBConnection.connect(TSDBConnection.java:64)
at com.taosdata.jdbc.TSDBConnection.<init>(TSDBConnection.java:56)
at com.taosdata.jdbc.TSDBDriver.connect(TSDBDriver.java:135)
at java.sql.DriverManager.getConnection(DriverManager.java:664)
at java.sql.DriverManager.getConnection(DriverManager.java:208)
at com.rexel.tdengine.utils.TdUtils.getConnection(TdUtils.java:54)
at com.rexel.tdengine.api.CreateDatabase.main(CreateDatabase.java:17)
⽹友说可能是因为客户端的时间与服务器时间相差⽐较多的原因,
于是调整了服务器的时间。
命令如下,调整之后,重启了⼀下服务器
修改系统时间:date --set "09/30/20 14:15"
系统时间向硬件同步:clock --show
重新运⾏程序,正确执⾏。
感谢⽹友的帮助。
【感谢道友】
【⼩插曲2】
本来运⾏的好好的,debug也都没有问题,但是下午去酒店再debug测试,就提⽰“Unable to establish connection”按照官⽹的FAQ提⽰,⼀顿检查,没有发现什么问题,⾮常迷惑。
后来想到由于服务器⽤的是阿⾥云ECS,需要配置⽹络安全组的IP地址⽩名单,
我配置的时候只配置了TCP,没有配置UDP,配置上了UCP的权限之后,debug就恢复正常了。
3、插⼊数据样例
我这⾥写了⼀个JSON字符串转换为SQL,并持续插⼊的样例。
package com.rexel.tdengine.api;
import com.alibaba.fastjson.JSONObject;
import com.rexel.tdengine.utils.TdUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
/**
* @ClassName CreateDatabase
* @Description CreateDatabase
* @Author: chunhui.qu
* @Date: 2020/10/12
*/
public class InsertJson {
public static void main(String[] args) throws SQLException {
TdUtils tdUtils = TdUtils.getInstance();
Connection conn = tdUtils.getConnection();
if (conn == null) {
return;
}
System.out.println("get connection");
Statement stmt = conn.createStatement();
if (stmt == null) {
return;
}
List<String> aiList = new ArrayList<String>(){{
add("AI_PICK_UDATA");
add("AI_PROD_NPER");
add("AI_PROD_NPICK");
add("AI_PRODUCT_EFF");
add("AI_PRODUCT_QUANTITY");
add("AI_PRODUCT_TIME_MIN");
add("AI_PROD_NPRODING");
}};
List<String> diList = new ArrayList<String>(){{
add("DI_BELOWCLOSTS");
add("DI_BELOWOPNSTS");
add("DI_CANDY_OUTBEELINEA");
add("DI_CANDY_OUTBEELINEB");
add("DI_CANDY_OUTBEELINEC");
add("DI_CHUCKCLOSTS");
add("DI_CHUCKOPNSTS");
add("DI_COVERCLOSTS");
add("DI_COVEROPNSTS");
add("DI_CTNCLO_BSTART");
add("DI_CTNOPN_BSTART");
add("DI_DENSO_BAUTOST");
add("DI_DENSO_BERROR");
add("DI_DENSO_BMOTORONST");
add("DI_DENSO_BREADY");
add("DI_DENSO_BRUNNING");
add("DI_EPSON_BERROR");
add("DI_EPSON_BESTOPON");
add("DI_EPSON_BMOTORONST");
add("DI_EPSON_BREADY");
add("DI_EPSON_BRUNNING");
add("DI_LEFTPUSHCLOSTS");
add("DI_LEFTPUSHOPNSTS");
add("DI_PRINT_BRUNNING");
add("DI_RIGHTCLOSTS");
add("DI_RIGHTOPNSTS");
add("DI_RIGHTPUSHCLOSTS");
add("DI_RIGHTPUSHLOPN");
add("DI_RLCLOSTS");
add("DI_RLOPNSTS");
add("DI_ROBOT1_BLINKSTS");
add("DI_ROBOT1_BSTART");
add("DI_ROBOT2_BLINKSTS");
add("DI_ROBOT2TOSTOR");
add("DI_ROBOT2TOWAI");
add("DI_SYS_BRUNNING");
add("DI_TOPCLOSTS");
add("DI_TOPOPNSTS");
add("DI_UPDOWNCLOSTS");
add("DI_UPDOWNOPNSTS");
add("DI_BBELTSENSOROVT");
add("DI_BCTNCLOCOOPNOVT");
add("DI_BCTNCLORCLOOVT");
add("DI_BCTNCLOROPNOVT");
add("DI_BCTNCLOTCLOOVT");
add("DI_BCTNCLOTOPNOVT");
add("DI_BCTNOVT");
add("DI_BELOWVALCLOOVT");
add("DI_BELOWVALOPNOVT");
add("DI_BROBOT2VALCLOVT");
add("DI_BROBOT2VALOPOVT");
add("DI_BRTSUCKEROVT");
add("DI_BVALCOVERCLOOVT");
add("DI_CHUCJVALCLOOVT");
add("DI_CHUCJVALOPOVT");
add("DI_CHUCKVALOPNOVT");
add("DI_DENSOBERROR");
add("DI_EPSONBERROR");
add("DI_INSENCTNALARM");
add("DI_LEFTNEWVALCLOVT");
add("DI_RLNEWOPVALOPOVT");
add("DI_RLNEWVALCLOOVT");
add("DI_UPDOWNNVALCLOVT");
add("DI_UPDOWNNVALOPOVT");
}};
int count = 0;
while(true) {
Random intRandom = new Random();
JSONObject demoJson = new JSONObject();
demoJson.put("table", "device_data_up");
demoJson.put("time", System.currentTimeMillis());
JSONObject tagJson = new JSONObject();
tagJson.put("productKey", "a1B6t6ZG6oR");
tagJson.put("deviceName", "QCHTestDevice1");
demoJson.put("tags", tagJson);
JSONObject dataJson = new JSONObject();
aiList.forEach(field -> dataJson.put(field, intRandom.nextInt(10000))); diList.forEach(field -> dataJson.put(field, intRandom.nextInt(2)));
demoJson.put("datas", dataJson);
String sql = jsonToSql(demoJson);
stmt.executeUpdate(sql);
count ++;
System.out.println("executeUpdate. count=" + count + ", sql=" + sql);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static String jsonToSql(JSONObject jsonObject) {
String sql = "insert into {table} ({fields}) values ({values});";
sql = sql.replace("{table}", getTable(jsonObject));
sql = sql.replace("{fields}", getFields(jsonObject));
return sql.replace("{values}", getValues(jsonObject));
}
private static String getTable(JSONObject jsonObject) {
return "t_" + jsonObject.getString("table");
}
private static String getTime(JSONObject jsonObject) {
if (jsonObject.containsKey("time")) {
return timeLongToStr(jsonObject.getLong("time"));
} else {
return timeLongToStr(System.currentTimeMillis());
}。