Как ускорить экспорт данных в MS SQL Server?R в два раза быстрее - PullRequest
1 голос
/ 05 апреля 2019

Я очень хорошо знаю, что есть много похожих вопросов, и большинство ответов предлагают такие вещи, как массовая вставка CSV (что было бы более головной болью, чем экспорт из R).

Однако я не в курселюбое сравнение с R, которое обращается, если pandas.DataFrame.to_sql() может когда-либо достигать той же скорости, что и R's DBI::dbWriteTable.

, я запускаю Anaconda на компьютере с Windows 10.В качестве теста я экспортирую 15 таблиц, каждая из которых содержит 10 000 строк, 30 столбцов случайных чисел с плавающей точкой и 3 строковых столбца.

Время:

  • pyodbc без fast_executemany: 19 секунд
  • pyodbc с fast_executemany: 7 секунд
  • turbodbc: 13 секунд
  • R и DBI :: dbWriteTable: 4 секунды

Я пробовал pymssql, ноЯ не могу заставить его работать (см. Комментарии в коде).

fast_executemany - большое улучшение, но оно все равно занимает почти вдвое больше времени, чем R. Разница против R поразительна! И это также предполагает, что в соединении с сервером SQL нет ничего неправильного.

Если ответ таков: «Нет, R намного быстрее, точка», может кто-нибудь уточнить, почему?Было бы очень интересно понять, в чем причина различий.

Для гигантских таблиц я мог бы подумать об экспорте их в формат, такой как паркет или перо, заставить R прочитать их, а затем экспортировать в SQL для RОднако для таблиц среднего размера (от 30 до 200 МБ данных) я бы предпочел найти лучшее решение в Python.

PS Это SQL Server Express, работающий на том же ПК, с которогоЯ использую Python и R.

Edit

В ответ на комментарий я сравнил время выполнения с разными размерами, и отношение времени R к времени pyodbc кажется довольно постоянным.Примите это с недоверием - я не эксперт по базам данных, и вполне могут быть конфигурации базы данных или другие факторы, которые мне не хватает, которые играют роль.Суть в том, что в моих случаях R почти в два раза быстрее.

enter image description here

Мой код:

import numpy as np
import pandas as pd
import timeit
from sqlalchemy import create_engine #, MetaData, Table, select
import pymssql
ServerName = myserver
Database = mydb
params = '?driver=SQL+Server+Native+Client+11.0'

# we define the pyodbc connection
engine_pyo = create_engine('mssql+pyodbc://' + ServerName + '/' + Database + params,
                           encoding='latin1', fast_executemany=True)
conn_pyo = engine_pyo.connect()

# now the turbodbc
engine_turbo = create_engine('mssql+turbodbc://' + ServerName + '/' + Database + params, encoding='latin1')
conn_turbo = engine_turbo.connect()

# pymssql is installed but doesn't work.
# I get:
# connect() got an unexpected keyword argument 'driver'
#engine_pyms = create_engine('mssql+pymssql://' + ServerName + '/' + Database + params, encoding='latin1')
#conn_pyms = engine_pyms.connect()

sheets = 15
rows= int(10e3)

def create_data(sheets, rows):
    df = {} # dictionary of dataframes
    for i in range(sheets):
        df[i] = pd.DataFrame(data= np.random.rand(rows,30) )
        df[i]['a'] = 'some long random text'
        df[i]['b'] = 'some more random text'
        df[i]['c'] = 'yet more text'
    return df

def data_to_sql(df, conn):
    for d in df:
        df[d].to_sql('Test ' + str(d) , conn, if_exists='replace' )

#NB: df is a dictionary containing dataframes - it is NOT a dataframe
# df[key] is a dataframe
df = create_data(sheets, rows)

rep = 1
n = 1
t_pyodbc = timeit.Timer( "data_to_sql(df, conn_pyo)" , globals=globals() ).repeat(repeat = rep, number = n)
t_turbo = timeit.Timer( "data_to_sql(df, conn_turbo)" , globals=globals() ).repeat(repeat = rep, number = n)

Мой код R:

library(tictoc)
library(readxl)
library(tidyverse)
library(dplyr)
library(dbplyr)
library(DBI)

tic("data creation")
rows = 10000
cols = 30
tables = 15

dataframes <- list()

for (i in 1:tables){

newdf <- as_tibble( matrix(rnorm(rows * cols),rows , cols) ) 
newdf <- mutate(newdf, a = 'some long random text') 
newdf <- mutate(newdf, b = 'some more random text') 
newdf <- mutate(newdf, c = 'yet more text')

dataframes[[i]] <- newdf

}
toc()

tic("set up odbc")
con <- DBI::dbConnect(odbc::odbc(),
                      driver = "SQL Server",
                      server = "LTS-LNWS010\\SQLEXPRESS",
                      database = "CDL",
                      trusted_connection = TRUE)
toc()

tic("SQL export")
for(i in seq_along(dataframes)){
  DBI::dbWriteTable(con, paste("Test_", i), dataframes[[i]], overwrite = TRUE)
}
toc()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...