InfluxQL内部机制
了解InfluxQL的实现,了解结果的处理方式以及如何创建高效查询
查询生命周期
InfluxQL查询字符串被分解成标记,然后解析成抽象语法树(AST)。这是查询本身的代码表示。
AST传递给
QueryExecutor
,它将查询定向到相应的处理程序。例如,与元数据相关的查询由元数据服务执行,而SELECT
语句由分片本身执行。查询引擎然后确定与
SELECT
语句的时间范围匹配的分片。从这些分片中,为语句中的每个字段创建迭代器。迭代器传递给发射器,它排空它们并将结果点连接起来。发射器的任务是将简单的时间/值点转换为更复杂的返回给客户端的结果对象。
理解迭代器
迭代器为遍历一组点提供了一个简单的接口。例如,这是一个浮点数迭代器
type FloatIterator interface {
Next() *FloatPoint
}
这些迭代器通过IteratorCreator
接口创建
type IteratorCreator interface {
CreateIterator(opt *IteratorOptions) (Iterator, error)
}
IteratorOptions
提供了关于字段选择、时间范围和维度的参数,迭代器创建者可以在规划迭代器时使用这些参数。在许多层面使用 IteratorCreator
接口,例如在 Shards
、Shard
和 Engine
中。这使得在适用的情况下可以执行优化,例如返回预计算的 COUNT()
。
尽管迭代器主要用于从存储中读取原始数据,但迭代器可以被组合以提供围绕输入迭代器的额外功能。例如,一个 DistinctIterator
可以计算输入迭代器每个时间窗口的不同值。或者一个 FillIterator
可以生成输入迭代器中缺失的点。
这种组合也非常适合聚合。例如,在下面的 SQL 中,MEAN(value)
是一个包装了底层分片迭代器的 MeanIterator
SELECT MEAN(value) FROM cpu GROUP BY time(10m)
以下示例将 MEAN(value)
包装在另一个迭代器(DERIVATIVE()
)中,以确定均值的导数
SELECT DERIVATIVE(MEAN(value), 20m) FROM cpu GROUP BY time(10m)
游标
光标 通过 (时间, 值) 对在单个系列(测量,标签集和字段)中按分片识别数据。光标遍历以日志结构合并树存储的数据,并处理跨级别的去重、删除数据的墓碑以及合并缓存(预写日志)。光标按时间顺序(升序或降序)对 (时间, 值) 对进行排序。
例如,一个查询评估 3 个分片上的 1,000 个系列中的一个字段,至少构建 3,000 个光标(每个分片 1,000 个)。
辅助字段
因为 InfluxQL 允许用户使用如 FIRST()
、LAST()
、MIN()
和 MAX()
等选择函数,所以引擎必须提供一种方法,以便在返回所选点的同时返回相关数据。
让我们看看以下查询
SELECT FIRST(value), host FROM cpu GROUP BY time(1h)
我们正在选择每个小时出现的第一个 value
,但我们还想要检索与该点相关的 host
。由于 Point
类型仅指定一个类型化的 Value
以提高效率,我们将 host
推送到点的辅助字段中。这些辅助字段附加到点上,直到它被传递到发射器,此时字段被分开到自己的迭代器中。
内置迭代器
有许多辅助迭代器可以帮助我们构建查询
合并迭代器 - 这种迭代器将一个或多个迭代器合并为同一类型的单个新迭代器。此迭代器保证在开始下一个窗口之前,窗口内的所有点都将输出,但不在窗口内提供排序保证。这允许对于不需要更强排序保证的聚合查询进行快速访问。
排序合并迭代器 - 与
MergeIterator
类似,这种迭代器将一个或多个迭代器合并为同一类型的新迭代器。但是,此迭代器保证每个点的时序。这使得它比MergeIterator
慢,但这种排序保证对于返回原始数据点的非聚合查询是必需的。限制迭代器 - 这种迭代器限制了每个名称或标签组每点的数量。这是
LIMIT
和OFFSET
语法的一种实现。填充迭代器 - 这种迭代器在输入迭代器中缺少点时会注入额外的点。它可以提供
null
点、具有前一个值的点或具有特定值的点。缓冲迭代器 - 这种迭代器提供了将点“重新读取”回缓冲区的功能,以便下次可以再次读取。这被广泛用于提供窗口的预览。
Reduce 迭代器 - 此迭代器为窗口中的每个点调用一个归约函数。当窗口完成时,则输出该窗口的所有点。这用于简单的聚合函数,如
COUNT()
。Reduce 切片迭代器 - 此迭代器首先收集窗口中所有点,然后将它们一次性传递给归约函数。结果由迭代器返回。这用于聚合函数,如
DERIVATIVE()
。转换迭代器 - 此迭代器为输入迭代器中的每个点调用转换函数。这用于执行二元表达式。
去重迭代器 - 此迭代器仅输出唯一点。因为它资源密集,此迭代器仅用于小查询,如元查询语句。
调用迭代器
InfluxQL 中的函数调用在两个级别实现
一些调用可以在多个层次上封装以提高效率。例如,可以在分片级别执行
COUNT()
,然后使用另一个CountIterator
将多个CountIterator
封装起来,以计算所有分片的计数。可以使用NewCallIterator()
创建这些迭代器。一些迭代器更复杂或需要在高一级别实现。例如,
DERIVATIVE()
函数需要在执行计算之前检索窗口中的所有点。此迭代器由引擎本身创建,并且不会被低级别请求创建。
这个页面有帮助吗?
感谢您的反馈!