连续查询
介绍
连续查询(Continuous Queries下文统一简称CQ)是InfluxQL对实时数据自动周期运行的查询,然后把查询结果写入到指定的measurement中。
语法
基本语法
语法描述
cq_query
cq_query
需要一个函数,一个INTO
子句和一个GROUP BY time()
子句:
注意:请注意,在
WHERE
子句中,cq_query
不需要时间范围。 InfluxDB在执行CQ时自动生成cq_query
的时间范围。cq_query
的WHERE
子句中的任何用户指定的时间范围将被系统忽略。
运行时间点以及覆盖的时间范围
CQ对实时数据进行操作。他们使用本地服务器的时间戳,GROUP BY time()
间隔和InfluxDB的预设时间边界来确定何时执行以及查询中涵盖的时间范围。
CQs以与cq_query
的GROUP BY time()
间隔相同的间隔执行,并且它们在InfluxDB的预设时间边界开始时运行。如果GROUP BY time()
间隔为1小时,则CQ每小时开始执行一次。
当CQ执行时,它对于now()
和now()
减去GROUP BY time()
间隔的时间范围运行单个查询。 如果GROUP BY time()
间隔为1小时,当前时间为17:00,查询的时间范围为16:00至16:59999999999。
基本语法的例子
以下例子使用数据库transportation
中的示例数据。measurementbus_data
数据存储有关公共汽车乘客数量和投诉数量的15分钟数据:
例一:自动采样数据
使用简单的CQ自动从单个字段中下采样数据,并将结果写入同一数据库中的另一个measurement。
cq_basic
从bus_data
中计算乘客的平均小时数,并将结果存储在数据库transportation
中的average_passengers
中。
cq_basic
以一小时的间隔执行,与GROUP BY time()
间隔相同的间隔。 每个小时,cq_basic
运行一个单一的查询,覆盖了now()
和now()
减去GROUP BY time()
间隔之间的时间范围,即now()
和now()
之前的一个小时之间的时间范围。
下面是2016年8月28日上午的日志输出:
在8点时,
cq_basic
执行时间范围为time => '7:00' AND time <'08:00'
的查询。cq_basic
向average_passengers
写入一个点:在9点时,
cq_basic
执行时间范围为time => '8:00' AND time <'09:00'
的查询。cq_basic
向average_passengers
写入一个点:
结果:
例二:自动采样数据到另一个保留策略里
从默认的的保留策略里面采样数据到完全指定的目标measurement中:
cq_basic_rp
从bus_data
中计算乘客的平均小时数,并将结果存储在数据库tansportation
的RP为three_weeks
的measurementaverage_passengers
中。
cq_basic_rp
以一小时的间隔执行,与GROUP BY time()
间隔相同的间隔。每个小时,cq_basic_rp
运行一个单一的查询,覆盖了now()
和now()
减去GROUP BY time()
间隔之间的时间段,即now()
和now()
之前的一个小时之间的时间范围。
下面是2016年8月28日上午的日志输出:
在8:00
cq_basic_rp
执行时间范围为time >='7:00' AND time <'8:00'
的查询。cq_basic_rp
向RP为three_weeks
的measurementaverage_passengers
写入一个点:在9:00
cq_basic_rp
执行时间范围为time >='8:00' AND time <'9:00'
的查询。cq_basic_rp
向RP为three_weeks
的measurementaverage_passengers
写入一个点:
结果:
cq_basic_rp
使用CQ和保留策略自动降低样本数据,并将这些采样数据保留在不同的时间长度上。
例三:使用逆向引用自动采样数据
使用带有通配符(*
)和INTO
查询的反向引用语法的函数可自动对数据库中所有measurement和数值字段中的数据进行采样。
cq_basic_br
计算数据库transportation
中每个measurement的30分钟平均乘客和投诉。它将结果存储在数据库downsampled_transportation
中。
cq_basic_br
以30分钟的间隔执行,与GROUP BY time()
间隔相同的间隔。每30分钟一次,cq_basic_br
运行一个查询,覆盖了now()
和now()
减去GROUP BY time()
间隔之间的时间段,即now()
到now()
之前的30分钟之间的时间范围。
下面是2016年8月28日上午的日志输出:
在7:30,
cq_basic_br
执行查询,时间间隔time >='7:00' AND time <'7:30'
。cq_basic_br
向downsampled_transportation
数据库中的measurement为bus_data
写入两个点:8点时,
cq_basic_br
执行时间范围为time >='7:30' AND time <'8:00'
的查询。cq_basic_br
向downsampled_transportation
数据库中measurement为bus_data
写入两个点:[…]
9点时,
cq_basic_br
执行时间范围为time >='8:30' AND time <'9:00'
的查询。cq_basic_br
向downsampled_transportation
数据库中measurement为bus_data
写入两个点:
结果为:
例四:自动采样数据并配置CQ的时间边界
使用GROUP BY time()
子句的偏移间隔来改变CQ的默认执行时间和呈现的时间边界:
cq_basic_offset
从bus_data
中计算乘客的平均小时数,并将结果存储在average_passengers
中。
cq_basic_offset
以一小时的间隔执行,与GROUP BY time()
间隔相同的间隔。15分钟偏移间隔迫使CQ在默认执行时间后15分钟执行; cq_basic_offset
在8:15而不是8:00执行。
每个小时,cq_basic_offset
运行一个单一的查询,覆盖了now()
和now()
减去GROUP BY time()
间隔之间的时间段,即now()
和now()
之前的一个小时之间的时间范围。 15分钟偏移间隔在CQ的WHERE
子句中向前移动生成的预设时间边界; cq_basic_offset
在7:15和8:14.999999999而不是7:00和7:59.999999999之间进行查询。
下面是2016年8月28日上午的日志输出:
在8:15
cq_basic_offset
执行时间范围time> ='7:15'AND time <'8:15'
的查询。cq_basic_offset
向average_passengers
写入一个点:在9:15
cq_basic_offset
执行时间范围time> ='8:15'AND time <'9:15'
的查询。cq_basic_offset
向average_passengers
写入一个点:
结果为:
请注意,时间戳为7:15和8:15而不是7:00和8:00。
基本语法的常见问题
问题一:无数据处理时间间隔
如果没有数据落在该时间范围内,则CQ不会在时间间隔内写入任何结果。请注意,基本语法不支持使用fill()
更改不含数据的间隔报告的值。如果基本语法CQs包括了fill()
,则会忽略fill()
。一个解决办法是使用下面的高级语法。
问题二:重新采样以前的时间间隔
基本的CQ运行一个查询,覆盖了now()
和now()
减去GROUP BY time()
间隔之间的时间段。有关如何配置查询的时间范围,请参阅高级语法。
问题三:旧数据的回填结果
CQ对实时数据进行操作,即具有相对于now()
发生的时间戳的数据。使用基本的INTO
查询来回填具有较旧时间戳的数据的结果。
问题四:CQ结果中缺少tag
默认情况下,所有INTO
查询将源measurement中的任何tag转换为目标measurement中的field。
在CQ中包含GROUP BY *
,以保留目的measurement中的tag。
高级语法
高级语法描述
cq_query
同上面基本语法里面的cq_query
。
运行时间点以及覆盖的时间范围
CQs对实时数据进行操作。使用高级语法,CQ使用本地服务器的时间戳以及RESAMPLE
子句中的信息和InfluxDB的预设时间边界来确定执行时间和查询中涵盖的时间范围。
CQs以与RESAMPLE
子句中的EVERY
间隔相同的间隔执行,并且它们在InfluxDB的预设时间边界开始时运行。如果EVERY
间隔是两个小时,InfluxDB将在每两小时的开始执行CQ。
当CQ执行时,它运行一个单一的查询,在now()
和now()
减去RESAMPLE
子句中的FOR
间隔之间的时间范围。如果FOR
间隔为两个小时,当前时间为17:00,查询的时间间隔为15:00至16:59999999999。
EVERY
间隔和FOR
间隔都接受时间字符串。RESAMPLE
子句适用于同时配置EVERY
和FOR
,或者是其中之一。如果没有提供EVERY
间隔或FOR
间隔,则CQ默认为相关为基本语法。
高级语法例子
示例数据如下:
例一:配置执行间隔
在RESAMPLE
中使用EVERY
来指明CQ的执行间隔。
cq_advanced_every
从bus_data
中计算passengers
的一小时平均值,并将结果存储在数据库transportation
中的average_passengers
中。
cq_advanced_every
以30分钟的间隔执行,间隔与EVERY
间隔相同。每30分钟,cq_advanced_every
运行一个查询,覆盖当前时间段的时间范围,即与now()
交叉的一小时时间段。
下面是2016年8月28日上午的日志输出:
在8:00
cq_basic_every
执行时间范围time> ='7:00'AND time <'8:00'
的查询。cq_basic_every
向average_passengers
写入一个点:在8:30
cq_basic_every
执行时间范围time> ='8:00'AND time <'9:00'
的查询。cq_basic_every
向average_passengers
写入一个点:在9:00
cq_basic_every
执行时间范围time> ='8:00'AND time <'9:00'
的查询。cq_basic_every
向average_passengers
写入一个点:
结果为:
请注意,cq_advanced_every
计算8:00时间间隔的结果两次。第一次,它运行在8:30,计算每个可用数据点在8:00和9:00(8,15和15)之间的平均值。 第二次,它运行在9:00,计算每个可用数据点在8:00和9:00(8,15,15和17)之间的平均值。由于InfluxDB处理重复点的方式,所以第二个结果只是覆盖第一个结果。
例二:配置CQ的重采样时间范围
在RESAMPLE
中使用FOR
来指明CQ的时间间隔的长度。
cq_advanced_for
从bus_data
中计算passengers
的30分钟平均值,并将结果存储在数据库transportation
中的average_passengers
中。
cq_advanced_for
以30分钟的间隔执行,间隔与GROUP BY time()
间隔相同。每30分钟,cq_advanced_for
运行一个查询,覆盖时间段为now()
和now()
减去FOR
中的间隔,即是now()
和now()
之前的一个小时之间的时间范围。
下面是2016年8月28日上午的日志输出:
在8:00
cq_advanced_for
执行时间范围time> ='7:00'AND time <'8:00'
的查询。cq_advanced_for
向average_passengers
写入两个点:在8:30
cq_advanced_for
执行时间范围time> ='7:30'AND time <'8:30'
的查询。cq_advanced_for
向average_passengers
写入两个点:在9:00
cq_advanced_for
执行时间范围time> ='8:00'AND time <'9:00'
的查询。cq_advanced_for
向average_passengers
写入两个点:
请注意,cq_advanced_for
会计算每次间隔两次的结果。CQ在8:00和8:30计算7:30的平均值,在8:30和9:00计算8:00的平均值。
结果为:
例三:配置执行间隔和CQ时间范围
在RESAMPLE
子句中使用EVERY
和FOR
来指定CQ的执行间隔和CQ的时间范围长度。
cq_advanced_every_for
从bus_data
中计算passengers
的30分钟平均值,并将结果存储在数据库transportation
中的average_passengers
中。
cq_advanced_every_for
以1小时的间隔执行,间隔与EVERY
间隔相同。每1小时,cq_advanced_every_for
运行一个查询,覆盖时间段为now()
和now()
减去FOR
中的间隔,即是now()
和now()
之前的90分钟之间的时间范围。
下面是2016年8月28日上午的日志输出:
在8:00
cq_advanced_every_for
执行时间范围time>='6:30'AND time <'8:00'
的查询。cq_advanced_every_for
向average_passengers
写三个个点:在9:00
cq_advanced_every_for
执行时间范围time> ='7:30'AND time <'9:00'
的查询。cq_advanced_every_for
向average_passengers
写入三个点:
请注意,cq_advanced_every_for
会计算每次间隔两次的结果。CQ在8:00和9:00计算7:30的平均值。
结果为:
例四:配置CQ的时间范围并填充空值
使用FOR
间隔和fill()
来更改不含数据的时间间隔值。请注意,至少有一个数据点必须在fill()
运行的FOR
间隔内。 如果没有数据落在FOR
间隔内,则CQ不会将任何点写入目标measurement。
cq_advanced_for_fill
从bus_data
中计算passengers
的1小时的平均值,并将结果存储在数据库transportation
中的average_passengers
中。并会在没有结果的时间间隔里写入值1000
。
cq_advanced_for_fill
以1小时的间隔执行,间隔与GROUP BY time()
间隔相同。每1小时,cq_advanced_for_fill
运行一个查询,覆盖时间段为now()
和now()
减去FOR
中的间隔,即是now()
和now()
之前的两小时之间的时间范围。
下面是2016年8月28日上午的日志输出:
在6:00
cq_advanced_for_fill
执行时间范围time>='4:00'AND time <'6:00'
的查询。cq_advanced_for_fill
向average_passengers
不写入任何点,因为在那个时间范围bus_data
没有数据:在7:00
cq_advanced_for_fill
执行时间范围time>='5:00'AND time <'7:00'
的查询。cq_advanced_for_fill
向average_passengers
写入两个点:[...]
在11:00
cq_advanced_for_fill
执行时间范围time> ='9:00'AND time <'11:00'
的查询。cq_advanced_for_fill
向average_passengers
写入两个点:在12:00
cq_advanced_for_fill
执行时间范围time>='10:00'AND time <'12:00'
的查询。cq_advanced_for_fill
向average_passengers
不写入任何点,因为在那个时间范围bus_data
没有数据.
结果:
注意:如果前一个值在查询时间之外,则
fill(previous)
不会在时间间隔里填充数据。
高级语法的常见问题
问题一:如果EVERY间隔大于GROUP BY time()的间隔
如果EVERY
间隔大于GROUP BY time()
间隔,则CQ以与EVERY
间隔相同的间隔执行,并运行一个单个查询,该查询涵盖now()
和now()
减去EVERY
间隔之间的时间范围(不是在now()
和now()
减去GROUP BY time()
间隔之间)。
例如,如果GROUP BY time()
间隔为5m,并且EVERY
间隔为10m,则CQ每10分钟执行一次。每10分钟,CQ运行一个查询,覆盖now()
和now()
减去EVERY
间隔之间的时间段,即now()
到now()
之前十分钟之间的时间范围。
此行为是故意的,并防止CQ在执行时间之间丢失数据。
问题二:如果FOR间隔比执行的间隔少
如果FOR
间隔比GROUP BY time()
或者EVERY
的间隔少,InfluxDB返回如下错误:
为了避免在执行时间之间丢失数据,FOR
间隔必须等于或大于GROUP BY time()
或者EVERY
间隔。
CQ的管理
只有admin用户允许管理CQ。
列出CQ
列出InfluxDB实例上的所有CQ:
SHOW CONTINUOUS QUERIES
按照database作分组。
例子
下面展示了telegraf
和mydb
的CQ:
删除CQ
从一个指定的database删除CQ:
DROP CONTINUOUS QUERY
返回一个空的结果。
例子
从数据库telegraf
中删除idle_hands
这个CQ:
修改CQ
CQ一旦创建就不能修改了,你必须DROP
再CREATE
才行。
CQ的使用场景
采样和数据保留
使用CQ与InfluxDB的保留策略(RP)来减轻存储问题。结合CQ和RP自动将高精度数据降低到较低的精度,并从数据库中移除可分配的高精度数据。
预先计算昂贵的查询
通过使用CQ预先计算昂贵的查询来缩短查询运行时间。使用CQ自动将普通查询的高精度数据下采样到较低的精度。较低精度数据的查询需要更少的资源并且返回更快。
提示:预先计算首选图形工具的查询,以加速图形和仪表板的展示。
替换HAVING子句
InfluxQL不支持HAVING
子句。通过创建CQ来聚合数据并查询CQ结果以达到应用HAVING
子句相同的功能。
注意:InfluxDB提供了子查询也可以达到类似于
HAVING
相同的功能。
例子
InfluxDB不接受使用HAVING
子句的以下查询。该查询以30分钟间隔计算平均bees
数,并请求大于20的平均值。
要达到相同的结果:
1. 创建一个CQ
此步骤执行以上查询的mean("bees")
部分。因为这个步骤创建了CQ,所以只需要执行一次。
以下CQ自动以30分钟间隔计算bees
的平均数,并将这些平均值写入measurementaggregate_bees
中的mean_bees
字段。
2. 查询CQ的结果
这一步要实现HAVING mean("bees") > 20
部分的查询。
在WHERE
子句中查询measurementaggregate_bees
中的数据和大于20的mean_bees
字段的请求值:
替换嵌套函数
一些InfluxQL函数支持嵌套其他函数,大多数是不行的。如果函数不支持嵌套,可以使用CQ获得相同的功能来计算最内部的函数。然后简单地查询CQ结果来计算最外层的函数。
注意:InfluxQL支持也提供与嵌套函数相同功能的子查询。
例子
InfluxDB不接受使用嵌套函数的以下查询。 该查询以30分钟间隔计算bees
的非空值数量,并计算这些计数的平均值:
为了得到结果:
1. 创建一个CQ
此步骤执行上面的嵌套函数的count(“bees”)
部分 因为这个步骤创建了一个CQ,所以只需要执行一次。 以下CQ自动以30分钟间隔计算bees
的非空值数,并将这些计数写入aggregate_bees
中的count_bees
字段。
2. 查询CQ的结果
此步骤执行上面的嵌套函数的mean([...])
部分。 在aggregate_bees
中查询数据,以计算count_bees
字段的平均值:
Last updated
Was this helpful?