Мне нужно вставлять несколько тысяч строк в Redshift несколько раз в день.Но я не могу использовать массовую вставку из S3 по административным причинам.Какой самый быстрый способ?
Подробности:
Есть 3 способа (я вижу), чтобы вставить строки в таблицу в Amazon Redshift из R:
- Строка за строкой вставки запроса.Каждая строка вставляется как собственный
INSERT VALUES
запрос - Запрос на вставку нескольких строк: то же, что и 1, но для каждого запроса вставляется несколько записей.Размер ограничен либо количеством строк, либо ограничением максимального размера SQL-запроса в 16 МБ.
- Массовая вставка из AWS S3, Dynamo или EMR.
Каждый вышеприведенный подход примерно на порядок быстрее предыдущего.Я бы хотел использовать массовую вставку для создания или обновления таблиц, но наша организация приняла решение по безопасности и административному решению не разрешать бизнес-пользователям загружать или выгружать данные в S3.Так что я не могу использовать пакет redshiftTools для загрузки файлов.
Я могу сделать номер 1 выше, используя RODBC::sqlSave
.Что медленно, но делает работу ... в конце концов.
Я бы предпочел что-то вроде sqlSave
, который вставляет несколько строк данных одновременно.Но не настолько, чтобы преодолеть пределы строки / размера для красного смещения.Это легко для простых структур данных, но обобщенная функция, которая будет обрабатывать целые числа, символы, даты и т. Д., Была бы идеальной, поскольку я делаю это не только с одной таблицей.Поэтому я открыл исходный код для sqlSave
и начал накатывать свою собственную функцию для построения многострочных вставок, которые бы разбивали данные на 1000 кусочков, строили и выполняли запрос для каждого чанка.
Но я перестал спрашивать здесь, было ли это уже сделано?Есть ли способ лучше?У меня такое ощущение, что, возможно, один из других пакетов SQL для R имеет функцию, которая делает что-то вроде этого.Однако, когда я ищу все, я нахожу, что другие люди имеют такую же проблему .
Есть какие-нибудь советы?
ОБНОВЛЕНИЕ 1
Благодаря некоторым подсказкам я исследовал переключатель fast=TRUE
в RODBC::sqlSave
.Документация звучит так, как будто это то, что я ищу:
быстро: логично.Если false, запишите данные по строке за раз.Если это правда, используйте параметризованный запрос INSERT INTO или UPDATE, чтобы записать все данные за одну операцию.
Так что я решил проверить это.Поэтому я создал небольшой фрейм данных с 10 записями и 2 столбцами:
df <- data.frame(a=rnorm(10), b=sample(letters, 10, replace=TRUE),
stringsAsFactors = FALSE)
Затем я использовал benchmark
, чтобы рассчитать время выполнения 5 репликаций:
benchmark( sqlSave(dbhandle, df, tablename = 'jal_test1', append=TRUE, fast=TRUE), replications = 5)
# test replications elapsed relative user.self sys.self user.child sys.child
# 1 sqlSave(dbhandle, df, tablename = "jal_test1", append = TRUE, fast = TRUE) 5 512.59 1 0.08 0.03 NA NA
benchmark( sqlSave(dbhandle, df, tablename = 'jal_test1', append=TRUE, fast=FALSE), replications = 5)
# test replications elapsed relative user.self sys.self user.child sys.child
# 1 sqlSave(dbhandle, df, tablename = "jal_test1", append = TRUE, fast = FALSE) 5 264.37 1 0.08 0.02 NA NA
Это немного сложночитать, но в итоге:
fast=TRUE
заняло 512 секунд fast=FALSE
заняло 264 секунды
с 25 записями, время идетдо:
fast=TRUE
заняло 1208 секунд fast=FALSE
заняло 604 секунды
Что для меня абсолютно бессмысленно.
Обновление 2
Я попробовал переключатель test=TRUE
, думая, что он покажет мне, что происходит, но я не могу понять, что это вообще делает ... Однако поворот verbose=TRUE
помог мне понять, что fast=TRUE
не делает то, что я думал, что сделал.Кажется, что используется замена, но не делает одну большую вставку.Это все еще делает вставки nrow(df)
:
> df <- data.frame(a=rnorm(5), b=sample(letters, 5, replace=TRUE), stringsAsFactors = FALSE)
> sqlSave(dbhandle, df, tablename = 'jal_test1', append=TRUE, fast=FALSE, verbose=TRUE)
Query: INSERT INTO "jal_test1" ( "rownames", "a", "b" ) VALUES ( '1', -1.45261402, 'd' )
Query: INSERT INTO "jal_test1" ( "rownames", "a", "b" ) VALUES ( '2', -0.01642518, 'm' )
Query: INSERT INTO "jal_test1" ( "rownames", "a", "b" ) VALUES ( '3', 1.11767938, 'm' )
Query: INSERT INTO "jal_test1" ( "rownames", "a", "b" ) VALUES ( '4', -0.63480166, 'a' )
Query: INSERT INTO "jal_test1" ( "rownames", "a", "b" ) VALUES ( '5', -0.75538702, 'k' )
> sqlSave(dbhandle, df, tablename = 'jal_test1', append=TRUE, fast=TRUE, verbose=TRUE)
Query: INSERT INTO "jal_test1" ( "rownames", "a", "b" ) VALUES ( ?,?,? )
Binding: 'rownames' DataType -9, ColSize 255
Binding: 'a' DataType 6, ColSize 17
Binding: 'b' DataType -9, ColSize 255
Parameters:
no: 1: rownames 1/***/no: 2: a -1.45261/***/no: 3: b d/***/
no: 1: rownames 2/***/no: 2: a -0.0164252/***/no: 3: b m/***/
no: 1: rownames 3/***/no: 2: a 1.11768/***/no: 3: b m/***/
no: 1: rownames 4/***/no: 2: a -0.634802/***/no: 3: b a/***/
no: 1: rownames 5/***/no: 2: a -0.755387/***/no: 3: b k/***/