InfluxDB SHOW SERIES语句按照什么顺序返回?

news2025/1/20 4:48:58

在这里插入图片描述本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。

文章目录

  • 引言
  • 样例
  • SHOW SERIES比较原理
  • 结论
  • 结束语

引言

influxdb的计算引擎为了做到自底而上的合并逻辑,必然存在某种row的排序规则,这些规则在查询计划的创建阶段就已经确定。

比如group by tags,此类查询基于tag的排序;而group by time的查询,则基于time去做排序;group by tags, time 则是基于tags和time;至于show则是基于field排序;特殊的比如show series cardinality在改写为select后实际是基于tags排序;

事实上要完成一个流式引擎必须自底而上遵循某种排序规则;例如子查询内部的排序规则和内部排序规则不同是则需要重排,这就没法做到流式返回。

样例

show series不是基于serieskey或者基于展开后的tag做排序,简单的看两个show series 返回的case:

"yottadb_partition_replicas_num_lzl_ywq,account_id2=Mqw0vQ\\=\\="
"yottadb_partition_replicas_num_lzl_ywq,account_id4=Mqw0vQ\\=\\="
"yottadb_partition_replicas_num_lzl_ywq,account_id5=Mqw0vQ\\=\\="
"yottadb_partition_replicas_num_lzl_ywq,account_id7=Mqw0vQ\\=\\="
"yottadb_partition_replicas_num_lzl_ywq,account_id8=Mqw0vQ\\=\\="
"yottadb_partition_replicas_num_lzl_ywq,account_id9=Mqw0vQ\\=\\="
account_id2account_id4account_id5account_id7account_id8account_id9
Mqw0vQ\=\=nullnullnullnullnull
nullMqw0vQ\=\=nullnullnullnull
nullnullMqw0vQ\=\=nullnullnull
nullnullnullMqw0vQ\=\=nullnull
nullnullnullnullMqw0vQ\=\=null
nullnullnullnullnullMqw0vQ\=\=

这个case表示不是以serieskey内部的tag本身做排序;因为以这个规则排序展开后account_id9应该排在最前面,因为null本身小于任何值。

"car1,city=city_0dddd,id=2,type=type_2"
"car1,city=city_0dddd\\ ,id=2,type=type_2"
"car1,city=city_1,id=3,type=type_0"

空格的ascall码小于 ‘,’ ,所以也不是以serieskey排序

SHOW SERIES比较原理

我们回到show series,引擎内部迭代器调用栈帧如下:

  1. v1/coordinator/statement_executor.go:createIteratorsV2
  2. influxql/query/select.go:Select
  3. influxql/query/compile.go: (c *compiledStatement) Prepare 已经把shards赋值给preparedStatement.ic
  4. influxql/query/select.go: (p *preparedStatement) Select
  5. influxql/query/select.go:buildCursor
  6. influxql/query/select.go:buildAuxIterator
  7. tsdb/shard.go:(a Shards) CreateIterator
  8. tsdb/shard.go:(s *Shard) CreateIterator
  9. tsdb/engine/tsm1/engine.go:CreateIterator
  10. tsdb/shard.go:(a Shards) CreateIterator
  11. tsdb/shard.go:(a Shards) createSeriesIterator
  12. tsdb/index.go:NewSeriesPointIterator
  13. tsdb/index.go:MeasurementIterator (is IndexSet) measurementIterator()
  14. tsdb/index/tsi1/index.go: (i *Index) MeasurementIterator()
  15. tsdb/index/tsi1/partition.go (p *Partition) MeasurementIterator()
  16. tsdb/index/tsi1/file_set.go (fs *FileSet) MeasurementIterator()
  17. tsdb/index/tsi1/log_file.go (f *LogFile) MeasurementIterator()

事实上createSeriesIterator之下的MeasurementIterator都是基于measurement name做比较,真正的比较是shards中的seriesPointIterator,其首先会获取每一个measurement的全部时间序列对应的tsid,随后从sfile中获取tsid对应的serieskey,直接原地调用sort, 排序seriesKeys,实际调用CompareSeriesKeys作为比较函数。

核心比较函数为CompareSeriesKeys:

func CompareSeriesKeys(a, b []byte) int {
	// Handle 'nil' keys.
	if len(a) == 0 && len(b) == 0 {
		return 0
	} else if len(a) == 0 {
		return -1
	} else if len(b) == 0 {
		return 1
	}

	// Read total size.
	_, a = ReadSeriesKeyLen(a)
	_, b = ReadSeriesKeyLen(b)

	// Read names.
	name0, a := ReadSeriesKeyMeasurement(a)
	name1, b := ReadSeriesKeyMeasurement(b)

	// Compare names, return if not equal.
	if cmp := bytes.Compare(name0, name1); cmp != 0 {
		return cmp
	}

	// Read tag counts.
	tagN0, a := ReadSeriesKeyTagN(a)
	tagN1, b := ReadSeriesKeyTagN(b)

	// Compare each tag in order.
	for i := 0; ; i++ {
		// Check for EOF.
		if i == tagN0 && i == tagN1 {
			return 0
		} else if i == tagN0 {
			return -1
		} else if i == tagN1 {
			return 1
		}

		// Read keys.
		var key0, key1, value0, value1 []byte
		key0, value0, a = ReadSeriesKeyTag(a)
		key1, value1, b = ReadSeriesKeyTag(b)

		// Compare keys & values.
		if cmp := bytes.Compare(key0, key1); cmp != 0 {
			return cmp
		} else if cmp := bytes.Compare(value0, value1); cmp != 0 {
			return cmp
		}
	}
}

结论

所以事实上show series返回的真正顺序遵循以下规则:

  1. 以measurement name排序
  2. 每个measuremnet基于serieskey内部的tag本身做排序

其实很好理解,因为从tsi中获取measurement对应的tsid后又从sfile获取对应的serieskey,此时的serieskey为了解析的性能,事实上进行了二进制编码的,无法直接拿来比较;其次此时是没有schema的概念的,所以如果基于tag去排序效率会及其低下,因为需要先计算合并后的schema结构,然后再生成新的row,所以搞了个这么个性能不错,但是奇奇怪怪的排序方法;

这种比较方式可以应用到流式框架,但是意义不大,因为本身这种排序就没有规定一个全局顺序(不同的tagkey都直接拿来比较了),而且与influxql本来的排序方式差别很大,额外的开发工作很多;

从用户的角度看,show series的顺序没有什么意义,就算希望有意义,当前的show series也无法满足,所以最好的方式就是直接hash merge,不给用户保证show series的返回顺序,influxdb的官网也没有保证show series的顺序。

结束语

花了三十分钟迅速写完这篇文章,倒不是这个点很重要,关键在于我在半年前实现某些特性时"假设"其顺序是serieskey,在第二次实现"假设"其是以tag为顺序,最后发现与想的完全不同。

以后做任何事前都需要提醒自己,合理的规划可以节省大量时间。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1496080.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

曲线曲面 - 连续性, 坐标变换矩阵

连续性 有两种:参数连续性(Parametric Continuity)、几何连续性(Geometric Continuity)参数连续性: 零阶参数连续性,记为,指相邻两段曲线在结合点处具有相同的坐标 一阶参数连续性&…

前缀和+哈希表:联手合击Leetcode 560.和为k的子数组

题目 给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1: 输入:nums [1,1,1], k 2 输出:2示例 2: 输入:nums [1,2…

GPT-4技术解析:与Claude3、Gemini、Sora的技术差异与优势对比

【最新增加Claude3、Gemini、Sora、GPTs讲解及AI领域中的集中大模型的最新技术】 2023年随着OpenAI开发者大会的召开,最重磅更新当属GPTs,多模态API,未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义,不亚…

【笔记】OpenHarmony和HarmonyOS区别及应用开发简介

一、概念 OpenHarmony(OH) : OpenAtom OpenHarmonyHarmonyOS(HO):开发 | 华为开发者联盟 (huawei.com) HO当前最高是3.1,在华为mate 60上面也是。关于4.0、5.0和next这类版本说法都是面向用户的,不是开发人员。对于程序员&#…

算法相关计算

1 内存管理相关 1 .1 float 6.9 f 的内存计算方法 二进制小数的计算: (1)小数的二进制算法和整数的大致相反,就是不断的拿小数部分乘以2取积的整数部分,然后正序排列。比如求0.9的二进制: 0.9*21.8 取 1…

opencv边缘检测之Canny算法

文章目录 简介实战 简介 Canny在1986年提出了一种边缘检测算法,因其卓越的性能和准确性而广泛应用于各种图像分析领域。opencv中提供了这种算法,其操作步骤如下 高斯滤波:采用 5 5 5\times5 55的高斯核函数进行滤波,对图像进行…

chrome插件chrome.storage数据写入失败QUOTA_BYTES_PER_ITEM quota exceeded

Unchecked runtime.lastError while running storage.set: QUOTA_BYTES_PER_ITEM quota exceeded at Object.callback 在开发浏览器插件的时候,报错提示:超出存储限制,浏览器插件存储官方文档:https://developer.chrome.com/docs…

selinux规则

selinux状态 相关命令 进程要和文件的安全上下文相匹配,进程才能打开文件 查找这个命令从哪个安装包来的用 yum provides 命令 进程httpd 必须与ls -Z的文件类型一致,要不然在强制模式下面,打开不了 在终端2用此命令,把文件类型改…

【Ubuntu】将多个python文件打包为.so文件

1.为什么要将python打包为.so文件? 保护源码 2.实战例子 a.安装相应的包 pip install cython 验证安装是否成功 cython --version b.实战的文件目录和内容 hi.py # This is a sample Python script.# Press ShiftF10 to execute it or replace it with your…

基于OpenCV的图形分析辨认01

目录 一、前言 二、实验目的 三、实验内容 四、实验过程 一、前言 编程语言:Python,编程软件:vscode或pycharm,必备的第三方库:OpenCV,numpy,matplotlib,os等等。 关于OpenCV&…

Docker的镜像操作

目录 镜像的操作(**开头为常用请留意) 镜像查找 **拉取镜像 **推送镜像 **查看镜像 **修改镜像名称 **查看镜像的详细信息 ​编辑 删除镜像 查看所有镜像ID 删除全部镜像 **查看镜像的操作历史 镜像迁移 镜像打包 远程发送镜像(需要先打包) 本地镜像tar包恢复 镜像过…

FPGA——三速自适应以太网设计(2)GMII与RGMII接口

FPGA——以太网设计(2)GMII与RGMII 基础知识(1)GMII(2)RGMII(3)IDDR GMII设计转RGMII接口跨时钟传输模块 基础知识 (1)GMII GMII:发送端时钟由MAC端提供 下…

Web安全:报错注入原理分析,报错注入步骤,报错注入常用函数

「作者主页」:士别三日wyx 「作者简介」:CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」:对网络安全感兴趣的小伙伴可以关注专栏《网络安全自学教程》 报错注入 一、什么是报错注入二、执行原理1. 代码逻辑…

node_vue个人博客系统开发

Day01 一、导入express 1、创建node_serve服务文件夹 2、初始化项目 npm init -y3、导入express框架 npm i express4、创建一个app.js文件,为服务端的入口文件 // 导入express模块 const express = require(express); // 创建express服务 const app = express(); // 调用…

Promisification、微任务

前提摘要 Promise 对象的构造器(constructor)语法如下: let promise new Promise(function(resolve, reject) { // executor }); 传递给 new Promise的函数被称为 executor,当 new Promise 被创建,executor 会自动…

小程序Taro框架 自定义底部Tabbar,处理自定义Tab栏切换卡顿、闪烁

最终效果 最近在用Taro框架开发一个小程序,有一个自定义底部Tabbar的需求,最终效果如下 起步 这页是我第一次接触自定义小程序底部Tabbar,所有第一选择必然是相看官方文档:微信小程序自定义 Tabbar | Taro 文档 (如果…

支部管理系统微信小程序(管理端+用户端)flask+vue+mysql+微信小程序

系统架构如图所示 高校D支部管理系统 由web端和微信小程序端组成,由web端负责管理,能够收缴费用、发布信息、发布问卷、发布通知等功能 部分功能页面如图所示 微信小程序端 包含所有源码和远程部署,可作为毕设课设

SAP PP学习笔记07 - 简单BOM,派生BOM,多重BOM,批量修改工具 CEWB

上一章讲了BOM的操作。 SAP PP学习笔记06 - BOM操作(BOM 展开,BOM 使用先一览,BOM比较,批量更改BOM)-CSDN博客 本章延续上一章,继续讲BOM操作。 主要讲 派生BOM,多重BOM,以及BOM批…

Python·算法·每日一题(3月7日)电话号码的字母组合

题目 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 示例 示例 1: 输入:digits "23&qu…

IDEA中右侧工具栏没有maven框

第一步,首选确认自己的IDEA的Maven配置是否正常, 如果确认配置没问题,第二步,查看这个地方是否有Maven的选项? 什么,这里你居然也没有?好吧,那就跟我一样了,进入第三步 …