计算查询中的百分比

##3 查询中的基本计算

SELECT 语句支持使用基本的数学运算符,例如: +-/*()等等.

1
2
3
4
5
6
-- 两个field key相加
SELECT field_key1 + field_key2 AS "field_key_sum" FROM "measurement_name" WHERE time < now() - 15m
-- 两个field key相减
SELECT field_key1 - field_key2 AS "field_key_difference" FROM "measurement_name" WHERE time < now() - 15m
-- 分组计算并将它们连接起来
SELECT (field_key1 + field_key2) - (field_key3 + field_key4) AS "some_calculation" FROM "measurement_name" WHERE time < now() - 15m

计算查询中的百分比

使用基本的数学函数,将两个field字段的值相除并将结果乘以100,您就可以计算出两个field的百分比:

1
SELECT (field_key1 / field_key2) * 100 AS "calculated_percentage" FROM "measurement_name" WHERE time < now() - 15m

使用聚合函数计算百分比

如果在百分比计算中使用聚合函数,那么查询中所有的数据都会用到聚合函数。您不能将聚合数据和非聚合数据混合在一起。

所有聚合函数都需要一个GROUP BY time()子句,用于定义数据点分组和聚合的时间区间。

1
SELECT (sum(field_key1) / sum(field_key2)) * 100 AS "calculated_percentage" FROM "measurement_name" WHERE time < now() - 15m GROUP BY time(1m)

示例

示例数据下载

开始导入数据:

1
influx -ssl -username admin -password admin -host <网络地址> -port 3242 -import -path=path/to/apple_stand.txt -database=apple_stand

计算每个品种占总重量的百分比

以下查询计算在每个给定的时间点,每个苹果品种占总重量的百分比:

1
2
3
4
5
6
7
SELECT
("braeburn"/total_weight)*100,
("granny_smith"/total_weight)*100,
("golden_delicious"/total_weight)*100,
("fuji"/total_weight)*100,
("gala"/total_weight)*100
FROM "apple_stand"."autogen"."variety"

计算每个品种的聚合百分比

以下查询计算每一个小时,每个苹果品种的平均重量占平均总重量的百分比。

1
2
3
4
5
6
7
8
9
SELECT
(mean("braeburn")/mean(total_weight))*100,
(mean("granny_smith")/mean(total_weight))*100,
(mean("golden_delicious")/mean(total_weight))*100,
(mean("fuji")/mean(total_weight))*100,
(mean("gala")/mean(total_weight))*100
FROM "apple_stand"."autogen"."variety"
WHERE time >= '2018-06-18T12:00:00Z' AND time <= '2018-06-19T04:35:00Z'
GROUP BY time(1h)

关于以上查询,请注意:

  • 它使用聚合函数(mean())来提取所有数据
  • 它包含一个GROUP BY time()子句,将数据按一小时聚合
  • 它包含一个明确的时间区间,如果没有它,聚合函数是非常耗费资源的

通过HTTP API查询数据

单个查询

执行一个查询,需要发送一个GET请求到/query路径,设置URL的参数db为目标数据库,并设置URL的参数q为查询语句。您也可以发送POST请求,参数设置跟GET请求一样,作为URL的参数或者作为application/x-www-form-urlencoded类型的内容的一部分。

1
curl -G 'https://<网络地址>:3242/query?u=<账号名称>&p=<密码>&pretty=true' --data-urlencode "db=mydb" --data-urlencode "q=SELECT \"value\" FROM \"cpu_load_short\" WHERE \"region\"='us-west'"

注释:添加pretty=true到URL里可以使JSON的输出更美观,可读性更好,这在调试或者直接使用curl等工具查询时很有用,但是在实际生产中不建议使用,因为它会消耗不必要的网络带宽。

多个查询

在单个API调用中向InfluxDB®发送多个查询,只需使用分号将每个查询分隔开,例如:

1
curl -G 'https://<网络地址>:3242/query?u=<账号名称>&p=<密码>&pretty=true' --data-urlencode "db=mydb" --data-urlencode "q=SELECT \"value\" FROM \"cpu_load_short\" WHERE \"region\"='us-west';SELECT count(\"value\") FROM \"cpu_load_short\" WHERE \"region\"='us-west'"

查询数据时的其它选项

时间戳格式

InfluxDB®中的所有数据都是以UTC时间来存储和展示的。时间戳默认按RFC3339格式的UTC时间返回,并精确到纳秒级,例如2015-08-04T19:05:14.318570484Z。如果您想要返回Unix格式的时间戳,请在您的请求中设置参数epoch,其中,epoch的值是字符串类型,可以是[h, m, s, ms, u, ns]之一,分别代表小时、分钟、秒、毫秒、微秒和纳秒。例如,时间戳按Unix格式返回,精确到秒:

1
curl -G 'https://<网络地址>:3242/query?u=<账号名称>&p=<密码>' --data-urlencode "db=mydb" --data-urlencode "epoch=s" --data-urlencode "q=SELECT \"value\" FROM \"cpu_load_short\" WHERE \"region\"='us-west'"

分块

通过设置查询参数chunked=true,可以开启分块(Chunking),使结果流式批量地返回,而不是一次性全部返回。返回的结果可以按时间线或者按每10,000个数据点分块(哪个条件最先满足就以哪个条件来分块)。如果需要改变分块大小的最大值,请将查询参数chunk_size设为您需要的大小。例如,返回结果时,如果按每20,000个数据点进行分块,可以这样设置:

1
curl -G 'https://<网络地址>:3242/query?u=<账号名称>&p=<密码>' --data-urlencode "db=deluge" --data-urlencode "chunked=true" --data-urlencode "chunk_size=20000" --data-urlencode "q=SELECT * FROM liters"

通过HTTP API写入数据

通过HTTP API发送POST请求到/write路径是数据写入InfluxDB®的主要方式。假设已经成功创建好数据库mydb,现在我们来探索如何通过HTTP API将数据写入mydb

单点写入

其中,该数据点的measurement为cpu_load_short,有两个tag,tag key分别为host和region,对应的tag value分别为server01和us-west,field key是value,field value是0.64,timestamp是1434055562000000000:

1
curl -i -XPOST 'https://<网络地址>:3242/write?db=mydb&u=<账号名称>&p=<密码>' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'

多点写入

通过用换行符来分隔多个数据点,可以将它们同时发送到多个时间序列,这种批量发送的方式可以获得更高的性能。

下面的例子展示了将3个数据点写入数据库mydb。第一个点属于measurement为cpu_load_short、tag为host=server0的时间序列,timestamp是服务器本地的时间戳。第二个点属于measurement为cpu_load_short、tag为host=server02,region=us-west的时间序列,有明确的时间戳,timestamp为142256854370290025。第三个点跟第二个点的时间戳一样,但是该数据点属于measurement为cpu_load_short、tag为direction=in,host=server01,region=us-west的时间序列:

1
2
3
4
curl -i -XPOST 'https://<网络地址>:3242/write?db=mydb&u=<账号名称>&p=<密码>' --data-binary '
cpu_load_short,host=server02 value=0.67
cpu_load_short,host=server02,region=us-west value=0.55 1422568543702900257
cpu_load_short,direction=in,host=server01,region=us-west value=2.0 1422568543702900257'

文件写入

curl通过@filename的方式,将文件中的数据点写入TSDB For InfluxDB®。文件中的数据需要满足行协议的语法。

以下是格式正确的文件(cpu_data.txt)的一个示例:

1
2
3
cpu_load_short,host=server02 value=0.67
cpu_load_short,host=server02,region=us-west value=0.55 1422568543702900257
cpu_load_short,direction=in,host=server01,region=us-west value=2.0 1422568543702900257

开始写入:

1
curl -i -XPOST 'https://<网络地址>:3242/write?db=mydb&u=<账号名称>&p=<密码>' --data-binary @cpu_data.txt

注释:如果您的一个文件中有超过5000个数据点,那么可能需要将该文件拆分成多个文件,以便将数据批量写进TSDB For InfluxDB®,因为HTTP请求默认在5秒后超时,虽然写入请求超时后,TSDB For InfluxDB®依旧会尝试将这些数据点写入数据库,但是并不保障数据一定会写入成功。

Schemaless(无模式)的设计

TSDB For InfluxDB®是一个Schemaless的数据库。您可以在任意时间添加新的measurement、tags和fields。请注意,如果您尝试写入跟之前类型不同的数据(例如,field原来接收的是整型数据,现在却写了一个字符串进去),TSDB For InfluxDB®会拒绝这些数据。

关于REST的说明

InfluxDB®使用HTTP作为方便且广泛支持的数据传输协议。

现代web的API都基于REST的设计,因为它解决了一个共同的需求。随着终端数量的增加,对组织系统的需求变得越来越迫切。REST是一个工业界认定的用来组织大量终端的标准。这种一致性对于API的开发者和消费者都有好处:每个参与者都知道期望的是什么。

然而,REST只是一个惯例。TSDB For InfluxDB®是一个简单、易懂的系统,只提供三个API端点,使用HTTP作为InfluxQL的传输方法。所以TSDB For InfluxDB® API并不试图完全符合RESTful的标准。