【问题标题】:Read Large data from database table in pandas or dask从 pandas 或 dask 中的数据库表中读取大数据
【发布时间】:2025-12-03 14:55:01
【问题描述】:

我想将包含 10+ gb 数据的表中的所有数据读取到数据框中。当我尝试使用read_sql 阅读时,出现内存过载错误。我想对该数据进行一些处理并用新数据更新表。我怎样才能有效地做到这一点。我的电脑有 26gb 的内存,但数据最大为 11gb,但我仍然遇到内存过载错误。

在 Dask 中花费了很多时间。下面是代码。

import dateparser
import dask.dataframe as dd
import numpy as np

df = dd.read_sql_table('fbo_xml_json_raw_data', index_col='id', uri='postgresql://postgres:passwordk@address:5432/database')
def make_year(data):
    if data and data.isdigit() and int(data) >= 0:
        data = '20' + data
    elif data and data.isdigit() and int(data) < 0:
        data = '19' + data
    return data

def response_date(data):
    if data and data.isdigit() and int(data[-2:]) >= 0:
        data = data[:-2] + '20' + data[-2:]
    elif data and data.isdigit() and int(data[-2:]) < 0:
        data = data[:-2] + '19' + data[-2:]
    if data and dateparser.parse(data):
        return dateparser.parse(data).date().strftime('%Y-%m-%d')

def parse_date(data):
    if data and dateparser.parse(data):
        return dateparser.parse(data).date().strftime('%Y-%m-%d')

df.ARCHDATE = df.ARCHDATE.apply(parse_date)
df.YEAR = df.YEAR.apply(make_year)
df.DATE = df.DATE + df.YEAR
df.DATE = df.DATE.apply(parse_date)
df.RESPDATE = df.RESPDATE.apply(response_date)

【问题讨论】:

  • 在处理之前,像len(df)这样的简单操作是否有效?请注意,您要求 Dask 根据前 5 行的字节大小在此处猜测分区大小 - 您可能希望更具体地了解其他 kwargs。

标签: python pandas performance bigdata dask


【解决方案1】:

请看这里:https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_sql.html

看到chunksize arg 了吗?您可以对数据进行分块,使其适合内存。

它将返回一个块读取对象,以便您可以在块上迭代地应用操作。

您也可以合并multiprocessing

这将增加一层复杂性,因为您不再处理 DataFrame 本身,而是处理包含块的对象。

由于您使用的是Dask,因此“应该”适用。我不确定 Dask 如何处理分块。我已经有一段时间没有接触到 Pandas/Dask 的兼容性了。

【讨论】:

    【解决方案2】:

    主要问题似乎是pd.Series.apply 的独占使用。但是apply 只是一个逐行 Python 级循环。在 Pandas Dask 中会很慢。对于性能关键代码,您应该支持按列操作。

    事实上,dask.dataframe 支持 Pandas API 的 useful subset。以下是几个例子:-

    避免字符串操作

    先将数据转换为数值类型;然后执行矢量化操作。例如:

    dd['YEAR'] = dd['YEAR'].astype(int)
    dd['YEAR'] = dd['YEAR'].mask(dd['YEAR'] >= 0, 20)
    dd['YEAR'] = dd['YEAR'].mask(dd['YEAR'] < 0, 19)
    

    转换为日期时间

    如果您有适当格式的datetime 字符串:

    df['ARCHDATE'] = df['ARCHDATE'].astype('M8[us]')
    

    另见dask dataframe how to convert column to to_datetime

    【讨论】: