Как мне ограничить использование памяти duckdb в R?
У меня есть несколько больших R data.frames, которые я хотел бы поместить в локальную базу данных duckdb. Проблема, с которой я столкнулся, заключается в том, что duckdb, похоже, загружает все в память, хотя я указываю файл в качестве местоположения.
Кроме того, мне неясно, как правильно установить соединение (поэтому я не уверен, связано ли это с этим). Я пытался:
duckdrv <- duckdb(dbdir="dt.db", read_only=FALSE)
dkCon <- dbConnect(drv=duckdrv)
а также:
duckdrv <- duckdb()
dkCon <- dbConnect(drv=duckdrv, dbdir="dt.db", read_only=FALSE)
Оба работают нормально, то есть я могу создавать таблицы, использовать dbWriteTable, выполнять запросы и т. Д. Однако использование памяти очень велико (примерно того же размера, что и data.frames). Я думаю, что где-то читал, что duckdb по умолчанию использует определенный% доступной памяти, что не будет работать для меня, потому что система, которую я использую, является общим ресурсом. Я также хочу запускать несколько запросов параллельно, что еще больше увеличит использование памяти.
Я пробовал это:
dbExecute(dkCon, "PRAGMA memory_limit='1GB';")
но, похоже, это не имеет значения, даже если я закрою соединение, выключу экземпляр и снова подключусь.
Кто-нибудь знает, как я могу исправить эту проблему? RSQLite также временно использует большое количество памяти, когда я записываю данные в таблицу, но затем он возвращается в нормальное состояние, и если я открываю соединение только для чтения, это вообще не проблема. Я хотел бы, чтобы duckdb работал, потому что я думаю, что запросы должны быть намного быстрее. Любая помощь будет оценена по достоинству!
2 ответа
Ограничение памяти можно установить с помощью инструкции PRAGMA или SET в DuckDB. По умолчанию пределом является 75% оперативной памяти.
con.execute("PRAGMA memory_limit='200MB'")
ИЛИ
con.execute("SET memory_limit='200MB'")
Я могу подтвердить, что этот лимит работает. Однако это не жесткое ограничение, и иногда оно может быть превышено в зависимости от объема данных, формата данных, которые вы запрашиваете (например, паркет из s3), типа запроса - определенных ограничений или ограничений вокруг него на данный момент.
Ниже приведен один из примеров, когда объем данных в формате обычного текста (csv) составлял около 4,23 ГБ. Эти данные были сначала загружены в DuckDB, а затем были запущены некоторые SQL-запросы, установивmemory_limit='200MB'
. На приведенном ниже снимке экрана показана максимальная записанная память, используемая скриптом py.
Ваш подход правильный - использованиеmemory_limit
прагма, но вы использовали устаревшую версию.
Например, используя DuckDb версии 0.5.1:
library("DBI")
con = dbConnect(duckdb::duckdb(), dbdir="my-db.duckdb")
dbExecute(conn = con, paste0("PRAGMA memory_limit='500MB'"))
dbGetQuery(conn = con, "PRAGMA version")
dbExecute(con, "CREATE TABLE gen AS SELECT * FROM 'gen1GB.csv'")
dbGetQuery(conn = con, "select count(*) from gen")
Это выводит для меня:
library_version source_id
1 0.5.1 7c111322d
count_star()
1 1e+08
Использование памяти менее 500 МБ. На MacOs можно проверить с помощью:
ps axu | grep 'lib\/R' | awk '{print $6 " " $11}'
464768 /usr/local/Cellar/r/4.2.1_4/lib/R/bin/exec/R
Вы можете создать тестовый CSV-файл, используя:
import numpy as np
import pandas as pd
rng = np.random.default_rng()
df = pd.DataFrame(rng.integers(0, 100, size=(100000000, 4)), columns=list('ABCD'))
df.to_csv('gen1GB.csv', index=False)