TDengine数据迁移之数据对比

数据完整性和一致性校验是迁移数据后的必要步骤,TDengine 数据迁移也是如此。但通常TDengine存储的都是海量数据,动辄几百亿条数据,如果像手工对比差异,工作量是非常巨大的。

以下脚本实现了对两个数据库记录数的对比。主要实现方式为:

  1. 读取超级表信息
  2. 读取时间段信息
  3. 通过 select count(*) from 超级表 group by tbname where ts>='' and ts<''; 查询子表记录数
  4. 对比源和目标库的记录数是否一致
  5. 输出对比结果。

为保证兼容2.x和3.x,数据库查询采用 Restful 方式。

脚本使用方法如下:

  1. 将要对比的超级表名称放入相同目录的stblist文件中(必须是同一个数据库)。
  2. 配置源和目标数据库信息(用户名、密码、URL、数据库名称)
  3. 运行脚本 python3 datacompare.py 2023-01-01T00:00:00Z 2023-10-01T00:00:00Z

注意:

  1. 时间格式必须是 ISO8601 格式
  2. 如果没有指定时间段,则默认为2000-01-01T00:00:00.000+00:002023-10-01T00:00:00.000+00:00
import requests
import sys
import datetime
import json
from requests.auth import HTTPBasicAuth
import configparserdef arg_j(sarg):"""Parse time string in ISO8601 format to timestamp."""try:dt = datetime.datetime.fromisoformat(sarg).strftime('%s')return dtexcept ValueError:sys.exit(f"{sarg}. Time only support ISO8601 format!")def request_post(url, sql, user, pwd):"""Post request to specific url."""try:sql = sql.encode("utf-8")headers = {'Connection': 'keep-alive','Accept-Encoding': 'gzip, deflate, br',}result = requests.post(url, data=sql, auth=HTTPBasicAuth(user,pwd),headers=headers)text = result.content.decode()return textexcept Exception as e:print(e)def check_return(result, tdversion):"""Check result of request."""if tdversion == 2:datart = json.loads(result).get("status")else:datart = json.loads(result).get("code")if str(datart) == 'succ' or str(datart) == '0':chkrt = 'succ'else:chkrt = 'error'return chkrtdef get_data(stbname, url, username, password, dbname, version, stime, etime):"""Get data from source database or destination database."""data = dict()if version == 2:sql = f"select count(*) from `{dbname}`.`{stbname}` where _c0>='{stime}' and _c0<='{etime}' group by tbname;"else:sql = f"select count(*),tbname from `{dbname}`.`{stbname}` where _c0>='{stime}' and _c0<='{etime}' group by tbname;"rt = request_post(url, sql, username, password)code = check_return(rt, version)if code != 'error':rdata = json.loads(rt).get("data")for ll in range(len(rdata)):data[rdata[ll][1]] = rdata[ll][0]else:print(rt)return datadef compare_data(source_info, destination_info, stime, etime):"""Compare data between source database and destination database."""tb_lost = set()tb_diff = set()with open('stblist', 'r') as sfile:for stbname in sfile:stbname = stbname.strip()source_data = get_data(stbname, **source_info, stime=stime, etime=etime)destination_data = get_data(stbname, **destination_info, stime=stime, etime=etime)for key, source_value in source_data.items():destination_value = destination_data.get(key)if destination_value is None:tb_lost.add(key)print(f'Table {key} not exist in destination DB {destination_info["dbname"]}')elif destination_value != source_value:tb_diff.add(key)print(f'Table {key} has different values between source and destination, source is {source_value}, destination is {destination_value}.')print("Lost tables: {}, Diff tables: {}.".format(len(tb_lost), len(tb_diff)))def main():config = configparser.ConfigParser()config.read('config.ini')source_info = {'url': config['source']['url'],'username': config['source']['username'],'password': config['source']['password'],'dbname': config['source']['dbname'],'version': int(config['source']['version']),}destination_info = {'url': config['destination']['url'],'username': config['destination']['username'],'password': config['destination']['password'],'dbname': config['destination']['dbname'],'version': int(config['destination']['version']),}if len(sys.argv) >= 3:stime = str(sys.argv[1])etime = str(sys.argv[2])else:stime = '2000-01-01T00:00:00.000+00:00'etime = '2023-10-01T00:00:00.000+00:00'arg_j(stime)arg_j(etime)compare_data(source_info, destination_info, stime, etime)if __name__ == "__main__":main()

以上代码是 AI 修改过的,不保证能够执行成功。

我将调试好的代码也上传了。点击下载

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

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

相关文章

前端设计模式之【访问者模式】

文章目录 前言介绍实现优缺点应用场景后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;前端设计模式 &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#…

ChatGPT:something went wrong

今天下午不知什么原因&#xff0c;ChatGPT无法使用。我原来在使用ChatGPT for chrome&#xff0c;返回了一个答案&#xff0c;后来在网页端无法使用&#xff0c;以为是这个chrome插件泄露API KEY导致的。注销账号&#xff0c;删除API KEY后&#xff0c;wrong问题仍然存在。 我…

oj刷题-C语言版

1. A B 题目 输入两个整数&#xff0c;求这两个整数的和是多少。 输入格式 输入两个整数A,B &#xff0c;用空格隔开 输出格式 输出一个整数&#xff0c;表示这两个数的和 数据范围 0≤A,B≤108 样例输入&#xff1a; 3 4 样例输出&#xff1a; 7AC代码C&#xff1a; #…

API是什么?解密API背后的奥秘

API&#xff0c;全称Application Programming Interface&#xff0c;是一种用于不同应用程序间通信的接口&#xff0c;它允许不同的应用程序之间交换数据和功能。API可以理解为应用程序提供给其他应用程序或开发者的接口&#xff0c;通过这个接口&#xff0c;其他应用程序或开发…

2023年CCF非专业级别软件能力认证第二轮 (CSP-J)入门级C++语言试题

2023年CCF非专业级别软件能力认证第二轮 &#xff08;CSP-J&#xff09;入门级C语言试题 编程题第 1 题 问答题 小苹果&#xff08;apple&#xff09; 题目描述 小Y的桌子上放着n个苹果从左到右排成一列&#xff0c;编号为从1到n。 小苞是小Y的好朋友&#xff0c;每天她都会…

PostgreSQL 技术内幕(十一)位图扫描

扫描算子在上层计算和底层存储之间&#xff0c;向下扫描底层存储的数据&#xff0c;向上作为计算的输入源&#xff0c;在SQL的执行层中&#xff0c;起着关键的作用。顺序、索引、位图等不同类型的扫描算子适配不同的数据分布场景。然而&#xff0c;扫描算子背后的实现原理是怎样…

flink测试map转换函数和process函数

背景 在flink中&#xff0c;我们需要对我们写的map转换函数&#xff0c;process处理函数进行单元测试&#xff0c;测试的内容包括查看函数的输出结果是否符合以及函数内的状态是否正确更新&#xff0c;本文就记录几个测试过程中的要点 flink中测试函数 首先我们根据我们要测…

RSA加密的使用(前后端)

公钥&#xff08;publicKey&#xff09;加密、私钥&#xff08;privateKey&#xff09;解密。不能逆向&#xff0c;私钥&#xff08;privateKey&#xff09;加密、公钥&#xff08;publicKey&#xff09;解密。说白了就是前后端都需要用公钥&#xff08;publicKey&#xff09;进…

【JavaEESpring】认识Spring

认识Spring 1. 什么是框架2. SpringBoot 介绍2.1 Spring 的介绍2.2 SpringBoot 1. 什么是框架 框架(Framework) &#xff0c;意思是框架、机制、准则。通俗的来讲: 框架是实现某种功能的半成品, 他提供了⼀些常⽤的⼯具类, 我们在框架的基础上, 可以更加⾼效的进⾏开发 后端框…

Redis6的IO多线程分析

性能测试 机器配置 C Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 14 On-line CPU(s) list: 0-13 Mem: 62G性能 配置推荐 官方表示&#xff0c;当使用redis时有性能瓶…

vue3接口、数据懒加载,回滚不重复加载

目标&#xff1a;实现当组件进入可视区域在加载数据或者发送请求。 背景&#xff1a;父组件为vxe-table构成的组件、子组件为table的某一列&#xff0c;这一列的数据通过接口返回&#xff0c;有多少条表格数据就会请求多少次接口&#xff0c;为了提升性能&#xff0c;所以采用…

《开箱元宇宙》:认识香港麦当劳通过 The Sandbox McNuggets Land 的 Web3 成功经验

McNuggets Land 是 The Sandbox 于 2023 年发布的最受欢迎的体验之一。在本期的《开箱元宇宙》系列中&#xff0c;我们采访了香港麦当劳数位顾客体验暨合作伙伴资深总监 Kai Tsang&#xff0c;来了解这一成功案例背后的策略。 在不断发展的市场营销和品牌推广领域&#xff0c;不…

Visual Studio 2022 + OpenCV 4.5.2 安装与配置教程

目录 OpenCV的下载与配置Visual Studio 2022的配置新建工程新建文件新建项目属性表环境配置测试先写一个输出将OpenCV的动态链接库添加到项目的 x64 | Debug下测试配置效果 Other OpenCV的下载与配置 参考这个OpenCV的下载与环境变量的配置&#xff1a; Windows10CLionOpenCV4…

网络原理---拿捏HTTP协议:请求和响应

文章目录 认识请求首行URLURL的格式URL的encode和decode 版本号方法GET方法POST方法GET VS POST 请求头&#xff1a;headerHostContent-Length 和 Content-TypeUser-Agent&#xff08;UA&#xff09;RefererCookie 空行正文&#xff1a;body如何构造HTTP请求&#xff1f;浏览器…

ARMday04(开发版简介、LED点灯)

开发版简介 开发板为stm32MP157AAA,附加一个拓展版 硬件相关基础知识 PCB PCB&#xff08; Printed Circuit Board&#xff09;&#xff0c;中文名称为印制电路板&#xff0c;又称印刷线路板&#xff0c;是重要的电子部件&#xff0c;是电子元器件的支撑体&#xff0c;是电子…

Linux生成随机密码和根据密码批量生成用户

cat /dev/urandom|tr -dc [:alnum:]|head -c20 生成20位数字字母的随机密码。 /dev/urandom生成随机数&#xff0c;tr -dc [:alnum:] 保留所有数字和字母&#xff0c;head -c20保留前20位。 使用原生的Linux命令生成可以说是极度安全的&#xff0c;也适用于批量用户生成的情况…

Django中如何让DRF的接口针对前后台返回不同的字段

在Django中&#xff0c;使用Django Rest Framework&#xff08;DRF&#xff09;时&#xff0c;可以通过序列化器&#xff08;Serializer&#xff09;和视图&#xff08;View&#xff09;的组合来实现前后台返回不同的字段。这通常是因为前后台对数据的需求不同&#xff0c;或者…

AlphaControls控件TsRadioGroup的使用

通常使用AlphaControls控件中的TsRadioGroup时&#xff0c;往往使用默认值&#xff0c;会造成TsRadioGroup标题被TsRadioGroup的ITEMs占用&#xff0c;严重影响美观&#xff1a; 解决方案&#xff0c;通过对TsRadioGroup的ContentVOffset属性&#xff0c;设置为10。即可立即改善…

处理uniapp打包后有广告的问题

1、登录平台&#xff08;开发者中心&#xff09; 2、 3、 4、 5、

3线硬件SPI+DMA驱动 HX8347 TFT屏-快速显示文字

本文实现DMA快速显示文字 汉字点阵通常是16*16点阵&#xff0c;那么用DMA一次性显示汉字&#xff0c;应该至少申请480*16个字节的空间&#xff0c;用于显示一行文字&#xff0c;其中480是屏幕一行用DMA驱动所需内存。 一、 源码 HX8347.h #ifndef USER_HX8347_H_ #define USE…