SQLAlchemy Идеальный дизайн для фиксации - PullRequest
1 голос
/ 20 апреля 2011

У меня есть серверная часть Pylons, работающая на SQLAlchemy.У меня есть сценарий, который читает дерево файлов XML с HTTP-сервера (он загружает XML X, а затем загружает дочерние элементы X, а затем выполняет итерацию дочерних элементов и т. Д. В рекурсии).Каждый xml-файл представляет модель SQLAlchemy.

Проблема в том, что у меня есть тысячи этих XML (иногда 5000, иногда 26000).Мне удалось оптимизировать процесс загрузки с помощью пула HTTP, но я не могу думать о лучшем подходе в отношении передачи моделей в БД.Каждый раз, когда загружается XML-файл, я создаю для него объект orm и добавляю его в сеанс.

Проблема 1: некоторые XML-файлы будут существовать несколько раз в дереве, поэтому я проверяю, нет ли дубликатов вставки.Является ли проверка в моем коде оптимальной, или я должен хранить индексируемую коллекцию на стороне и использовать ее для проверки на дубликаты?

Проблема 2: мой автокоммит установлен на False, потому что я не хочу фиксировать на каждомдобавить (не потому, что его плохой дизайн, а из-за производительности).Но я также не хочу перебирать все дерево тысяч категорий без фиксации вообще.Для этого я создал постоянное число, по которому мой код фиксирует данные.Это хороший подход?Что было бы хорошим номером для этого?Возможно, важно упомянуть, что я не знаю заранее, сколько xml я просматриваю.

Вот как выглядит мой псевдокод (игнорируйте синтаксические ошибки):

count = 0
COMMIT_EVERY = 50

def recursion(parent):
    global count, COMMIT_EVERY
    pool = get_http_connection_pool(...)
    sub_xmls = get_sub_xmls(pool, parent)

    if sub_xmls == None:
        return

    for sub_xml in sub_xmls:
        orm_obj = MyObj(sub_xml)

        duplicate = Session.query(MyObj).filter(MyObj.id == orm_obj.id).first()
        if not duplicate:
            Session.add(orm_obj)
            count = count + 1
            if count % COMMIT_EVERY == 0:
                Session.commit()            
            recursion(orm_obj.id)

recursion(0)

1 Ответ

0 голосов
/ 20 апреля 2011

Я думаю, вам следует добавить UniqueConstraint в таблицу моделей и забыть о запросе дубликатов, а затем просто:

try:
    Session.add(orm_obj)
except IntegrityError:
    log.warn("A duplicate found") #or just pass

Хорошее COMMIT_EVERY значение зависит от вас, протестируйте различные значения, характеристики профиля, оцените риски, я думаю, что никто не может сказать вам число с таким количеством информации.

P.S:.

if sub_xmls is None:
    return

EDIT:

Sqlalchemy может быть настроен на вставку при коммите , поэтому вы получаете IntegrityError только при коммите или просто каждый раз, когда делаете добавление, читаете документацию или спрашиваете SA group , я ничем не могу вам помочь.

Или используйте sql напрямую, а также увеличьте производительность: например, это вызовет исключение для каждого дубликата (синтаксис MySQL, проверьте вашу собственную СУБД):

conn = Session.connection()
try:
    curs = conn.execute("INSERT INTO table (id, value) VALUES (%s, %s)", (id, value))
except IntegrityError:
    log.warn("A duplicate found: id=%s" % id)
finally:
    #remember to close cursor
    curs.close() 
...