Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 通过二进制副本将包含PostGis字段的数据批量加载到PostgreSQL中 总结_Python_Postgresql_Binary_Postgis_Bulk Load - Fatal编程技术网

Python 通过二进制副本将包含PostGis字段的数据批量加载到PostgreSQL中 总结

Python 通过二进制副本将包含PostGis字段的数据批量加载到PostgreSQL中 总结,python,postgresql,binary,postgis,bulk-load,Python,Postgresql,Binary,Postgis,Bulk Load,我有一个带有PostgreSQL+PostGis数据库设置的应用程序,我正在尝试将大量行加载到它的一个表中。经过一些研究,二进制复制似乎是最好的方法,但经过无数次尝试和没完没了的调试,我一直无法实现数据的加载 此外,我注意到这种特定的方法有相当少的参考资料可用,因此我认为打开这个问题可以帮助未来的开发人员 背景 技术 应用程序后端是用Python 3编写的。目标数据库是本地托管的PostgreSQL v11数据库,扩展名为PostGIS 2.5.3。 正在使用psycopg2适配器将后端连接到数

我有一个带有PostgreSQL+PostGis数据库设置的应用程序,我正在尝试将大量行加载到它的一个表中。经过一些研究,二进制复制似乎是最好的方法,但经过无数次尝试和没完没了的调试,我一直无法实现数据的加载

此外,我注意到这种特定的方法有相当少的参考资料可用,因此我认为打开这个问题可以帮助未来的开发人员

背景 技术 应用程序后端是用Python 3编写的。目标数据库是本地托管的PostgreSQL v11数据库,扩展名为PostGIS 2.5.3。 正在使用psycopg2适配器将后端连接到数据库。 PPyGIS的ppygis3端口仅用于次要的替代尝试,如代码后面所示

资料 尽管由于保密原因,我无法共享此类数据的副本,但我可以描述数据由地理位置(lat-long格式)、时间戳和值组成。这些数据的数量大约为数百万

方法 我已经研究了解决这个问题的潜在方法,出于性能考虑,使用二进制格式的Postgres COPY命令似乎是最明智的方法

参考资料:

在查找参考资料时,发现了Mike T的这一非常有用的答案。不幸的是,它只涉及数字类型:

数据库表 表的简化模式类似于以下内容:

POINT TIMESTAMP value (Geography) (timestamp without zone) (real) 我猜这些问题要么与我的无知有关,要么与数据库没有识别/支持以这种方式插入地理字段有关。然而,令人惊讶的是,尝试使用如下所示的StringIO方法同样可以完美地工作

尝试使用StringIO进行复制 我还尝试了StringIO方法,我成功地使其工作,但其性能并不令人满意。请注意,在这种情况下,PostGis地理字段将以简化字符串形式(即“点(Y X)”传递给DB

con=psycopg2.connect(user=username,password=password,host=“localhost”,database=“test”)
cur=con.cursor()
#StringIO缓冲区类型
buffer=StringIO()
#虚拟值
lat=40.0
lon=10.0
日期=“2019-01-01 00:00:00”
point=“point({}{})”。格式(lon,lat)
值=555.555
缓冲区写入(点)
buffer.write('\t')
#读取时间戳
缓冲区写入(日期)
buffer.write('\t')
#参数读取
缓冲区写入(str(值))
buffer.write('\n')
#将偏移量重置为字节0
buffer.seek(0)
cur.copy_from(缓冲区,“testtable”,null='None')
con.commit()
当前关闭()
con.close()
尝试使用这两种方法之一(对WKB表示点的字符串表示进行编码)进行二进制复制会产生以下错误:

psycopg2.errors.InternalError\遇到无效的endian标志值。 上下文:复制testtable,第1行,列地理

预期/理想的结果自然是将数百万行成功加载到数据库中


如有任何意见和/或指导,将不胜感激

如果使用二进制模式,则需要提供内部二进制表示。这是存储在内存和磁盘上的值的格式

使用类型输入和输出功能在内部格式和外部格式之间转换数据

现在你可以预料,我不能责怪你,
geometry
的内部二进制格式是EWKB(它们的名字中都有“binary”)。但事实并非如此——EWKB是数据的文本表示。这就是你问题的原因


如果要使用内部二进制格式,则必须读取PostGIS源代码。我认为你不使用二进制cooy。我认为这是一个过早的优化。是什么让您认为您的代码比PostGIS的类型输入函数更高效?除此之外,,如果clent体系结构与服务器体系结构不同,您将面临危险:您能确定它们以相同的方式表示8字节浮点值吗?

我明白了-我将深入PostGIS文档/源代码,尝试找到地理字段的内部二进制表示形式,并对其进行更多拍摄。关于代码与输入函数效率的问题,我并不是怀疑输入函数的性能,而是因为插入的数量,根据我找到的参考资料,批量复制似乎是更好的选择。谢谢你的见解!您可以使用文本格式批量
复制
。没有必要为此而弄乱内部二进制表示。 CREATE TABLE testtable ( point GEOGRAPHY(Point), timestamp TIMESTAMP WITHOUT TIME ZONE, value REAL );