当前位置: 首页 > news >正文

五分钟掌握 TDengine 数据文件的工作原理

小 T 导读:今天我们来探讨一下——TDengine中的时序数据到底是如何存储的?

在上一期的文章《五分钟掌握 TDengine 时序数据的保留策略》中,我们知道了TDengine是如何按照时间段对数据进行分区来管理数据的。

接下来,我们和大家一起从产品使用者的视角继续向前探索——TDengine中的时序数据到底是如何存储的?

在那篇文章里,在我们第一次写入数据并重启数据库服务后,在vnode xx路径下看到了这三个文件。

图片

这哥仨,其实就是TDengine中广义上的数据文件,也可以说它们是一个数据文件组。

从后缀上看,仿佛.data这个文件就是数据文件组中的数据文件。而其他二位都是为它保驾护航的“辅助”。但是这个感觉是不够准确的,因为.last文件同样也会存储数据。而.head文件则是存储数据块的索引的文件。

在了解它们之前,首先我们要知道两个参数:

1.minRows:数据块中记录的最小条数,单位为条,默认值为100。

2.maxRows:数据块中记录的最大条数,单位为条,默认值为4096。

数据块,是每个.data数据文件里存储数据的单位,每一个数据块都只能存储一个表的数据。所以上面的参数描述的意思就是——形成一个数据块默认的最小行数是100行,最多就是4096行。

那么,对于一张表来说,小于100行的话数据会去哪儿呢?大于4096行的话数据又去哪儿了呢?

答案是,.last文件正是表行数不足100时数据存放的位置;而大于4096行的表会生成一个新的数据块。最终在.data文件中,数据块的分布方式如下:

图片

当然,这样讲会比较抽象,我们继续用实例说明:

我们假设创建库时使用的参数为 maxrows=1000,minrows=100。某库中有两张表A和B,我们向其中分别插入1000行和99行数据。然后,我们重启taosd服务,以上数据就会从内存中落盘到存储上。这个时候.data文件中会生成1个数据块,它就是表A的数据块1,里面拥有1000条数据。而表B的99条数据因为不足minrows所以就进入了.last文件。

接下来,继续向它们分别插入1000行和99行,然后重启taosd服务落盘。这个时候表A总共拥有2000条数据,新写入的1000行数据会被写入进表A的数据块2。而表B的数据量现在已经有了198行,大于了100行。于是它们也会被写入.data文件里面,成为表B的数据块1。

值得注意的是,当.last文件小于32k的时候,所有数据都只会追加进来。但是当.last文件大于32k的时候,每次落盘.last文件都是重写生成的了——这个的32k限制是为了防止数据的移动过于频繁。

所以,我们在做测试的时候会发现:为什么当该表行数从99到100行以上时,.data文件的大小已经增加可.last文件却没有变小。只有当.last文件大于32k的时候,才能看到符合我们心理预期的效果——.last文件把数据移到.data文件,.last文件变小,.data文件变大。

以上场景只针对两个表,但其实放大到100个表,1000个表都是一样的逻辑。尽管每个vnode内存里存储的大量数据分属于不同的表,但是每次落盘只要这些表的行数保证大于minrows,它们都会落入到.data文件的数据块中。不满足上述条件的表数据被写入.last文件后,继续等待新数据的写入,直到该表满足了行数minrows的大小后,.last文件中该表的数据会被读入到内存,之后一起写入到.data文件中。

最后总结一下:

.data类文件存储的是真正的时序数据,为多个数据块构成。一个数据块只属于一张表,且数据块的顺序只与落盘的先后顺序有关。

.last文件与.data文件一样,也是存储时序数据的,只不过.last文件存储的块中的数据条数小于minRows。

本篇文章重点讲述的是.last与.data文件的关系。

关于.head文件,我们会在后面的文章中讲解。在此之前,我们只要知道它是用来方便查询数据的索引文件就可以了。.head文件的用途是什么?它会影响到哪些重要的功能?minrows和maxrows的变化会给性能带来多大的影响呢?以上这类问题都会涉及到很广泛的性能问题,我们将会在今后的日子慢慢讨论。

如果不了解TDengine的体系架构,对于用户来说很可能是事倍功半的。现在,涛思数据的每一期内容推送都是在为大家未来可以事半功倍而做的内容沉淀。

关于 TDengine

TDengine  是一款专为物联网、工业互联网等场景设计并优化的大数据平台,其核心模块是高性能、集群开源、云原生、极简的时序数据库。

http://www.dtcms.com/a/286284.html

相关文章:

  • 《设计模式之禅》笔记摘录 - 8.命令模式
  • 【Mediatek】AN7563搭建编译环境操作说明
  • 1 初识C++
  • 【java 安全】 IO流
  • 20250718-3-Kubernetes 应用程序生命周期管理-Pod对象:存在意义_笔记
  • Android性能优化之包体积优化
  • C++算法竞赛篇:DevC++ 如何进行debug调试
  • Django 实战:I18N 国际化与本地化配置、翻译与切换一步到位
  • 第7天 | openGauss中一个数据库中可以创建多个模式
  • 51c视觉~合集13
  • 互联网医疗健康服务包的核心内容架构与模块组合
  • 小记_想写啥写啥_实现行间的Latex公式_VScode始终折叠大纲
  • 构建直播平台大体的流程
  • gcc 源码阅读---编译器后端实现的关键数据结构
  • DOM笔记
  • 什么是KL散度
  • Android-EDLA【CTS】CtsInputMethodTestCases存在fail
  • 4G模块 A7680发送中文短信到手机
  • 高精度减法模版和分析(C++版本)
  • 嵌入式八股(持续更新)
  • 【算法训练营Day14】二叉树part4
  • windows终端美化(原生配置+Oh My Posh主题美化)
  • 客诉:危机到信任的重建
  • Flutter 应用如何设计通知服务
  • Flutter——Android原生View是如何通过Flutter进行加载
  • 2025年Flutter开发主流技术栈
  • Flutter 多语言(国际化)入门教程
  • 企业如何让内部视频仅限公司官网或指定域名播放?
  • 低代码开发实践博客
  • C++语法 匿名对象 与 命名对象 的详细区分