поле счетчика pyodbc to_sql неверно или синтаксическая ошибка - PullRequest
0 голосов
/ 05 июня 2018

Я загружаю данные Json с веб-сайта API и использую функцию to_sql sqlalchemy, pyodbc и pandas для вставки этих данных в MSSQL-сервер.

Я могу загрузить до 10000 строк, однако я должен ограничить размер фрагмента 10, иначе я получаю следующую ошибку:

DBAPIError: (pyodbc.Error) ('07002', '[07002] [Microsoft] [Собственный клиент SQL Server 11.0] Поле COUNT неверно или синтаксическая ошибка (0) (SQLExecDirectW)') [SQL: 'INSERT INTO [TEMP_produc_entity_details]

Есть около500 миллионов строк для загрузки, он просто ползет с такой скоростью.Любой совет об обходном пути?

Спасибо,

Ответы [ 2 ]

0 голосов
/ 13 июня 2019

Сделано несколько модификаций на основе ответа Горда Томпсона.Это автоматически вычислит размер фрагмента и сохранит его до наименьшего ближайшего целочисленного значения, которое соответствует пределу 2100 параметров:

import math
df_num_of_cols=len(df.columns)
chunknum=math.floor(2100/df_num_of_cols)
df.to_sql('MY_TABLE',con=engine,schema='myschema',chunksize=chunknum,if_exists='append',method='multi',index=False )
0 голосов
/ 05 июня 2018

ОБНОВЛЕНИЕ:

Панды 0.23.1 отменили проблемные изменения, внесенные в 0.23.0.Тем не менее, лучшим решением для необработанной производительности остается подход CSV -> bcp, как описано ниже.

ОБНОВЛЕНИЕ:

pandas 0.24.0, по-видимому, вновь представил проблему (ref: здесь )


(Оригинальный ответ)

До версии 0.23.0 для панд to_sql генерировал отдельную INSERT для каждогострока в DataTable:

exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6)',
    N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2)',
    0,N'row000'
exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6)',
    N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2)',
    1,N'row001'
exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6)',
    N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2)',
    2,N'row002'

Предполагается, что для повышения производительности pandas 0.23.0 теперь генерирует конструктор табличных значений для вставки нескольких строк за вызов

exec sp_prepexec @p1 output,N'@P1 int,@P2 nvarchar(6),@P3 int,@P4 nvarchar(6),@P5 int,@P6 nvarchar(6)',
    N'INSERT INTO df_to_sql_test (id, txt) VALUES (@P1, @P2), (@P3, @P4), (@P5, @P6)',
    0,N'row000',1,N'row001',2,N'row002'

Проблема заключается в том, что SQLХранимые процедуры сервера (включая системные хранимые процедуры, такие как sp_prepexec) ограничены 2100 параметрами, поэтому, если DataFrame имеет 100 столбцов, то to_sql может вставлять только около 20 строк одновременно.

Мы можем вычислить требуемое chunksize, используя

# df is an existing DataFrame
#
# limit based on sp_prepexec parameter count
tsql_chunksize = 2097 // len(df.columns)
# cap at 1000 (limit for number of rows inserted by table-value constructor)
tsql_chunksize = 1000 if tsql_chunksize > 1000 else tsql_chunksize
#
df.to_sql('tablename', engine, if_exists='replace', index=False, chunksize=tsql_chunksize)

Однако наиболее быстрый подход все еще будет:

  • сбросить DataFrameв CSV-файл (или аналогичный), а затем

  • попросите Python вызвать утилиту SQL Server bcp для загрузки этого файла в таблицу.

...