Como subir múltiplos e grandes arquivos para o PostgreSQL com R

Neste tutorial, irei mostrar como copiar para uma base de dados do PostgreSQL múltiplos arquivos com que não cabem na memória RAM, a partir do R, já tradados, sem sobrecarregar a memória.

José de Jesus Filho https://rpg.consudata.com.br
06-07-2021

Neste tutorial, irei mostrar como copiar para uma base de dados do PostgreSQL múltiplos arquivos com que não cabem na memória RAM, a partir do R, sem sobrecarregar a memória. Além disso, você poderá realizar todas as transformações necessárias nos dados, antes de inseri-los.

Eu diria que há algumas vantagens nesta solução. A primeira delas é a possibilidade de inspecionar os arquivos antes de inseri-los na base de dados SQL. A segunda é inserir os arquivos em parcelas, sem ter de carregar na memória todas as linhas, principalmente quando esta é formada por milhões de linhas. A terceira é a possibilidade de realizar ajustes prévios, tais como selecionar apenas algumas colunas, manter unicamente linhas de interesse, ajustar encoding e realizar todo tipo de transformação nos dados antes de inseri-los.

Por outro lado, algumas precauções devem ser tomadas, tanto do lado do R, quanto do lado do PostgreSQL a fim de otimizar o processo de inserção. Assim mesmo, se você possui grandes arquivos em csv ou txt que não carecem de transformação, possivelmente a opção mais eficaz será usar copy diretamente no psql em vez de inserir via R.

Para melhor desempenho, também não crie chaves primárias nem faça indexação antes do término na inserção. Igualmente, se você usa apenas uma instância do PostgreSQL, sem replicação, e não há uma preocupação com eventual interrupção ou de desligamento repentino da máquina, você pode desativar o WAL, por meio da criação de UNLOGGED TABLE. Para mais informações acerca de melhoria de desempenho em inserções e cópia de grande volumes de dados, veja esse tutorial

A título de exemplo, iremos utilizar os arquivos da RAIS (relação anual de informações sociais) do Ministério do Trabalho do ano de 2018.

Você pode baixar esses dados deste endereço. Eles estão compactados em formato 7z. Para baixá-los, basta usar a função download.file() em conjunção com a função walk do pacote purrr.

Antes, porém, vamos carregar os pacotes tidyverse, vez que usaremos vários deles. Além disso, para extrair os arquivos compactados, usaremos o pacote archive. Para inspecionar o arquivo, usaremos a função fread do pacote data.table. Para ajustar os nomes das colunas, usaremos o pacote janitor. Os pacotes DBI e dbx serão usados paa criar a tabela no PostgreSQL e inseri-los, respectivamente.

devtools::install_github("jimhester/archive")
library(archive)
library(tidyverse)
library(data.table)
library(janitor)
library(DBI)
library(dbx)

Baixando os dados

Baixaremos apenas os arquivos correspondentes aos trabalhadores, excluindo o relativo aos estabelecimentos. Estou supondo que você irá baixá-lo no diretório atual e que este está vazio.

arquivos <- readLines("ftp://ftp.mtps.gov.br/pdet/microdados/RAIS/2018/") %>% 
            str_extract("RAIS.+") %>% 
            str_subset("ESTAB",negate = TRUE) %>% 
            str_c("ftp://ftp.mtps.gov.br/pdet/microdados/RAIS/2018/",.)

walk(arquivos, download.file)

Uma vez descompactados, esses arquivos ocuparão vários gigas de memória. Somente o arquivo de São Paulo, o maior deles, ocupa 8,9 Gb. Vamos descompactá-los:

arquivos1 <- list.files()

walk(arquivos,archive_extract)

Inspecionando os dados

Antes de proceder à transferência dos dados, iremos inspecioná-los. Vamos ler as primeiras dez linhas de um dos arquivos e verificar como elas se apresentam. Note que eu coloquei o enconding “Latin-1”. Fiz isso porque havia tentado ler com o default que é “UTF-8” e não foi possível.

df <- fread("RAIS_VINC_PUB_SP.txt",nrows=10,encoding="Latin-1")
glimpse(df)
Rows: 10
Columns: 62
$ `Bairros SP`              <int> 9999, 9999, 9999, 9999, 654, 9999,…
$ `Bairros Fortaleza`       <chr> "{ñ class}", "{ñ class}", "{ñ clas…
$ `Bairros RJ`              <chr> "{ñ class}", "{ñ class}", "{ñ clas…
$ `Causa Afastamento 1`     <int> 99, 99, 99, 99, 99, 99, 99, 99, 99…
$ `Causa Afastamento 2`     <int> 99, 99, 99, 99, 99, 99, 99, 99, 99…
$ `Causa Afastamento 3`     <int> 99, 99, 99, 99, 99, 99, 99, 99, 99…
$ `Motivo Desligamento`     <int> 11, 11, 12, 21, 11, 11, 11, 11, 11…
$ `CBO Ocupação 2002`       <int> 717020, 514320, 784205, 622010, 62…
$ `CNAE 2.0 Classe`         <int> 41204, 46869, 78205, 1610, 91031, …
$ `CNAE 95 Classe`          <int> 45217, 51594, 74500, 1619, 92533, …
$ `Distritos SP`            <int> 9999, 9999, 9999, 9999, 67, 9999, …
$ `Vínculo Ativo 31/12`     <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ `Faixa Etária`            <int> 4, 6, 5, 5, 6, 7, 4, 5, 6, 5
$ `Faixa Hora Contrat`      <int> 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
$ `Faixa Remun Dezem (SM)`  <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ `Faixa Remun Média (SM)`  <int> 2, 2, 3, 2, 4, 3, 4, 2, 5, 3
$ `Faixa Tempo Emprego`     <int> 3, 4, 1, 1, 6, 4, 4, 1, 7, 1
$ `Escolaridade após 2005`  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ `Qtd Hora Contr`          <int> 44, 44, 44, 44, 44, 44, 44, 44, 44…
$ Idade                     <int> 27, 44, 30, 35, 43, 59, 29, 30, 44…
$ `Ind CEI Vinculado`       <int> 0, 0, 0, 0, 0, 1, 1, 0, 0, 0
$ `Ind Simples`             <int> 0, 1, 0, 0, 1, 0, 0, 1, 1, 0
$ `Mês Admissão`            <int> 0, 0, 6, 9, 0, 0, 0, 9, 0, 7
$ `Mês Desligamento`        <int> 1, 5, 7, 10, 6, 5, 5, 10, 3, 10
$ `Mun Trab`                <int> 0, 0, 354870, 0, 355030, 350950, 3…
$ Município                 <int> 350550, 352440, 354780, 350320, 35…
$ Nacionalidade             <int> 10, 10, 10, 10, 10, 10, 10, 10, 10…
$ `Natureza Jurídica`       <int> 2062, 2062, 2305, 2305, 2135, 2062…
$ `Ind Portador Defic`      <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ `Qtd Dias Afastamento`    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 10
$ `Raça Cor`                <int> 2, 2, 2, 4, 2, 2, 6, 2, 2, 8
$ `Regiões Adm DF`          <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ `Vl Remun Dezembro Nom`   <chr> "0000000000,00", "0000000000,00", …
$ `Vl Remun Dezembro (SM)`  <chr> "000000,00", "000000,00", "000000,…
$ `Vl Remun Média Nom`      <chr> "0000001174,62", "0000001405,21", …
$ `Vl Remun Média (SM)`     <chr> "000001,23", "000001,47", "000001,…
$ `CNAE 2.0 Subclasse`      <int> 4120400, 4686902, 7820500, 161099,…
$ `Sexo Trabalhador`        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ `Tamanho Estabelecimento` <int> 4, 2, 10, 7, 1, 1, 1, 4, 2, 8
$ `Tempo Emprego`           <chr> "11,9", "17,1", "0,4", "1,2", "51,…
$ `Tipo Admissão`           <int> 0, 0, 2, 2, 0, 0, 0, 2, 0, 1
$ `Tipo Estab`              <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ `Tipo Estab.1`            <chr> "CNPJ", "CNPJ", "CNPJ", "CNPJ", "C…
$ `Tipo Defic`              <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ `Tipo Vínculo`            <int> 10, 10, 50, 10, 10, 10, 10, 10, 10…
$ `IBGE Subsetor`           <int> 15, 17, 19, 25, 21, 15, 15, 19, 3,…
$ `Vl Rem Janeiro CC`       <chr> "000001174,62", "000001272,42", "0…
$ `Vl Rem Fevereiro CC`     <chr> "000000000,00", "000001299,48", "0…
$ `Vl Rem Março CC`         <chr> "000000000,00", "000001643,73", "0…
$ `Vl Rem Abril CC`         <chr> "000000000,00", "000000000,00", "0…
$ `Vl Rem Maio CC`          <chr> "000000000,00", "000000000,00", "0…
$ `Vl Rem Junho CC`         <chr> "000000000,00", "000000000,00", "0…
$ `Vl Rem Julho CC`         <chr> "000000000,00", "000000000,00", "0…
$ `Vl Rem Agosto CC`        <chr> "000000000,00", "000000000,00", "0…
$ `Vl Rem Setembro CC`      <chr> "000000000,00", "000000000,00", "0…
$ `Vl Rem Outubro CC`       <chr> "000000000,00", "000000000,00", "0…
$ `Vl Rem Novembro CC`      <chr> "000000000,00", "000000000,00", "0…
$ `Ano Chegada Brasil`      <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ `Ind Trab Intermitente`   <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ `Ind Trab Parcial`        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ `Tipo Salário`            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ `Vl Salário Contratual`   <chr> "1.438,31", "1.344,87", "1.473,61"…

Verificamos alguns problemas com este dataframe. O primeiro deles está nos nomes, que não estão num formato amigável. Outro problema é que as colunas referentes à remuneração estão como caractere. Uma breve inspeção permite verificar que são justamente aquelas colunas que começam com “Vl”. Assim, nossa tarefa ajustar os nomes das colunas e alterar para número as colunas que começam com “Vl”.

Transformando os dados

Para ajustar os nomes das colunas, usaremos a função clean_names do pacote janitor:

df <- clean_names(df)
glimpse(df)
Rows: 10
Columns: 62
$ bairros_sp              <int> 9999, 9999, 9999, 9999, 654, 9999, 9…
$ bairros_fortaleza       <chr> "{ñ class}", "{ñ class}", "{ñ class}…
$ bairros_rj              <chr> "{ñ class}", "{ñ class}", "{ñ class}…
$ causa_afastamento_1     <int> 99, 99, 99, 99, 99, 99, 99, 99, 99, …
$ causa_afastamento_2     <int> 99, 99, 99, 99, 99, 99, 99, 99, 99, …
$ causa_afastamento_3     <int> 99, 99, 99, 99, 99, 99, 99, 99, 99, …
$ motivo_desligamento     <int> 11, 11, 12, 21, 11, 11, 11, 11, 11, …
$ cbo_ocupacao_2002       <int> 717020, 514320, 784205, 622010, 6220…
$ cnae_2_0_classe         <int> 41204, 46869, 78205, 1610, 91031, 41…
$ cnae_95_classe          <int> 45217, 51594, 74500, 1619, 92533, 45…
$ distritos_sp            <int> 9999, 9999, 9999, 9999, 67, 9999, 99…
$ vinculo_ativo_31_12     <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ faixa_etaria            <int> 4, 6, 5, 5, 6, 7, 4, 5, 6, 5
$ faixa_hora_contrat      <int> 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
$ faixa_remun_dezem_sm    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ faixa_remun_media_sm    <int> 2, 2, 3, 2, 4, 3, 4, 2, 5, 3
$ faixa_tempo_emprego     <int> 3, 4, 1, 1, 6, 4, 4, 1, 7, 1
$ escolaridade_apos_2005  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ qtd_hora_contr          <int> 44, 44, 44, 44, 44, 44, 44, 44, 44, …
$ idade                   <int> 27, 44, 30, 35, 43, 59, 29, 30, 44, …
$ ind_cei_vinculado       <int> 0, 0, 0, 0, 0, 1, 1, 0, 0, 0
$ ind_simples             <int> 0, 1, 0, 0, 1, 0, 0, 1, 1, 0
$ mes_admissao            <int> 0, 0, 6, 9, 0, 0, 0, 9, 0, 7
$ mes_desligamento        <int> 1, 5, 7, 10, 6, 5, 5, 10, 3, 10
$ mun_trab                <int> 0, 0, 354870, 0, 355030, 350950, 350…
$ municipio               <int> 350550, 352440, 354780, 350320, 3550…
$ nacionalidade           <int> 10, 10, 10, 10, 10, 10, 10, 10, 10, …
$ natureza_juridica       <int> 2062, 2062, 2305, 2305, 2135, 2062, …
$ ind_portador_defic      <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ qtd_dias_afastamento    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 10
$ raca_cor                <int> 2, 2, 2, 4, 2, 2, 6, 2, 2, 8
$ regioes_adm_df          <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ vl_remun_dezembro_nom   <chr> "0000000000,00", "0000000000,00", "0…
$ vl_remun_dezembro_sm    <chr> "000000,00", "000000,00", "000000,00…
$ vl_remun_media_nom      <chr> "0000001174,62", "0000001405,21", "0…
$ vl_remun_media_sm       <chr> "000001,23", "000001,47", "000001,54…
$ cnae_2_0_subclasse      <int> 4120400, 4686902, 7820500, 161099, 9…
$ sexo_trabalhador        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ tamanho_estabelecimento <int> 4, 2, 10, 7, 1, 1, 1, 4, 2, 8
$ tempo_emprego           <chr> "11,9", "17,1", "0,4", "1,2", "51,9"…
$ tipo_admissao           <int> 0, 0, 2, 2, 0, 0, 0, 2, 0, 1
$ tipo_estab              <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ tipo_estab_1            <chr> "CNPJ", "CNPJ", "CNPJ", "CNPJ", "CNP…
$ tipo_defic              <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ tipo_vinculo            <int> 10, 10, 50, 10, 10, 10, 10, 10, 10, …
$ ibge_subsetor           <int> 15, 17, 19, 25, 21, 15, 15, 19, 3, 19
$ vl_rem_janeiro_cc       <chr> "000001174,62", "000001272,42", "000…
$ vl_rem_fevereiro_cc     <chr> "000000000,00", "000001299,48", "000…
$ vl_rem_marco_cc         <chr> "000000000,00", "000001643,73", "000…
$ vl_rem_abril_cc         <chr> "000000000,00", "000000000,00", "000…
$ vl_rem_maio_cc          <chr> "000000000,00", "000000000,00", "000…
$ vl_rem_junho_cc         <chr> "000000000,00", "000000000,00", "000…
$ vl_rem_julho_cc         <chr> "000000000,00", "000000000,00", "000…
$ vl_rem_agosto_cc        <chr> "000000000,00", "000000000,00", "000…
$ vl_rem_setembro_cc      <chr> "000000000,00", "000000000,00", "000…
$ vl_rem_outubro_cc       <chr> "000000000,00", "000000000,00", "000…
$ vl_rem_novembro_cc      <chr> "000000000,00", "000000000,00", "000…
$ ano_chegada_brasil      <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ ind_trab_intermitente   <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ ind_trab_parcial        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ tipo_salario            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ vl_salario_contratual   <chr> "1.438,31", "1.344,87", "1.473,61", …

Com isso, podemos converter as colunas iniciadas por “vl” para numéricas:

df <- df %>% 
  mutate(across(starts_with("vl"),~{
    .x %>% 
    str_replace_all("\\.","") %>% ## Remove os pontos
    str_replace(",",".") %>%  ## Substitui a vírgula por ponto
    as.numeric() ## Converte para número
}))

glimpse(df)
Rows: 10
Columns: 62
$ bairros_sp              <int> 9999, 9999, 9999, 9999, 654, 9999, 9…
$ bairros_fortaleza       <chr> "{ñ class}", "{ñ class}", "{ñ class}…
$ bairros_rj              <chr> "{ñ class}", "{ñ class}", "{ñ class}…
$ causa_afastamento_1     <int> 99, 99, 99, 99, 99, 99, 99, 99, 99, …
$ causa_afastamento_2     <int> 99, 99, 99, 99, 99, 99, 99, 99, 99, …
$ causa_afastamento_3     <int> 99, 99, 99, 99, 99, 99, 99, 99, 99, …
$ motivo_desligamento     <int> 11, 11, 12, 21, 11, 11, 11, 11, 11, …
$ cbo_ocupacao_2002       <int> 717020, 514320, 784205, 622010, 6220…
$ cnae_2_0_classe         <int> 41204, 46869, 78205, 1610, 91031, 41…
$ cnae_95_classe          <int> 45217, 51594, 74500, 1619, 92533, 45…
$ distritos_sp            <int> 9999, 9999, 9999, 9999, 67, 9999, 99…
$ vinculo_ativo_31_12     <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ faixa_etaria            <int> 4, 6, 5, 5, 6, 7, 4, 5, 6, 5
$ faixa_hora_contrat      <int> 6, 6, 6, 6, 6, 6, 6, 6, 6, 6
$ faixa_remun_dezem_sm    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ faixa_remun_media_sm    <int> 2, 2, 3, 2, 4, 3, 4, 2, 5, 3
$ faixa_tempo_emprego     <int> 3, 4, 1, 1, 6, 4, 4, 1, 7, 1
$ escolaridade_apos_2005  <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ qtd_hora_contr          <int> 44, 44, 44, 44, 44, 44, 44, 44, 44, …
$ idade                   <int> 27, 44, 30, 35, 43, 59, 29, 30, 44, …
$ ind_cei_vinculado       <int> 0, 0, 0, 0, 0, 1, 1, 0, 0, 0
$ ind_simples             <int> 0, 1, 0, 0, 1, 0, 0, 1, 1, 0
$ mes_admissao            <int> 0, 0, 6, 9, 0, 0, 0, 9, 0, 7
$ mes_desligamento        <int> 1, 5, 7, 10, 6, 5, 5, 10, 3, 10
$ mun_trab                <int> 0, 0, 354870, 0, 355030, 350950, 350…
$ municipio               <int> 350550, 352440, 354780, 350320, 3550…
$ nacionalidade           <int> 10, 10, 10, 10, 10, 10, 10, 10, 10, …
$ natureza_juridica       <int> 2062, 2062, 2305, 2305, 2135, 2062, …
$ ind_portador_defic      <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ qtd_dias_afastamento    <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 10
$ raca_cor                <int> 2, 2, 2, 4, 2, 2, 6, 2, 2, 8
$ regioes_adm_df          <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ vl_remun_dezembro_nom   <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ vl_remun_dezembro_sm    <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ vl_remun_media_nom      <dbl> 1174.62, 1405.21, 1473.60, 968.94, 2…
$ vl_remun_media_sm       <dbl> 1.23, 1.47, 1.54, 1.01, 2.14, 1.89, …
$ cnae_2_0_subclasse      <int> 4120400, 4686902, 7820500, 161099, 9…
$ sexo_trabalhador        <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ tamanho_estabelecimento <int> 4, 2, 10, 7, 1, 1, 1, 4, 2, 8
$ tempo_emprego           <chr> "11,9", "17,1", "0,4", "1,2", "51,9"…
$ tipo_admissao           <int> 0, 0, 2, 2, 0, 0, 0, 2, 0, 1
$ tipo_estab              <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ tipo_estab_1            <chr> "CNPJ", "CNPJ", "CNPJ", "CNPJ", "CNP…
$ tipo_defic              <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ tipo_vinculo            <int> 10, 10, 50, 10, 10, 10, 10, 10, 10, …
$ ibge_subsetor           <int> 15, 17, 19, 25, 21, 15, 15, 19, 3, 19
$ vl_rem_janeiro_cc       <dbl> 1174.62, 1272.42, 0.00, 0.00, 20.50,…
$ vl_rem_fevereiro_cc     <dbl> 0.00, 1299.48, 0.00, 0.00, 20.50, 19…
$ vl_rem_marco_cc         <dbl> 0.00, 1643.73, 0.00, 0.00, 20.50, 19…
$ vl_rem_abril_cc         <dbl> 0.0, 0.0, 0.0, 0.0, 20.5, 0.0, 0.0, …
$ vl_rem_maio_cc          <dbl> 0.0, 0.0, 0.0, 0.0, 20.5, 0.0, 0.0, …
$ vl_rem_junho_cc         <dbl> 0.0, 0.0, 1473.6, 0.0, 20.5, 0.0, 0.…
$ vl_rem_julho_cc         <dbl> 0.00, 0.00, 1473.60, 0.00, 0.00, 0.0…
$ vl_rem_agosto_cc        <dbl> 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, …
$ vl_rem_setembro_cc      <dbl> 0.00, 0.00, 0.00, 1118.01, 0.00, 0.0…
$ vl_rem_outubro_cc       <dbl> 0.00, 0.00, 0.00, 819.87, 0.00, 0.00…
$ vl_rem_novembro_cc      <dbl> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ ano_chegada_brasil      <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ ind_trab_intermitente   <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ ind_trab_parcial        <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
$ tipo_salario            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
$ vl_salario_contratual   <dbl> 1438.31, 1344.87, 1473.61, 11.18, 20…

Transferindo para a base de dados SQL

Realizar essas transformações num pequeno dataframe foi fácil. O desafio é programar para que o R leia o arquivo em parcelas, realize as transformações e envie para a base de dados. Assumindo que você já sabe se conectar a uma base SQL, vamos dar os passos seguintes.

A mágica ficará por conta da função walk do pacote purrr e da função read_delim_chunk do pacote readr. Esta última permite que você leia o arquivo em parcelas (chunks) e aplique uma função callback sobre cada um dos chunks. Nesta função callback, você pode incluir todas as transformações que quiser e um comando para inserir os dados na base SQL.

Inicialmente, vamos criar uma tabela na base de dados com o dataframe transformado:

DBI::dbCreateTable(conn,"df",df)

Vamos criar a função callback. Ela irá ajustar os nomes das colunas, converter aquelas iniciadas por “vl” para numéricas e, por fim, inserir os dados na tabela.

f <- function(x, pos){

`%>%` <- magrittr::`%>%`  

x %>% 
janitor::clean_names() %>% 
dplyr::mutate(dplyr::across(dplyr::starts_with("vl"),~{
    .x %>% 
    stringr::str_replace_all("\\.","") %>% ## Remove os pontos
    stringr::str_replace(",",".") %>%  ## Substitui a vírgula por ponto
    as.numeric() %>% ## Converte para número
    dbx::dbxInsert(conn,"df",.) ## Insere os dados na tabela já criada
}))

}

Vamos agora criar um vetor com os nomes dos arquivos a serem lidos, chamar a função read_delim_chunk dentro do walk do purrr para ler 50 mil linhas por vez, realizar as transformações e inserir na tabela previamente criada na base de dados.

a <- list.files(pattern="txt$")

walk(a,~{

.x %>% 
readr::read_delim_chunked(callback = readr::DataFrameCallback$new(f),
                         locale = readr::locale(encoding="latin1"),
                         delim = "\t",
                         chunk_size = 50000)

})

Pronto, basta rodar o comando acima para deixar o R trabalhando na leitura, tranformação dos dados e inserção na base de forma segura e eficiente.