Python - 如何构建和访问大量数据而不用尽内存或减慢处理速度

标签 python memory collections persistence containers

我正在用 Python 编写一个脚本来对专有 ESRI 数据库表中的 QC 数据进行处理。该脚本的目的不是修改无效数据,而只是通过csv文件向用户报告无效数据。我正在使用 ESRI 的 ArcPy 包通过 arcpy.SearchCursor 访问每个单独的记录。 SearchCursor 是访问 ESRI 格式的每个单独记录的唯一方法。

当我滚动浏览表格的每条记录时,我会进行多次 QC 检查以验证特定的业务逻辑。其中一项检查是在特定字段中查找重复数据。这些领域之一可能是几何学。我通过为每个字段创建一个空容器对象来完成此操作,并在检查每条记录时使用以下逻辑。

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内存

预先感谢您的帮助。

编辑:

示例 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 个字段和大约。 700 万条记录。

我尝试使用 timeit 来确定这个过程花费了多长时间,但是在处理了 2 个小时之后,只完成了 120,000 条记录。

最佳答案

如果您将散列存储在(压缩的)文件中,您可以流式传输它们以比较散列以查找重复项。流式传输通常对内存的要求非常低——您可以设置所需的缓冲区,例如,每个散列记录一行。权衡通常是时间,特别是如果您添加压缩,但如果您按某些标准对文件进行排序,那么您可能能够遍历未压缩的流以更快地比较记录。

关于Python - 如何构建和访问大量数据而不用尽内存或减慢处理速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7836672/

相关文章:

python - 将字符串转换为单词列表?

C#解压内存中的.EXE文件

c - 查找进程内存中未使用的内存

memory - 检查正在运行的程序中的可用 RAM 量

python - try-except-else 语句的用例

python - 使用 Jinja2 遍历 Python 字典

java - 如何在为不包含重复项的项目指定特定逻辑的同时连接两个 Java 流?

java - 对集合进行排序的最佳方法?

Java LinkedBlockingQueue 实现

Python:使用 subprocess.Popen 加载 python 脚本时传递 sys.argv