Я очень хорошо знаю, что есть много похожих вопросов, и большинство ответов предлагают такие вещи, как массовая вставка 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 почти в два раза быстрее.
Мой код:
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()