Это правильный способ пакетного upsert в psycopg2? - PullRequest
0 голосов
/ 27 сентября 2018

Мне нужно написать скрипт, который берет набор строк из БД PostgreSQL, вычисляет несколько значений для каждой строки и переносит результаты обратно в БД (существующую таблицу).Есть сложность - мне нужно иметь возможность программно управлять именами таблиц и столбцов.

Мое текущее решение выглядит так:

import psycopg2
from psycopg2.extensions import AsIs, quote_ident
import psycopg2.extras

def upsert_estimated_values(con, table_name, timestamps, column_names, value_list, page_size=1000):
  # con is a psycopg2 connection
  # timestamps is a list of timestamps (which are the index in the DB table)
  # column_names is a list of columns in the DB
  # value_list is a list of tuples where each tuple
  #  contains a value for every column in column_names

  sql = 'INSERT INTO %s (timestamp_utc, ' + ', '.join('%s' for _ in range(len(column_names))) \
        + ')\n VALUES (%s, ' + ', '.join('%s' for _ in range(len(column_names))) \
        + ')\nON CONFLICT (timestamp_utc) DO UPDATE\n SET ' \
        + ', '.join('%s = %s' for _ in range(len(column_names))) \
        + ';'

  with con.cursor() as cur:
    tbl = AsIs(quote_ident(table_name, cur))
    cols = [AsIs(quote_ident(col, cur)) for col in column_names]

    data = []
    for vs, ts in zip(value_list, timestamps):
      data.append((
        tbl,
        *cols,
        ts,
        *vs,
        *itertools.chain(*zip(cols, vs))
      ))

    psycopg2.extras.execute_batch(
      cur, sql, page_size=page_size, argslist=data
    )

  con.commit()

Насколько я понимаю psycopg2функция execute_batch создает одну длинную инструкцию SQL для минимизации связи с БД.Но что происходит в этом конкретном случае?Я передаю имя таблицы и имена столбцов в каждой записи argslist, и я не уверен, что это хорошая идея.

В настоящее время этот переход занимает примерно в 8 раз больше времени, чем получение данных из БД.Любые советы?

...