вставка нескольких записей одновременно в Redshift с помощью R - PullRequest
0 голосов
/ 01 июня 2018

Мне нужно вставлять несколько тысяч строк в Redshift несколько раз в день.Но я не могу использовать массовую вставку из S3 по административным причинам.Какой самый быстрый способ?

Подробности:

Есть 3 способа (я вижу), чтобы вставить строки в таблицу в Amazon Redshift из R:

  1. Строка за строкой вставки запроса.Каждая строка вставляется как собственный INSERT VALUES запрос
  2. Запрос на вставку нескольких строк: то же, что и 1, но для каждого запроса вставляется несколько записей.Размер ограничен либо количеством строк, либо ограничением максимального размера SQL-запроса в 16 МБ.
  3. Массовая вставка из 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/***/

Ответы [ 2 ]

0 голосов
/ 08 июня 2018

В конечном итоге я не смог найти реализацию функции записи SQL, которая бы выполняла разбиение на части в R. Но я видел, что в Python пакет sqlalchemy, объединенный с pandas, мог легко это сделать.Поэтому я извлек Reticulate и обернул Python в некоторый код R, чтобы создать функцию для записи в красное смещение.Похоже на излишество, но оно выполняет работу без необходимости что-либо переопределять:

start_python <- function(){
  library(reticulate)
  use_condaenv( "r-reticulate")
  pd <- import('pandas')
  sa <- import('sqlalchemy')
}

# write a table to RDW sandbox
write_to_redshift <- function(df, tablename, if_exists = 'append'){
  pd_df <- r_to_py(df)
  eng = sa$create_engine('postgres://user:pwd@redshift_name:5439/db_name')
  conn = eng$connect()
  write_result <- pd_df$to_sql( name=tablename, con=conn,  index = FALSE, if_exists = if_exists, schema='my_schema', chunksize=10000L)
  conn$close()
  return(write_result)
}
0 голосов
/ 01 июня 2018

Рекомендовать выполнять массовую загрузку с опцией не-S3:

  1. Копировать с Amazon EMR
  2. Копировать с удаленного хоста (SSH)
  3. Копировать с AmazonDynamoDB

https://docs.aws.amazon.com/redshift/latest/dg/copy-parameters-data-source.html

...