Быстрая вставка панд DataFrame в Postgres DB с помощью psycopg2 - PullRequest
6 голосов
/ 22 марта 2012

Я пытаюсь вставить pandas DataFrame в базу данных Postgresql (9.1) наиболее эффективным способом (с использованием Python 2.7).
Использование «cursor.execute_many" очень медленно, поэтому«DataFrame.to_csv (buffer, ...)» вместе с «copy_from».
Я нашел уже много!более быстрое решение в Интернете (http://eatthedots.blogspot.de/2008/08/faking-read-support-for-psycopgs.html), которое я адаптировал для работы с пандами.
Мой код можно найти ниже.
Мой вопрос заключается в том, является ли метод этого связанного вопроса (с использованием "copy from stdin withдвоичный файл ") может быть легко переведен для работы с DataFrames, и если это будет намного быстрее.
Используйте двоичную таблицу COPY FROM с psycopg2
К сожалению, моих навыков в Python недостаточно для понимания реализацииэтого подхода.
Это мой подход:


import psycopg2
import connectDB # this is simply a module that returns a connection to the db
from datetime import datetime

class ReadFaker:
    """
    This could be extended to include the index column optionally. Right now the index
    is not inserted
    """
    def __init__(self, data):
        self.iter = data.itertuples()

    def readline(self, size=None):
        try:
            line = self.iter.next()[1:]  # element 0 is the index
            row = '\t'.join(x.encode('utf8') if isinstance(x, unicode) else str(x) for x in line) + '\n'
        # in my case all strings in line are unicode objects.
        except StopIteration:
            return ''
        else:
            return row

    read = readline

def insert(df, table, con=None, columns = None):

    time1 = datetime.now()
    close_con = False
    if not con:
        try:
            con = connectDB.getCon()   ###dbLoader returns a connection with my settings
            close_con = True
        except psycopg2.Error, e:
            print e.pgerror
            print e.pgcode
            return "failed"
    inserted_rows = df.shape[0]
    data = ReadFaker(df)

    try:
        curs = con.cursor()
        print 'inserting %s entries into %s ...' % (inserted_rows, table)
        if columns is not None:
            curs.copy_from(data, table, null='nan', columns=[col for col in columns])
        else:
            curs.copy_from(data, table, null='nan')
        con.commit()
        curs.close()
        if close_con:
            con.close()
    except psycopg2.Error, e:
        print e.pgerror
        print e.pgcode
        con.rollback()
        if close_con:
            con.close()
        return "failed"

    time2 = datetime.now()
    print time2 - time1
    return inserted_rows

Ответы [ 2 ]

1 голос
/ 09 сентября 2013

У пандас-фреймов данных теперь есть метод .to_sql. Postgresql пока не поддерживается, но для него есть патч, который выглядит так, как будто он работает. Смотрите выпуски здесь и здесь .

0 голосов
/ 28 мая 2012

Я не тестировал производительность, но, возможно, вы можете использовать что-то вроде этого:

  1. Итерация по строкам DataFrame с получением строки, представляющей строку (см. Ниже)
  2. Преобразовать эту итерацию в поток, используя, например, Python: Преобразовать итерацию в поток? Наконец, используйте psycopg copy_from в этом потоке.

Для эффективного получения строк в DataFrame используйте что-то вроде:

    def r(df):
            for idx, row in df.iterrows():
                    yield ','.join(map(str, row))
...