循序渐进丨使用 Python 向 MogDB 数据库批量操作数据的方法

当我们有时候需要向数据库里批量插入数据,或者批量导出数据时,除了使用传统的gsql copy命令,也可以通过Python的驱动psycopg2进行批量操作。本文介绍了使用psycopg2里的executemany、copy_from、copy_to、copy_expert等方式来批量操作 MogDB 数据库里的数据的方法。

outside_default.png

安装psycopg2驱动

适配 MogDB 的psycopg2可以从以下链接下载:

https://www.mogdb.io/downloads/psycopg2/all

下载之前,先确定所用的Python版本:

python3 --version
Python 3.7.9

目前只支持Python 3.6以上版本:

8760cbf461f04f2ff00afb4b5007940e.png

下载之后,将文件上传到运行程序的主机上,并运行以下命令:

python3 -m pip install psycopg*.whl

当然,如果该主机可以联通互联网,也可以直接从以下链接获取下载地址:https://www.mogdb.io/downloads/psycopg2/all 

396e6482dc40bab9c1342474cbf6f5f9.png

不用真正下载,而是直接运行(其中url对应实际Python版本的url):

python3 -m pip install https://cdn-mogdb.enmotech.com/drivers/python/psycopg2-whl/5.0.0.3/psycopg2-5.0.0.3-cp37-cp37m-linux_aarch64.whl

数据库端创建测试用户和测试表:

gsql
create user pytest sysadmin password 'Enmotech@123';
create table test_psycopg2(id int,source varchar(32), create_time date,name varchar(32),val int);

outside_default.png

建立连接并创建cursor对象

Python中:

import psycopg2
conn=psycopg2.connect(database="postgres",user="pytest",password="Test@123",host="127.0.0.1",port=26000)
cur=conn.cursor()
conn.close()

参数就不用介绍含义了,一目了然。

outside_default.png

使用execute进行逐条插入

execute可用于逐条插入,它是cursor中的一个方法,接收的参数为语句+一个可索引的列表,列表中每一列对应语句中的 %s.

cursor.execute(sqltext,var_List)

假设现在我们需要往数据库中插入10000条随机数据,可以循环调用execute:

import psycopg2
import datetime
import random
import timeconn=psycopg2.connect(database="postgres",user="pytest",password="Test@123",host="127.0.0.1",port=26000)
cur=conn.cursor() 
currtime=datetime.datetime.now()
data1=[(id,"execute",(currtime+datetime.timedelta(minutes=id)).strftime('%Y-%m-%d %H:%M:%S'),"name"+str(id),random.randint(0,100000)) for id in range(1,10001)];start=time.perf_counter()
for row in data1:cur.execute ("insert into test_psycopg2 values(%s,%s,%s,%s,%s)",row); #此处有5个占位符,对应的row中有5列end=time.perf_counter();
print(f"use execute to insert 10000 rows, cost {int((end-start)*1000)} ms");
conn.commit()

26002c3dbeab15a5a6eefa1ef49e76ad.png

outside_default.png

使用executemany进行批量插入

executemany可用于批量插入,它是cursor中的一个方法,接收的参数为语句+一个嵌套了可索引的列表的列表,列表中每一行对应语句中的 %s.

cursor.executemany(sqltext,var_List)

假设现在我们需要往数据库中插入10000条随机数据,可以调用一次executemany:

import psycopg2
import datetime
import random
import time
conn=psycopg2.connect(database="postgres",user="pytest",password="Test@123",host="127.0.0.1",port=26000)
cur=conn.cursor()
currtime=datetime.datetime.now()
data2=[(id,"executemany",(currtime+datetime.timedelta(minutes=id)).strftime('%Y-%m-%d %H:%M:%S'),"name"+str(id),random.randint(0,100000)) for id in range(1,10001)];
start=time.perf_counter()
cur.executemany("insert into test_psycopg2 values(%s,%s,%s,%s,%s)",data2);
end=time.perf_counter();
print(f"use executemany to insert 10000 rows, cost {int((end-start)*1000)} ms");
conn.commit()

14df9a64ed6c39a5276e5b2ebf6b4b3a.png

从执行时间看executemany和execute相差无几,并没有使用类似于JDBC驱动中的批量绑定功能。

outside_default.png

使用copy_from(文件)从文件中批量插入

无论是execute还是executemany,性能都不够理想。如果对性能有要求,批量插入的时候,应该使用copy相关的方法,如copy_from。

copy_from接收多个参数,主要是前面的4个参数:

copy_from(input_file, table_name, sep, columns)

其中第一个参数设计上是文件句柄,但是也可以用其他带有read()和readline()方法的对象来代替。

第三个参数则是分隔符,因为使用copy时,需要自己先按行把数据拼好的,列之间用分隔符来分隔,通常可以使用"tab"或者",". 当然,这需要考虑你的数据中会不会包含这两个字符,避免二义性。

第四个参数则是列名的列表,如果不提供,则是所有列,但是要注意列顺序。

假设现在我们需要往数据库中插入10000条随机数据,可以先生成一个文件,再调用copy_from(文件):

import psycopg2
import datetime
import random
import time
from io import StringIO
conn=psycopg2.connect(database="postgres",user="pytest",password="Enmotech@123",host="127.0.0.1",port=26000)
cur=conn.cursor()
currtime=datetime.datetime.now()
tmpfile=open("test_psycopg2_from.csv","w");
filesize=0
for id in range(1,10001):filesize=filesize+tmpfile.write(f"{id},copy_from_File,{(currtime+datetime.timedelta(minutes=id)).strftime('%Y-%m-%d %H:%M:%S')},name{id},{random.randint(0,100000)}\n")tmpfile.close()tmpfile2=open("test_psycopg2_from.csv","r");start=time.perf_counter()
cur.copy_from(tmpfile2,"test_psycopg2",sep=",");
end=time.perf_counter();
print(f"use copy_from(File) to insert 10000 rows, cost {int((end-start)*1000)} ms");
conn.commit()
tmpfile.close()

af73baac17c8d4ce6238a9581fd93715.png

19ms,相比execute和executemany,有百倍的提升。

outside_default.png

使用copy_from(StringIO)进行批量插入

对于在内存中处理的数据,专门放到文件系统再取出来显然没有必要,因此,copy_from第一参数可以使用StringIO这个模块来模拟内存中的一个类文件对象(关于StringIO,限于篇幅,不展开解释)。

假设现在我们需要往数据库中插入10000条随机数据,可以把记录按行写到StringIO对象,再调用copy_from(StringIO):

import psycopg2
import datetime
import random
import time
from io import StringIO
conn=psycopg2.connect(database="postgres",user="pytest",password="Enmotech@123",host="127.0.0.1",port=26000)
cur=conn.cursor()
currtime=datetime.datetime.now()
tmpfile=StringIO("");
filesize=0
for id in range(1,10001):filesize=filesize+tmpfile.write(f"{id},copy_from_StringIO,{(currtime+datetime.timedelta(minutes=id)).strftime('%Y-%m-%d %H:%M:%S')},name{id},{random.randint(0,100000)}\n")tmpfile.seek(0)
start=time.perf_counter()
cur.copy_from(tmpfile,"test_psycopg2",sep=",");
end=time.perf_counter();
print(f"use copy_from(StringIO) to insert 10000 rows, cost {int((end-start)*1000)} ms");
conn.commit()

2b577bd0d528a3a9e840bf49f4de288d.jpeg

同样19ms。

这里面需要注意的是,StringIO写完了(write)之后,必须调用seek(0)回到文件头,否则,相当于从文件末端开始,是无法完成copy的操作的。

outside_default.png

使用copy_to(文件)导出到文件

有进就有出,pyscopg2里面也支持把表copy到文件中。

copy_to接收多个参数,主要是前面的4个参数。

copy_to(out_file, table_name, sep, columns)

其中第一个参数设计上是文件句柄,但是也可以用其他带有write()方法的对象来代替。

第三个参数则是分隔符。

第四个参数则是列名的列表,如果不提供,则是所有列。

假设现在我们把表导出成本地文件,可以直接调用copy_to(文件):

import psycopg2
import time
conn=psycopg2.connect(database="postgres",user="pytest",password="Enmotech@123",host="127.0.0.1",port=26000)
cur=conn.cursor()
currtime=datetime.datetime.now()
tmpfile=open("test_psycopg2_to.csv","w");
start=time.perf_counter()
cur.copy_to(tmpfile,"test_psycopg2",sep=",");
end=time.perf_counter();
print(f"use copy_to(File) to dump tables, cost {int((end-start)*1000)} ms");
tmpfile.close()

aed001013d8a9217e774bcf5d218f2de.png

58ms,不过表里面目前已经有4万条记录。

outside_default.png

使用copy_to(StringIO)导出到内存对象

同理,也可以把表导出到StringIO的内存对象中,调用copy_to(StringIO),如下所示:

import psycopg2
import time
from io import StringIO
conn=psycopg2.connect(database="postgres",user="pytest",password="Enmotech@123",host="127.0.0.1",port=26000)
cur=conn.cursor()
currtime=datetime.datetime.now()
tmpfile=StringIO("");
start=time.perf_counter()
cur.copy_to(tmpfile,"test_psycopg2",sep=",");
end=time.perf_counter();
print(f"use copy_to(StringIO) to dump tables, cost {int((end-start)*1000)} ms");
print(f"filelength:{len(tmpfile.getvalue())}")
conn.commit()
tmpfile.close()

db138d9fcf2554110fbec412120ecb2b.png

outside_default.png

使用copy_expert()进行复杂copy操作

gsql的copy命令其实提供了很多复杂的功能,但显然copy_from/copy_to无法全部做到,比如,从表中根据条件过滤出需要的数据并进行copy。

因此,除了copy_from/copy_to, pyscopg2提供了更专业的copy_expert函数,更接近原始的copy命令,它接收两个参数,第一个是SQL语句,第二个是类文件句柄, 你可以认为是把它嫁接给了gsql里面的STDIN/STDOUT。

copy_export(sql,file_handle)

假设现在我们需要把之前的source为"copy_from_File"的部分取出来,然后,对表的数据做一定运算,还希望带表header, 可以调用copy_expert,进行精细调控:

import psycopg2
import time
conn=psycopg2.connect(database="postgres",user="pytest",password="Enmotech@123",host="127.0.0.1",port=26000)
cur=conn.cursor()
currtime=datetime.datetime.now()
tmpfile=open("test_psycopg2_copy_expert.csv","w");
start=time.perf_counter()
cur.copy_expert("copy (select *,sqrt(val) val2 from test_psycopg2 test_psycopg2 where source = 'copy_from_File') to STDIN with(format 'csv', header on ) ",tmpfile);
end=time.perf_counter();
print(f"use copy_expert() to dump tables, cost {int((end-start)*1000)} ms");
conn.commit()
tmpfile.close()

f6da111643db536a8aa64397ebfc7400.png

看看导出效果,没问题:

81ba0d4363eecca0c134569f8077af58.png

outside_default.png

参考文档

  • https://docs.mogdb.io/zh/mogdb/v5.0/1-psycopg-based-development

  • https://www.psycopg.org/docs/cursor.html

关于作者

罗海雄,云和恩墨数据库研发架构师,性能优化专家,2012年 ITPUB 全国SQL大赛冠军。他拥有超十年企业级系统设计与优化经验,对SQL优化理解尤其深入,曾服务于甲骨文公司。

f03719b383c77a81f33e6c4955117909.gif

数据驱动,成就未来,云和恩墨,不负所托!


云和恩墨创立于2011年,是业界领先的“智能的数据技术提供商”。公司总部位于北京,在国内外35个地区设有本地办公室并开展业务。

云和恩墨以“数据驱动,成就未来”为使命,致力于将创新的数据技术产品和解决方案带给全球的企业和组织,帮助客户构建安全、高效、敏捷且经济的数据环境,持续增强客户在数据洞察和决策上的竞争优势,实现数据驱动的业务创新和升级发展。

自成立以来,云和恩墨专注于数据技术领域,根据不断变化的市场需求,创新研发了系列软件产品,涵盖数据库、数据库存储、数据库云管和数据智能分析等领域。这些产品已经在集团型、大中型、高成长型客户以及行业云场景中得到广泛应用,证明了我们的技术和商业竞争力,展现了公司在数据技术端到端解决方案方面的优势。

在云化、数字化和智能化的时代背景下,云和恩墨始终以正和多赢为目标,感恩每一位客户和合作伙伴的信任与支持,“利他先行”,坚持投入于数据技术核心能力,为构建数据驱动的智能未来而不懈努力。

我们期待与您携手,共同探索数据力量,迎接智能未来。

5dc8bf55ca34ffbfa93bf5dfad3641ab.gif

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

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

相关文章

[C++][算法基础]求a的b次方模p的值(快速幂)

给定 n 组 ,对于每组数据,求出 的值。 输入格式 第一行包含整数 n。 接下来 n 行,每行包含三个整数 。 输出格式 对于每组数据,输出一个结果,表示 的值。 每个结果占一行。 数据范围 1≤n≤100000, 1≤≤2 …

移动Web学习09-响应式布局bootstrap案例开发

3、综合案例-AlloyTeam移动全端 准备工作 HTML 结构 <title>腾讯全端</title> <link rel"shortcut icon" href"favicon.ico" type"image/x-icon"> <!-- 层叠性&#xff1a;咱们的css 要 层叠 框架的 --> <link rel&…

匿名函数与gorm中的Transaction事务方法

整理下go中的匿名函数&#xff0c;项目中很多地方都在用。 1、函数类型的变量 Go中&#xff0c;函数也是一种数据类型。定义一个函数&#xff0c;把这个函数赋值给一个变量&#xff0c;这个变量就是函数类型的变量&#xff0c;用这个变量等价于直接调函数&#xff1a; packa…

数字阅览室解决方案

一、方案概述 “数字阅览室”概念一经提出&#xff0c;就得到了广泛的关注&#xff0c;纷纷组织力量进行探讨、研究和开发&#xff0c;进行各种模型的试验。随着数字地球概念、技术、应用领域的发展&#xff0c;数字阅览室已成为数字地球家庭的成员&#xff0c;为信息高速公路…

高频前端面试题汇总之JavaScript篇(上)

一、数据类型 1. JavaScript有哪些数据类型&#xff0c;它们的区别&#xff1f; JavaScript共有八种数据类型&#xff0c;分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。 其中 Symbol 和 BigInt 是ES6 中新增的数据类型&#xff1a; Symbol 代…

如何免费申请长期HTTPS证书?

长期HTTPS证书申请步骤&#xff1a; 第一步&#xff1a;确定证书类型 根据你的网站需求&#xff0c;选一种适合的HTTPS证书。一般有这几种&#xff1a; - 域名型&#xff08;DV&#xff09;证书&#xff1a;最基础&#xff0c;验证你对域名的所有权&#xff0c;适合个人网站或…

构建有序链表,有序链表的归并,反转链表

本次将对于构建有序链表&#xff0c;有序链表的归并&#xff0c;反转链表&#xff0c;进行一一介绍和代码分享。 首先是一些链表中的基本的函数&#xff1a; Node* creatList() {Node* headNode (Node*)malloc(sizeof(Node));assert(headNode);headNode->next NULL;retu…

海信电视:中国游戏的影像“黑神话”

【潮汐商业评论/文】 《西游记》最后一难中&#xff0c;通天河老鼋回唐三藏“何时才能修成正果”&#xff0c;《黑神话&#xff1a;悟空》也曾面临这个拷问&#xff0c;如今海信电视与它正在共同回答这个命题。 自2020年发布预告片震动行业后&#xff0c;这部游戏就承载着太多…

Shader 渐变屏幕

渐变 前置工作&#xff0c;创建缓冲&#xff0c;对顶点着色器传递顶点数据 function main() {var canvas document.getElementById(webgl);var gl getWebGLContext(canvas);if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) returnvar n initVertexBuffers(gl); }fu…

HBM 发展史与前景(持续更新)

主页&#xff1a; 元存储博客 文章目录 前言1. JEDEC 规范2. HBM 发展历程3. HBM 应用场景4. HBM 市场前景5. 发展挑战 翻译自&#xff1a; https://namu.wiki/w/HBM 前言 NVIDIA H2 上的 HBM100e。 1. JEDEC 规范 2. HBM 发展历程 HBM技术曾被视为一种噱头&#xff0c;因为它…

PSAvatar:一种基于点的可变形形状模型,用于3D高斯溅射的实时头部化身创建

PSAvatar: A Point-based Morphable Shape Model for Real-Time Head Avatar Creation with 3D Gaussian Splatting PSAvatar&#xff1a;一种基于点的可变形形状模型&#xff0c;用于3D高斯溅射的实时头部化身创建 Zhongyuan Zhao1,2, Zhenyu Bao1,2, Qing Li1, Guoping Qiu3,…

工时管理软件全攻略,8大关键因素一网打尽!

工时管理往往与项目管理与人力资源结合起来&#xff0c;考察每位员工的绩效指标。可以说&#xff0c;工时管理软件至关重要。什么叫工时管理&#xff1f;考虑到工时管理软件的八个关键要素包含&#xff1a;功能、使用体验、集成能力、扩展性、成本效率、安全隐私、技术支持、用…

javaWeb项目-智慧餐厅点餐管理系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、JavaScript Java…

【漏洞复现】泛微e-cology ProcessOverRequestByXml接口存在任意文件读取漏洞

漏洞描述 泛微e-cology依托全新的设计理念,全新的管理思想。 为中大型组织创建全新的高效协同办公环境。 智能语音办公,简化软件操作界面。 身份认证、电子签名、电子签章、数据存证让合同全程数字化。泛微e-cology ProcessOverRequestByXml接口存在任意文件读取漏洞 免责声…

虚拟机磁盘剩余空间不足

VMware 弹出提示&#xff1a; 对文件“E:\Virtual Machine\CentOS 7 1810 的克隆 (2)\CentOS 7 1810-cl1.vmdk”的操作失败。 如果该文件位于远程文件系统上&#xff0c;请确保网络连接以及该磁盘所在的服务器正常工作。如果该文件位于可移动介质中&#xff0c;请重新连接该介…

从零自制docker-11-【pivotRoot切换实现文件系统隔离】

文章目录 busyboxdocker run -d busybox topcontainerId(docker ps --filter "ancestorbusybox:latest"|grep -v IMAGE|awk {print $1})docker export -o busybox.tar $containerId or sudo docker export 09bbf421d93f > ./busybox.tar tar -xvf busybox.tar -C …

nvm下载的node没有npm

nvm下载的node没有npm 相信大家最近可能发现自己使用的nvm下载nodejs没有npm了。 会出现这种情况&#xff1a; C:\Users\89121>nvm install 15 Downloading node.js version 15.14.0 (64-bit)... Complete Downloading npm version 7.7.6... Download failed. Rolling Bac…

如何查找一篇英文文献的源代码?(论文中没有源代码链接时)如何查找一篇论文的实现代码从而复现论文?

有两个网址&#xff0c;从这两个网址里面能找到论文相关代码&#xff0c;但不确定是不是人家论文里的源代码&#xff0c;但是根据论文实在找不到的情况下&#xff0c;只能试试这两个网址了 1. https://paperswithcode.com/ 2. https://www.catalyzex.com/

【QT进阶】Qt Web混合编程之CMake VS2019编译并使用QCefView(图文并茂超详细版本)

往期回顾 【QT进阶】Qt Web混合编程之CEF、QCefView简单介绍-CSDN博客 【QT进阶】Qt Web混合编程之VS2019 CEF的编译与使用&#xff08;图文并茂超详细介绍&#xff09;-CSDN博客【QT进阶】Qt Web混合编程之QWebEngineView基本用法-CSDN博客【QT进阶】Qt Web混合编程之VS2019 C…

Geoserver的RESTful接口使用

概述 GeoServer提供了一个RESTful接口&#xff0c;客户端可以通过该接口获取有关实例的信息并进行配置更改。REST接口使用简单的HTTP调用&#xff0c;通过客户端就可以配置GeoServer&#xff0c;而无需使用Web管理接口。 Geoserver中的关系 工作区、数据源、图层、图层组以及…