Я пишу скрипт на Python для данных контроля качества в собственной таблице базы данных ESRI. Цель сценария не в том, чтобы изменить недопустимые данные, а просто в том, чтобы сообщить пользователю о недопустимых данных через файл 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 до 10 миллионов записей. У меня либо не хватает памяти, либо спектакль останавливается.
Я пробовал следующие типы контейнеров: наборы, списки, словари, ZODB + BList и Shelve.
С типами в памяти (наборы, списки, словари) процесс запускается очень быстро в начале, но по мере продвижения он становится намного медленнее. Мы эти типы, если у меня будет много записей в таблице, мне не хватит памяти. С постоянными типами данных у меня не хватает памяти, но обработка занимает очень много времени.
Мне нужны только данные во время работы скрипта, и все постоянные файлы данных будут удалены после завершения.
Вопрос. Существует ли лучший тип контейнера для хранения большого объема данных с малым объемом памяти без значительного снижения производительности при доступе к данным?
Система: Win7 64-разрядная, Python 2.6.5 32-разрядная, 4 ГБ ОЗУ
Заранее спасибо за помощь.
EDIT:
Пример кода 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 миллионов записей.
Я пытался использовать timeit
, чтобы определить, сколько времени занял этот процесс, однако после 2 часов обработки было завершено только 120 000 записей.