#python #postgresql #python-3.x #psycopg2
#python #postgresql #python-3.x #psycopg2
Вопрос:
В настоящее время я пытаюсь выполнить массовую вставку с помощью psycopy2, используя (copy_from). В настоящее время мой код приведен ниже. Я надеялся получить несколько советов о наиболее эффективной экранирующей функции и наилучшей практике экранирования значений, содержащих ограниченные символы. Я использую python3, строки поступают из mongodb.
Здесь приведены ссылки на символы с ограниченным доступом:http://www.postgresql.org/docs/9.2/static/sql-copy.html Как взято из документации: «Символы обратной косой черты () могут использоваться в КОПИРУЕМЫХ данных для заключения в кавычки символов данных, которые в противном случае могли бы использоваться в качестве разделителей строк или столбцов. В частности, перед следующими символами должна стоять обратная косая черта, если они появляются как часть значения столбца: сама обратная косая черта, перевод строки, возврат каретки и текущий символ-разделитель.»
def bulk_write(self, table, data, columns = None):
with psycopg2.connect(database = self.database,
user = self.user,
host = self.host,
password = self.password) as conn:
with conn.cursor() as cur:
cur.execute("SET TIME ZONE 'PDT8PST';")
cols_import = tuple(columns) if columns else None
data_tsv = 'n'.join(['t'.join(self.escape_copy_string(str(value)) for value in row) for row in data])
with open("test","w") as f:
f.write(data_tsv)
cur.copy_from(io.StringIO(data_tsv), table, columns=cols_import, null="None")
def escape_copy_string(self,s):
s = s.replace("\","\\").replace("n","\n").replace("r","\r").replace("t","\t")
return s
Ответ №1:
Вместо того, чтобы запускать ее вручную, я предлагаю использовать csv
модуль и использовать copy_from
в csv
режиме.
Данные не могут быть такими большими, если вы также используете для их обработки представления списка. У вас в спешке закончится оперативная память, если вы будете делать это с чем-то большим. Рассмотрите возможность использования цикла, который записывает каждую строку по мере ее выполнения.
Комментарии:
1. csv-модуль psycopg2 или csv-модуль python? Я загружаю данные пакетами. Спасибо!
2.
csv
Модуль as в Python от @BradRudermanpsycopg2
не имеетcsv
подмодуля.3. Спасибо за информацию, модуль CSV был хорошей идеей, однако повторное использование — нет. Если данные были слишком большими, я должен был разделить и выполнить массовые вставки. Циклическое выполнение было бы ужасным для производительности при начальных вставках
4. @BradRuderman Я был неясен. Я имел в виду, что вы могли бы выполнять цикл ввода и записывать каждую строку в
copy_from
поток, а не делать отдельные вставки.5. CSV-файл PSA python не будет корректно экранировать массивы на диалекте pgsql
Ответ №2:
После небольшого тестирования я думаю, что использование replace
является наиболее эффективным, по крайней мере, по сравнению с методом, основанным на регулярных выражениях:
import re
import timeit
string_rep = {
'\': '\\',
'r': '\r',
'n': '\n',
't': '\t',
}
string_pattern = re.compile('|'.join(re.escape(key) for key in string_rep))
def escape_re_sub(text):
return string_pattern.sub(lambda m: string_rep[m.group(0)], text)
def escape_str_replace(text):
return (
text.replace('\', '\\')
.replace('n', '\n')
.replace('r', '\r')
.replace('t', '\t')
)
string_no_escape = 'This is some bit of text that has no strings to replace'
time_re_sub = timeit.Timer(lambda: escape_re_sub(string_no_escape)).autorange()
print('no escape sub ', time_re_sub[0] / time_re_sub[1], 'iterations per second')
time_str_replace = timeit.Timer(lambda: escape_str_replace(string_no_escape)).autorange()
print('no escape replace', time_str_replace[0] / time_str_replace[1], 'iterations per second')
string_escape = 'This is somer \ bit of text nthat has tt some things to \t replace'
time_re_sub = timeit.Timer(lambda: escape_re_sub(string_escape)).autorange()
print('with escape sub ', time_re_sub[0] / time_re_sub[1], 'iterations per second')
time_str_replace = timeit.Timer(lambda: escape_str_replace(string_escape)).autorange()
print('with escape replace', time_str_replace[0] / time_str_replace[1], 'iterations per second')
для меня вывод:
no escape sub 1088292.3082792824 iterations per second
no escape replace 1310796.652683603 iterations per second
with escape sub 251530.53121228397 iterations per second
with escape replace 913308.513839589 iterations per second
Разница кажется особенно сильной, когда есть символы, которые нужно экранировать, но присутствует, когда экранирование не изменяет строки.