Большие CSV и Parquet: как обработать данные без сюрпризов
Большой CSV легко перегружает память, а неудачно записанный Parquet замедляет чтение и усложняет поддержку схемы. Показываем, как выбрать инструмент, задать типы данных, конвертировать файлы и проверить результат.

Если CSV больше доступной оперативной памяти, обычное чтение целиком может завершиться ошибкой или вытеснить из памяти другие процессы. Для обработки больших файлов выбирайте потоковое чтение или запрос к файлу, заранее задавайте типы столбцов и проверяйте результат после записи. Ниже — три рабочих подхода и примеры для Python 3.10, DuckDB 1.2.2 и PyArrow 19.0.1.
Сначала решите, что именно нужно сделать
CSV — текстовый формат: значения нужно разобрать, а типы данных нередко приходится определять при чтении. Parquet хранит данные колонками и схему вместе с ними. Это удобно для повторных запросов по нескольким полям, но не отменяет проверку типов и качества данных.
Перед запуском проверьте, что на диске хватит места для выходного файла и временных данных, а у процесса есть права на чтение источника и запись результата. Если файл приходит из внешней системы, выясните разделитель, кодировку, формат дат, правила для пустых значений и экранирование кавычек. Ошибка в любом из этих параметров может дать не падение, а неверные данные.
Row group — группа строк внутри Parquet-файла: при чтении колонок и фильтрации движок может работать не со всем файлом сразу. Слишком мелкие группы увеличивают накладные расходы, а слишком крупные могут сделать чтение отдельных частей менее удобным.
Три подхода — три разных компромисса
| Подход | Когда выбрать | Цена и риск |
|---|---|---|
| DuckDB: запрос к файлу и запись результата | Нужно фильтровать, агрегировать или преобразовать большие CSV и Parquet без загрузки всей таблицы в pandas. | Придётся освоить SQL и явно описать спорные типы. Сложные операции могут потребовать временного места на диске. |
| PyArrow: чтение батчами и ParquetWriter | Нужен контроль над схемой, размером порций и записью файла из Python-кода. | Больше кода и ответственности за обработку каждой порции. Потоковый CSV-чтитель PyArrow не использует многопоточность. |
| pandas: read_csv с chunksize | У вас уже есть обработка на pandas и её удобно выполнять для порций строк. | Для записи всех порций в один Parquet потребуется отдельный writer, например из PyArrow. Если вызвать обычную запись в файл на каждом шаге без такого writer, можно перезаписать предыдущую порцию. |
Если задача сводится к преобразованию, фильтрации или агрегации файла, начните с DuckDB. Если обработка должна включать произвольную логику Python между чтением и записью, берите PyArrow. pandas выбирайте, когда его DataFrame-операции уже нужны дальше по процессу, а не просто потому, что этот инструмент знаком.
Главная ошибка при работе с большими файлами — считать, что правильное расширение решит проблему памяти. Сначала определите формат и схему, затем выбирайте способ чтения.
DuckDB: конвертация и фильтрация одним запросом
В примере ниже входные столбцы сначала читаются как строки, а затем преобразуются явно. Это снижает риск, что автоматическое определение типов примет редкое значение за обычный текст или неверно распознает столбец. Код рассчитан на Python 3.10 и DuckDB 1.2.2; пути и имена столбцов замените на свои.
import duckdb
connection = duckdb.connect()
connection.execute("""
COPY (
SELECT
CAST(event_time AS TIMESTAMP) AS event_time,
CAST(user_id AS BIGINT) AS user_id,
CAST(amount AS DOUBLE) AS amount
FROM read_csv(
'events.csv',
header = true,
delim = ',',
columns = {
'event_time': 'VARCHAR',
'user_id': 'VARCHAR',
'amount': 'VARCHAR'
}
)
WHERE user_id IS NOT NULL
) TO 'events.parquet' (
FORMAT PARQUET,
COMPRESSION ZSTD,
ROW_GROUP_SIZE 100000
)
""")
connection.close()
Явные преобразования здесь сделаны намеренно: если в числовом поле встретится некорректное значение, запрос должен обратить на него внимание, а не молча превратить ошибку в правдоподобный результат. До запуска проверьте, что заголовки и разделитель совпадают с реальным CSV. Если разделитель или кавычки настроены неверно, сначала исправьте параметры чтения.
Размер группы в примере — стартовая настройка, а не универсальный оптимум. Не увеличивайте его ради абстрактной скорости: сравните время чтения и размер файла на характерных запросах вашего приложения. При сортировке и агрегации DuckDB может обращаться к временному диску; его нужно учитывать отдельно от места под итоговый Parquet.
PyArrow: обработка CSV порциями
Когда между чтением и записью нужна логика Python, используйте потоковый читатель и записывайте каждый батч в один Parquet-файл. В версии PyArrow 19.0.1 типы ниже заданы явно: без этого вывод типа по начальным данным может не подойти редким значениям в конце CSV.
import pyarrow as pa
import pyarrow.csv as csv
import pyarrow.parquet as pq
reader = csv.open_csv(
'events.csv',
read_options=csv.ReadOptions(block_size=1 << 20),
convert_options=csv.ConvertOptions(
column_types={
'event_time': pa.timestamp('us'),
'user_id': pa.int64(),
'amount': pa.float64(),
},
strings_can_be_null=True,
),
)
with pq.ParquetWriter(
'events.parquet',
reader.schema,
compression='zstd',
) as writer:
for batch in reader:
writer.write_batch(batch)
Здесь размер блока чтения указан в байтах; это не обещание, что каждый батч займёт ровно столько оперативной памяти. Потребление зависит от содержимого и типов столбцов. Начните с этого значения, а затем измерьте пиковую память на файле, похожем на производственный. Внутри цикла можно фильтровать или преобразовывать батчи, но схема записываемых данных должна оставаться совместимой с той, которую передали ParquetWriter.
Что ломается чаще всего
- Часть строк не проходит преобразование типа. Проверьте реальные значения в проблемном столбце: даты могут иметь разные форматы, а числа — лишние пробелы или символы. Не меняйте все значения на пустые, пока не выясните, допустимы ли такие записи для потребителя.
- Столбцы «съехали» или разделились неверно. Сверьте разделитель, кавычки, кодировку и наличие запятых внутри текстовых полей. Подайте небольшой образец в выбранный читатель с теми же параметрами, что и полный файл.
- Программа всё равно упирается в память. Проверьте, что код действительно читает файл порциями, а не собирает все батчи в список или один общий DataFrame. Для DuckDB проверьте объём доступного временного диска и стоимость операций сортировки и группировки.
- Итоговый файл есть, но данные потерялись. Сравните число строк до и после преобразования, проверьте пропуски и диапазоны значений. Сделайте контрольное чтение Parquet и запустите запрос, похожий на тот, который будет использоваться в работе.
- Файлов Parquet стало слишком много. Запись отдельного файла для каждой маленькой порции усложняет чтение и обслуживание. Если нужны отдельные файлы по датам или другим ключам, определите разумный размер разделов и проверьте, как их будет читать целевая система.
Как проверить результат и выбрать следующий шаг
Успешное завершение записи подтверждает только то, что инструмент создал файл. Перед передачей данных дальше проверьте схему, количество строк, пропуски в важных полях и несколько значений из начала и конца источника. Для преобразования с фильтром отдельно посчитайте, сколько строк должно было отсеяться.
Начните с небольшого фрагмента, затем запустите полный процесс на копии файла и замерьте пиковое потребление памяти, время обработки и объём временного диска. После этого протестируйте реальные запросы к Parquet: выбирайте только нужные колонки и измеряйте фильтры, которые будут использоваться регулярно. Инвалидация и обновление уже созданных файлов — отдельная задача; здесь речь только о чтении, преобразовании и проверке результата.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: DuckDB: чтение CSV, Apache Arrow: CSV и Parquet в Python
Частые вопросы
Можно ли читать Parquet через pandas, если файл не помещается в память?
Что делать, если в CSV встречаются неожиданные значения?
Подойдут ли примеры для других версий DuckDB и PyArrow?
Почему Parquet-файл может не ускорить запрос?
Что проверить перед запуском в проде?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.