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

解决python从TD数据库取50w以上大量数据慢的问题

1.问题背景描述

python项目中的时序数据都存放在TD数据库中,数据是秒级存入的,当查询一周数据时将超过50w数据量,这是一次性获取全量数据到python程序很慢,全流程10秒以上,希望进行优化加速

2.排查

首先,分步排查从td取超过7秒,在python程序中处理格式超过3秒;
其次,业务逻辑处理步骤中,时间大量消耗的逻辑是 时间对象转成字符串;
再次,td取数步骤中,时间大量消耗的逻辑是 获取到数据后时间戳转为时间对象
最后,思路确定为,从td获取的ts字段直接按bigint返回,交由业务逻辑处理,直接从bigint转成字符串;

3.查源码尝试修改

TD取的ts字段是用bigint存的(C_TIMESTAMP类型),排查源码发现公共包中会将C_TIMESTAMP类型的字段都转成datetime对象返回,而转化方法_convert_millisecond_to_datetime就是慢的根源;继续查相关源码,若想用bigint返回,发现CONVERT_FUNC_BLOCK这个函数工厂,key是每个字段类型fields[i][“type”],这个字段类型是在taos_fetch_fields

# TDHelper().db_query(sql) 调用入口
class TDHelper:  # 自定义的TD适配逻辑def db_query(self, sql, return_timestamp=False):with self.cursor() as c:return self._query_handler(c, sql, return_timestamp)def _query_handler(self, cursor, sql, return_timestamp=False):try:cursor.execute(sql)  # execute中会获取_fields属性,由决定后续字段序列化的逻辑# cursor._fields[0]._type = 5  # 修改,测试用result = cursor.fetchall()if not return_timestamp:return resultelse:ret_result = []for one in result:ret_result.append((one[0].timestamp(), *one[1:]))return ret_resultexcept ProgrammingError as e:if e.msg == 'Fail to get table info, error: Table does not exist':# 只输出sql,不需要输出异常信息logger.warning('Table does not exist, sql [{}]'.format(sql))return []raise e# 如下都是TD公共包中的源码def fetchall(self):  # cursor的方法if self._result is None:raise OperationalError("Invalid use of fetchall")fields = self._fields if self._fields is not None else taos_fetch_fields(self._result)buffer = [[] for i in range(len(fields))]self._rowcount = 0while True:block, num_of_rows = taos_fetch_block(self._result, self._fields)   # 关键逻辑errno = taos_errno(self._result)if errno != 0:raise ProgrammingError(taos_errstr(self._result), errno)if num_of_rows == 0:breakself._rowcount += num_of_rowsfor i in range(len(self._fields)):buffer[i].extend(block[i])return list(map(tuple, zip(*buffer)))def taos_fetch_block(result, fields=None, field_count=None):if fields is None:fields = taos_fetch_fields(result)if field_count is None:field_count = taos_field_count(result)pblock = ctypes.c_void_p(0)num_of_rows = _libtaos.taos_fetch_block(result, ctypes.byref(pblock))if num_of_rows == 0:return None, 0precision = taos_result_precision(result)blocks = [None] * field_countfor i in range(len(fields)):data = ctypes.cast(pblock, ctypes.POINTER(ctypes.c_void_p))[i]if fields[i]["type"] not in CONVERT_FUNC_BLOCK_v3 and fields[i]["type"] not in CONVERT_FUNC_BLOCK:raise DatabaseError("Invalid data type returned from database")offsets = []is_null = []if fields[i]["type"] in (FieldType.C_VARCHAR, FieldType.C_NCHAR, FieldType.C_JSON):offsets = taos_get_column_data_offset(result, i, num_of_rows)blocks[i] = CONVERT_FUNC_BLOCK_v3[fields[i]["type"]](data, is_null, num_of_rows, offsets, precision)else:is_null = [taos_is_null(result, j, i) for j in range(num_of_rows)]# 关键逻辑blocks[i] = CONVERT_FUNC_BLOCK[fields[i]["type"]](data, is_null, num_of_rows, offsets, precision)return blocks, abs(num_of_rows)CONVERT_FUNC_BLOCK = {FieldType.C_BOOL: _crow_bool_to_python,FieldType.C_TINYINT: _crow_tinyint_to_python,FieldType.C_SMALLINT: _crow_smallint_to_python,FieldType.C_INT: _crow_int_to_python,FieldType.C_BIGINT: _crow_bigint_to_python,FieldType.C_FLOAT: _crow_float_to_python,FieldType.C_DOUBLE: _crow_double_to_python,FieldType.C_BINARY: _crow_binary_to_python_block,FieldType.C_TIMESTAMP: _crow_timestamp_to_python,   # 关键逻辑FieldType.C_NCHAR: _crow_nchar_to_python_block,FieldType.C_TINYINT_UNSIGNED: _crow_tinyint_unsigned_to_python,FieldType.C_SMALLINT_UNSIGNED: _crow_smallint_unsigned_to_python,FieldType.C_INT_UNSIGNED: _crow_int_unsigned_to_python,FieldType.C_BIGINT_UNSIGNED: _crow_bigint_unsigned_to_python,FieldType.C_JSON: _crow_nchar_to_python_block,
}def _crow_timestamp_to_python(data, is_null, num_of_rows, nbytes=None, precision=FieldType.C_TIMESTAMP_UNKNOWN):"""Function to convert C bool row to python row."""_timestamp_converter = _convert_millisecond_to_datetime   # 关键逻辑if precision == FieldType.C_TIMESTAMP_MILLI:_timestamp_converter = _convert_millisecond_to_datetimeelif precision == FieldType.C_TIMESTAMP_MICRO:_timestamp_converter = _convert_microsecond_to_datetimeelif precision == FieldType.C_TIMESTAMP_NANO:_timestamp_converter = _convert_nanosecond_to_datetimeelse:raise DatabaseError("Unknown precision returned from database")return [None if is_null[i] else _timestamp_converter(ele)for i, ele in enumerate(ctypes.cast(data, ctypes.POINTER(ctypes.c_int64))[: abs(num_of_rows)])]def _convert_millisecond_to_datetime(milli):try:if _priv_tz is None:return _datetime_epoch + timedelta(seconds=milli / 1000.0)return (_utc_datetime_epoch + timedelta(seconds=milli / 1000.0)).astimezone(_priv_tz)  # 万恶之源except OverflowError:# catch OverflowError and passprint("WARN: datetime overflow!")pass

4. 最终修改和效果

修改ts字段的类型从C_TIMESTAMP改为C_BIGINT,相关逻辑如下,
参数说明:cursor 即TDHelper().cursor()获得,sql = ‘select ts,val from table_1 ORDER BY ts desc limit 1’
最后效果,50w数据从10s优化到3s

    def test(cursor, sql)try:cursor.execute(sql)# ts字段的类型修改为bigintif cursor._fields[0]._type == FieldType.C_TIMESTAMP:cursor._fields[0]._type = FieldType.C_BIGINTreturn cursor.fetchall()except ProgrammingError as e:if e.msg == 'Fail to get table info, error: Table does not exist':# 只输出sql,不需要输出异常信息logger.warning('Table does not exist, sql [{}]'.format(sql))return []raise e

相关文章:

解决python从TD数据库取50w以上大量数据慢的问题

1.问题背景描述 python项目中的时序数据都存放在TD数据库中,数据是秒级存入的,当查询一周数据时将超过50w数据量,这是一次性获取全量数据到python程序很慢,全流程10秒以上,希望进行优化加速 2.排查 首先&#xff0c…...

游戏心理学Day21

玩家情绪与暴力攻击 情绪 情绪的分类 情绪是一种经常波动的东西,我们既体验过骄傲激动和开心,也体验过羞怯内疚和沮丧。我们的感受高度依赖于情境。研究者区分出至少三种途径来考察作为一种相对固定的人格特征的情绪,即为情感性&#xff0…...

接口测试基础 --- 什么是接口测试及其测试流程?

接口测试是软件测试中的一个重要部分,它主要用于验证和评估不同软件组件之间的通信和交互。接口测试的目标是确保不同的系统、模块或组件能够相互连接并正常工作。 接口测试流程可以分为以下几个步骤: 1.需求分析:首先,需要仔细…...

贪心+动归1

​​​​​​​​​​​​​​跳跃游戏 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则&#xff0…...

三星S20以上手机中的动态相片及其分解

三星S20以后的相机,相机拍出来的图片,用三星手机自带的“相册”打开之后,还会有“查看动态照片”的选项,点击之后就能查看拍照片时前后2秒左右的视频! 不知道这个功能是不是三星独有的。 这样得到的图片非常大。因为…...

一文了解HarmonyOSNEXT发布重点内容

华为在2024年6月21日的开发者大会上正式发布了HarmonyOS NEXT版,这是华为在操作系统领域的一次重大飞跃,标志着华为在构建全场景智能生态方面的卓越成就。HarmonyOS NEXT版不仅带来了全新的系统架构和性能提升,还首次将AI能力融入系统&#x…...

矩阵中严格递增的单元格数

题目链接:leetcode:矩阵中严格递增的单元格数 描述 给你一个下标从 1 开始、大小为 m x n 的整数矩阵 mat,你可以选择任一单元格作为 起始单元格 。 从起始单元格出发,你可以移动到 同一行或同一列 中的任何其他单元格,但前提是目…...

超参数调优-通用深度学习篇(上)

文章目录 深度学习超参数调优网格搜索示例一:网格搜索回归模型超参数示例二:Keras网格搜索 随机搜索贝叶斯搜索 超参数调优框架Optuna深度学习超参数优化框架nvidia nemo大模型超参数优化框架 参数调整理论: 黑盒优化:超参数优化…...

小程序中data-xx是用方式

data-sts"3" 是微信小程序中的一种数据绑定语法,用于在 WXML(小程序模板)中将自定义的数据绑定到页面元素上。让我详细解释一下: data-xx 的作用: data-xx 允许你在页面元素上自定义属性,以便在事…...

【2024德国工作】外国人在德国找工作是什么体验?

挺难的,德语应该是所有中国人的难点。大部分中国人进德国公司要么是做中国业务相关,要么是做技术领域的工程师。先讲讲人在中国怎么找德国的工作,顺便延申下,德国工作的真实体验,最后聊聊在今年的德国工作签证申请条件…...

Unity中获取数据的方法

Input和GetComponent 一、Input 1、Input类: 用于处理用户输入(如键盘、鼠标、触摸等)的静态类 2、作用: 允许你检查用户的输入状态。如某个键是否被按下,鼠标的位置,触摸的坐标等 3、实例 (1) 键盘…...

Java的死锁问题

Java中的死锁问题是指两个或多个线程互相持有对方所需的资源,导致它们在等待对方释放资源时永久地阻塞的情况。 死锁产生条件 死锁发生通常需要满足以下四个必要条件: 互斥条件:至少有一个资源是只能被一个线程持有的,如果其他…...

Unity 公用函数整理【二】

1、在规定时间时间内将一个值变化到另一个值&#xff0c;使用Mathf.Lerp实现 private float timer;[Tooltip("当前温度")]private float curTemp;[Tooltip("开始温度")]private float startTemp 20;private float maxTemp 100;/// <summary>/// 升…...

千年古城的味蕾传奇-平凉锅盔

在甘肃平凉这片古老而神秘的土地上&#xff0c;有一种美食历经岁月的洗礼&#xff0c;依然散发着独特的魅力&#xff0c;那便是平凉锅盔。平凉锅盔&#xff0c;那可是甘肃平凉的一张美食名片。它外表金黄&#xff0c;厚实饱满&#xff0c;就像一轮散发着诱人香气的金黄月亮。甘…...

微信小程序视频如何下载

一、工具准备 1、抓包工具Fiddler Download Fiddler Web Debugging Tool for Free by Telerik 2、VLC media player Download official VLC media player for Windows - VideoLAN 3、微信PC端 微信 Windows 版 二、开始抓包 1、打开Fiddler工具&#xff0c;设置修改如下…...

SVN 安装教程

SVN 安装教程 SVN&#xff08;Subversion&#xff09;是一个开源的版本控制系统&#xff0c;广泛用于软件开发和文档管理。本文将详细介绍如何在不同的操作系统上安装SVN&#xff0c;包括Windows、macOS和Linux。 Windows系统上的SVN安装 1. 下载SVN 访问SVN官方网站或Visu…...

HTML静态网页成品作业(HTML+CSS)—— 家乡山西介绍网页(3个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有6个页面。 二、作品演示 三、代…...

【抽代复习笔记】20-群(十四):定理6的补充证明及三道循环置换例题

例1&#xff1a;找出S3中所有不能和(123)交换的元。 解&#xff1a;因为 (123)(1) (1)(123) (123)&#xff0c;(123)(132) (132)(123) (1)&#xff0c;所以(1)、(132)和(123)均可以交换&#xff1b; 而(12)(123) (23)&#xff0c;(123)(12) (13)&#xff0c;故 (12)(12…...

【单片机毕业设计选题24018】-基于STM32和阿里云的农业大棚系统

系统功能: 系统分为手动和自动模式&#xff0c;上电默认为自动模式&#xff0c;自动模式下系统根据采集到的传感器值 自动控制&#xff0c;温度过低后自动开启加热&#xff0c;湿度过高后自动开启通风&#xff0c;光照过低后自动开启补 光&#xff0c;水位过低后自动开启水泵…...

【计算机毕业设计】​206校园顺路代送微信小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

LeetCode - 199. 二叉树的右视图

题目 199. 二叉树的右视图 - 力扣&#xff08;LeetCode&#xff09; 思路 右视图是指从树的右侧看&#xff0c;对于每一层&#xff0c;只能看到该层最右边的节点。实现思路是&#xff1a; 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

【多线程初阶】单例模式 指令重排序问题

文章目录 1.单例模式1)饿汉模式2)懒汉模式①.单线程版本②.多线程版本 2.分析单例模式里的线程安全问题1)饿汉模式2)懒汉模式懒汉模式是如何出现线程安全问题的 3.解决问题进一步优化加锁导致的执行效率优化预防内存可见性问题 4.解决指令重排序问题 1.单例模式 单例模式确保某…...