Использование pythons oursql для хранения данных в базе данных mysql сканируется. Зачем? - PullRequest
1 голос
/ 07 июля 2011

Я анализирую огромный (я имею в виду действительно huuuuge) XML-файл. Он содержит несколько миллионов статей, подобных этой:

<article key="journals/cgf/HaeglerWAGM10" mdate="2010-11-12">
  <author>Simon Haegler</author>
  <author>Peter Wonka</author>
  <author>Stefan Müller Arisona</author>
  <author>Luc J. Van Gool</author>
  <author>Pascal Müller</author>
  <title>Grammar-based Encoding of Facades.</title>
  <pages>1479-1487</pages>
  <year>2010</year>
  <volume>29</volume>
  <journal>Comput. Graph. Forum</journal>
  <number>4</number>
  <ee>http://dx.doi.org/10.1111/j.1467-8659.2010.01745.x</ee>
  <url>db/journals/cgf/cgf29.html#HaeglerWAGM10</url>
</article>

Я просматриваю файл и анализирую эти статьи по lxml. Если я запускаю код без сохранения элементов в своей базе данных (комментируя populate_database(), он делает около 1000 записей в течение ~ 3 секунд. Но если я активирую хранилище (uncomment populate_database () `), он делает около 10 записей в секунду Это нормально? Я помню, как раз анализировал файл один раз, и база данных не была таким узким местом. Но у меня был другой подход ... (просматривая мои файлы, чтобы найти его ...)

Вот функция, которая заставляет мою голову болеть. Я прокомментировал эти три cursor.executes, и код снова начал работать. Так что кажется, что что-то не так с MySQL или что-то не так с запуском (мои догадки noobisch). Любой совет?

def add_paper(paper, cursor):
    questionmarks = str(('?',)*len(paper)).replace("'", "")
    # The line above: produces (?, ?, ?, ... ,?) for oursql query
    keys, values = paper.keys(), paper.values()
    keys = str(tuple(keys)).replace("'", "")
    # The line above: produces (mdate, title, ... date, some_key)
    query_paper = '''INSERT INTO dblp2.papers {0} VALUES {1};'''.\
                    format(keys, questionmarks)
    values = tuple(v.encode('utf8') for v in values)
    cursor.execute(query_paper, values)
    paper_id = cursor.lastrowid
    return paper_id

def populate_database(paper, authors, cursor):
    paper_id = add_paper(paper, cursor)
    query_author ="""INSERT INTO dblp2.authors
                     (name) VALUES (?) ON DUPLICATE KEY UPDATE
                     id=LAST_INSERT_ID(id)"""
    query_link_table = "INSERT INTO dblp2.author_paper
                        (author_id, paper_id) VALUES (?, ?)"
    for author in authors:
        cursor.execute(query_author, (author.encode('utf8'),))
        author_id = cursor.lastrowid
        cursor.execute(query_link_table, (author_id, paper_id))

Я добавил вывод профилирования из cProfile:

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
1    0.001    0.001   15.666   15.666 <string>:1(<module>)
1    0.000    0.000    0.000    0.000 __init__.py:49(normalize_encoding)
1    0.000    0.000    0.000    0.000 __init__.py:71(search_function)
510    0.002    0.000    0.002    0.000 _elementpath.py:222(_build_path_iterator)
510    0.005    0.000    0.008    0.000 _elementpath.py:260(iterfind)
408    0.005    0.000    0.017    0.000 _elementpath.py:270(find)
102    0.003    0.000    0.011    0.000 _elementpath.py:285(findall)
10    0.000    0.000    0.000    0.000 _elementpath.py:70(xpath_tokenizer)
5    0.000    0.000    0.000    0.000 _elementpath.py:85(prepare_child)
987    0.009    0.000    0.013    0.000 _elementpath.py:87(select)
1    0.000    0.000    0.000    0.000 codecs.py:77(__new__)
1    0.000    0.000    0.000    0.000 utf_8.py:15(decode)
1    0.000    0.000    0.000    0.000 utf_8.py:33(getregentry)
102    0.008    0.000    5.601    0.055 xml2db.py:25(add_paper)
680    0.003    0.000    0.006    0.000 xml2db.py:31(<genexpr>)
102    0.005    0.000   15.468    0.152 xml2db.py:36(populate_database)
477    0.003    0.000    0.013    0.000 xml2db.py:45(clean_parse)
101    0.002    0.000    0.005    0.000 xml2db.py:52(clear_element)
103    0.019    0.000    0.024    0.000 xml2db.py:57(extract_paper_elements)
1    0.017    0.017   15.557   15.557 xml2db.py:63(fast_iter)
1    0.004    0.004   15.665   15.665 xml2db.py:89(main)
1    0.000    0.000    0.000    0.000 {__import__}
1    0.000    0.000    0.000    0.000 {_codecs.utf_8_decode}
1    0.000    0.000    0.000    0.000 {built-in method __new__ of type object at 0x8245fc0}
5    0.000    0.000    0.000    0.000 {built-in method findall}
1    0.000    0.000    0.000    0.000 {hasattr}
2    0.000    0.000    0.000    0.000 {isinstance}
515    0.001    0.000    0.001    0.000 {iter}
107    0.000    0.000    0.000    0.000 {len}
477    0.010    0.000    0.010    0.000 {lxml.etree.strip_tags}
5    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
101    0.002    0.000    0.002    0.000 {method 'clear' of 'lxml.etree._Element' objects}
1    0.000    0.000    0.000    0.000 {method 'cursor' of 'oursql.Connection' objects}
1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
778    0.007    0.000    0.007    0.000 {method 'encode' of 'str' objects}
5    0.000    0.000    0.000    0.000 {method 'encode' of 'unicode' objects}
516   15.544    0.030   15.544    0.030 {method 'execute' of 'oursql.Cursor' objects}
408    0.004    0.000    0.023    0.000 {method 'find' of 'lxml.etree._Element' objects}
102    0.001    0.000    0.012    0.000 {method 'findall' of 'lxml.etree._Element' objects}
103    0.001    0.000    0.001    0.000 {method 'format' of 'str' objects}
2    0.000    0.000    0.000    0.000 {method 'get' of 'dict' objects}
204    0.001    0.000    0.001    0.000 {method 'get' of 'lxml.etree._Element' objects}
100    0.000    0.000    0.000    0.000 {method 'getparent' of 'lxml.etree._Element' objects}
201    0.001    0.000    0.001    0.000 {method 'getprevious' of 'lxml.etree._Element' objects}
510    0.004    0.000    0.004    0.000 {method 'iterchildren' of 'lxml.etree._Element' objects}
1    0.000    0.000    0.000    0.000 {method 'join' of 'str' objects}
102    0.000    0.000    0.000    0.000 {method 'keys' of 'dict' objects}
204    0.001    0.000    0.001    0.000 {method 'replace' of 'str' objects}
1    0.000    0.000    0.000    0.000 {method 'split' of 'str' objects}
1    0.000    0.000    0.000    0.000 {method 'translate' of 'str' objects}
102    0.000    0.000    0.000    0.000 {method 'values' of 'dict' objects}
2    0.000    0.000    0.000    0.000 {time.time}

Ответы [ 2 ]

2 голосов
/ 06 августа 2012

Мне кажется, вы запускаете целую кучу отдельных insert заявлений.Включение регистрации в mysql db должно показать вам несколько операторов вроде этого:

....
INSERT INTO dblp2.authors (name) VALUES (a) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)
INSERT INTO dblp2.authors (name) VALUES (b) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)
INSERT INTO dblp2.authors (name) VALUES (c) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)
INSERT INTO dblp2.authors (name) VALUES (d) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)
INSERT INTO dblp2.authors (name) VALUES (e) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)
INSERT INTO dblp2.authors (name) VALUES (f) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)
....

Вы хотите выполнить либо оператор paramaterized/multiple insert, либо упаковать все в файл csv и выполнить bulk insert.

Массовая вставка выполняется быстрее и поддерживает замену повторяющихся строк ( проверьте документы ).Если вы хотите истинное обновление, используйте несколько вставок или попробуйте эту идею временной таблицы .

Несколько операторов вставки будут выглядеть примерно так:

cursor.execute(query_author, [author.encode('utf8') for author in authors])

, которая должнавведите в журнал следующие записи:

INSERT INTO dblp2.authors (name) VALUES (a,b,c,d,e,f) ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)

У вас могут возникнуть проблемы с идентификаторами для второй таблицы.

0 голосов
/ 07 июля 2011

В каждой базе данных есть команда EXPLAIN для определения планов выполнения.

Кроме того: в Python есть профилировщик для определения того, какой код медленный.

Итак, во-первых: вы делаете свой анализ и, если у вас ничего не получается, вы возвращаетесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...