Как мне ограничить использование памяти 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)
Другие вопросы по тегам