Python—如何构建和访问大量数据,而不消耗最大内存或使处理速度减慢到停止状态
我正在用Python编写一个脚本,用于在专有ESRI数据库表中控制数据。脚本的目的不是修改无效数据,而是通过csv文件向用户报告无效数据。我正在使用ESRI的ArcPy包使用ArcPy.SearchCursor访问每个记录。SearchCursor是访问ESRI格式的每条记录的唯一方法 当我滚动浏览表的每个记录时,我会进行多个QC检查以验证特定的业务逻辑。其中一项检查是在特定字段中查找重复数据。其中一个字段可能是几何体。为此,我为每个字段创建了一个空容器对象,并在检查每个记录时使用以下逻辑Python—如何构建和访问大量数据,而不消耗最大内存或使处理速度减慢到停止状态,python,memory,collections,persistence,containers,Python,Memory,Collections,Persistence,Containers,我正在用Python编写一个脚本,用于在专有ESRI数据库表中控制数据。脚本的目的不是修改无效数据,而是通过csv文件向用户报告无效数据。我正在使用ESRI的ArcPy包使用ArcPy.SearchCursor访问每个记录。SearchCursor是访问ESRI格式的每条记录的唯一方法 当我滚动浏览表的每个记录时,我会进行多个QC检查以验证特定的业务逻辑。其中一项检查是在特定字段中查找重复数据。其中一个字段可能是几何体。为此,我为每个字段创建了一个空容器对象,并在检查每个记录时使用以下逻辑 fo
for field in dupCheckFields:
if row.getValue(field) in fieldValues[field]: dupValues.add(row.getValue(idField))
else: fieldValues[field].append(row.getValue(field))
上面的代码是我使用的基本逻辑的一个示例。我遇到的麻烦是,这些表中的每个表可能包含5000条到1000万条记录。我要么是内存不足,要么是演出停滞不前
我尝试了以下容器类型:集合、列表、字典、ZODB+BList和Shelve
对于内存中的类型(集合、列表、字典),这个过程在开始时非常快,但随着它的发展,它会变得慢得多。如果我们使用这些类型,如果表中有许多记录,我将耗尽内存。对于持久性数据类型,我不会耗尽内存,但处理它需要很长时间
我只需要在脚本运行时使用数据,任何持久数据文件都将在完成后删除
问题:在访问数据时,是否有更好的容器类型可以提供大量数据的低内存存储,而不会带来很大的性能成本
系统:Win7 64位,Python 2.6.5 32位,4gb RAM
提前感谢你的帮助
编辑:
SQLite代码示例:
import sqlite3, os, arcpy, timeit
fc = r"path\to\feature\class"
# test feature class was in ESRI ArcSDE format and contained "." characters separating database name, owner, and feature class name
fcName = fc.split(".")[-1]
# convert ESRI data types to SQLite data types
dataTypes = {"String":"text","Guid":"text","Double":"real","SmallInteger":"integer"}
fields = [(field.name,dataTypes[field.type]) for field in arcpy.ListFields(fc) if field.name != arcpy.Describe(fc).OIDFieldName]
# SQL string to create table in SQLite with same schema as feature class
createTableString = """create table %s(%s,primary key(%s))""" % (fcName,",\n".join('%s %s' % field for field in fields),fields[0][0])
# SQL string to insert data into SQLite table
insertString = """insert into %s values(%s)""" % (fcName, ",".join(["?" for i in xrange(len(fields))]))
# location to save SQLite database
loc = r'C:\TEMPORARY_QC_DATA'
def createDB():
conn = sqlite3.connect(os.path.join(loc,'database.db'))
cur = conn.cursor()
cur.execute(createTableString)
conn.commit()
rows = arcpy.SearchCursor(fc)
i = 0
for row in rows:
try:
cur.execute(insertString, [row.getValue(field[0]) for field in fields])
if i % 10000 == 0:
print i, "records"
conn.commit()
i += 1
except sqlite3.IntegrityError: pass
print i, "records"
t1 = timeit.Timer("createDB()","from __main__ import createDB")
print t1.timeit(1)
不幸的是,我无法共享我在该代码中使用的测试数据,但它是一个ESRI ArcSDE地理数据库表,包含约10个字段和约7 mil记录
我试图用
timeit
来确定这个过程花了多长时间,但是经过2个小时的处理,只完成了120000条记录。如果将哈希存储在(压缩的)文件中,您可以对它们进行流式处理,以比较哈希以查找重复项。流式处理通常具有非常低的内存要求-您可以设置所需的缓冲区,例如,每个哈希记录一行。权衡通常是时间,特别是如果添加压缩,但是如果按照某些标准对文件进行排序,则可以遍历未压缩的流以更快地比较记录。如果将哈希存储在(压缩的)文件中,则可以通过流来比较哈希以查找重复项。流式处理通常具有非常低的内存要求-您可以设置所需的缓冲区,例如,每个哈希记录一行。权衡通常是时间,特别是如果添加压缩,但如果按照某些标准对文件进行排序,则可以遍历未压缩的流以更快地比较记录。我想我应该评估在SQLite数据库中存储持久数据(如已知字段VAL和计数)。当然,这是内存使用和性能之间的权衡
如果您使用支持并发访问的持久性机制,那么您可能可以使用以下方法并行处理数据。完成后,可以从数据库生成错误摘要。我想我应该评估在SQLite数据库中存储持久数据(如已知字段VAL和计数)。当然,这是内存使用和性能之间的权衡
如果您使用支持并发访问的持久性机制,那么您可能可以使用以下方法并行处理数据。一旦完成,就可以从数据库中生成错误摘要。我不太清楚文件中的哈希和流式处理是什么意思。这是否仅仅意味着将数据保存在预定义组织中的txt文件中,并简单地通过txt来查找特定条目?我已经研究过哈希,这似乎是一个可能的解决方案。但是,一旦识别出重复的散列,如何找到原始数据向用户报告?在散列和标识键(例如,行号或ID)之间保留一个排序的关联数组。当您在两个表之间找到哈希匹配时,您将有记录键来执行所需的查找。您可以使用JSON或其他序列化格式。如果你使用JSON,它是一个文本文件,你可以压缩(如果磁盘空间很充裕的话)并解压缩到一个你可以遍历的流,一个一个散列。我不太清楚你所说的文件中的散列和流是什么意思。这是否仅仅意味着将数据保存在预定义组织中的txt文件中,并简单地通过txt来查找特定条目?我已经研究过哈希,这似乎是一个可能的解决方案。但是,一旦识别出重复的散列,如何找到原始数据向用户报告?在散列和标识键(例如,行号或ID)之间保留一个排序的关联数组。当您在两个表之间找到哈希匹配时,您将有记录键来执行所需的查找。您可以使用JSON或其他序列化格式。如果您使用JSON,它是一个文本文件,您可以对其进行压缩(如果磁盘空间非常宝贵),然后将其解压为一个可以遍历的流,逐个散列。感谢您的回复。我尝试过SQLite,这是我所尝试过的所有性能中最慢的。我尝试了一个包含30000条记录的数据集,在我不得不停止之前花了2个多小时才得到14000条记录。我意识到ESRI SearchCursor是迭代表中记录的一种相当慢的方法,但只是迭代