psycopg2

时间:2016-06-30 12:25:40

标签: python postgresql pandas

我有一个从4个数据库中读取的进程,每个数据库有4个表。我正在将这些数据整合到1个postgres数据库中,总共有4个表。 (每个原始的4个数据库都有相同的4个表需要合并)。

我现在使用pandas的方式。我一次从所有4个数据库中读取一个表,将数据连接成一个数据帧,然后我使用to_sql将其保存在我的postgres数据库中。然后我循环到剩下的数据库,为其他表做同样的事情。

我的问题是速度。我的一个表每个日期大约有1-2个行,所以完成将数据写入postgres需要大约5,000到6,000秒。将它写入.csv文件然后在pgadmin中使用COPY FROM会更快。

这是我目前的代码。请注意,有一些函数调用,但它基本上只是引用表名。我也有一些基本的日志记录,但这不是太必要。我正在为源数据库添加一个列,但这是必需的。我从实际字符串的字段中剥离.0但是pandas也将它们视为浮点数,并且我用0填充空白整数并确保列实际上是int类型。

def query_database(table, table_name, query_date):
    df_list = []
    log_list = []
    for db in ['NJ', 'NJ2', 'LA', 'NA']:
        start_time = time.clock()
        query_timestamp = dt.datetime.now(pytz.timezone('UTC')).strftime('%Y-%m-%d %H:%M:%S')
        engine_name = '{}{}{}{}'.format(connection_type, server_name, '/', db)
        print('Accessing {} from {}'.format((select_database(db)[0][table]), engine_name))
        engine = create_engine(engine_name)
        df = pd.read_sql_query(query.format(select_database(db)[0][table]), engine, params={query_date})
        query_end = time.clock() - start_time
        df['source_database'] = db
        df['insert_date_utc'] = query_timestamp
        df['row_count'] = df.shape[0]
        df['column_count'] = df.shape[1]
        df['query_time'] = round(query_end, 0)
        df['maximum_id'] = df['Id'].max()
        df['minimum_id'] = df['Id'].min()
        df['source_table'] = table_dict.get(table)
        log = df[['insert_date_utc', 'row_date', 'source_database', 'source_table', 'row_count', 'column_count', 'query_time', 'maximum_id', 'minimum_id']].copy()
        df.drop(['row_count', 'column_count', 'query_time', 'maximum_id', 'minimum_id', 'source_table'], inplace=True, axis=1)
        df_list.append(df)
        log_list.append(log)
    log = pd.concat(log_list)
    log.drop_duplicates(subset=['row_date', 'source_database', 'source_table'], inplace=True, keep='last')
    result = pd.concat(df_list)
    result.drop_duplicates('Id', inplace=True)
    cols = [i.strip() for i in (create_columns(select_database(db)[0][table]))]
    result = result[cols]
    print('Creating string columns for {}'.format(table_name))
    for col in modify_str_cols(select_database(db)[0][table]):
        create_string(result, col)
    print('Creating integer columns for {}'.format(table_name))
    for col in modify_int_cols(select_database(db)[0][table]):
        create_int(result, col)
    log.to_sql('raw_query_log', cms_dtypes.pg_engine, index=False, if_exists='append', dtype=cms_dtypes.log_dtypes)
    print('Inserting {} data into PostgreSQL'.format(table_name))
    result.to_sql(create_table(select_database(db)[0][table]), cms_dtypes.pg_engine, index=False, if_exists='append', chunksize=50000, dtype=create_dtypes(select_database(db)[0][table]))

如何将COPY TO和COPY FROM插入其中以加快速度?我应该只写.csv文件然后循环这些文件还是我可以从内存复制到我的postgres?

1 个答案:

答案 0 :(得分:3)

psycopg2提供了许多与copy相关的特定api。如果要使用csv,则必须使用copy_expert(允许您指定完整的copy语句)。

通常当我这样做时,我使用了copy_expert()和一个类似文件的对象,它遍历磁盘上的文件。这似乎运作得相当好。

据说,在你的情况下,我认为copy_tocopy_from是更好的匹配,因为它只是postgres到postgres转移。注意这些使用PostgreSQL的复制输出/输入语法而不是csv(如果你想使用csv,你必须使用copy_expert

注意在决定如何做之前,您需要注意:

copy_to从类似文件的对象复制到类文件对象(例如StringIO)和copy_from / copy_expert文件。如果您想使用熊猫数据框,您将不得不考虑这一点并创建类似文件的对象或使用csv以及StringIOcopy_expert来生成内存中的csv和加载。