数据帧到 SQL 服务器使用从 pyodbc 执行许多
Dataframe to SQL Server using Execute many from pyodbc
我正在尝试使用 Pyodbc 将数据从数据帧加载到 SQL 服务器,它逐行插入并且非常慢。
我已经尝试了网上找到的 2 种方法(中),但我没有发现性能有任何改进。
尝试在 SQL 天蓝色中 运行 所以 SQL 炼金术不是一个简单的连接方法。请找到我遵循的方法,还有其他方法可以提高批量加载的性能。
方法一
cursor = sql_con.cursor()
cursor.fast_executemany = True
for row_count in range(0, df.shape[0]):
chunk = df.iloc[row_count:row_count + 1,:].values.tolist()
tuple_of_tuples = tuple(tuple(x) for x in chunk)
for index,row in ProductInventory.iterrows():
cursor.executemany("INSERT INTO table ([x]],[Y]) values (?,?)",tuple_of_tuples)
方法二
cursor = sql_con.cursor()
for row_count in range(0, ProductInventory.shape[0]):
chunk = ProductInventory.iloc[row_count:row_count + 1,:].values.tolist()
tuple_of_tuples = tuple(tuple(x) for x in chunk)
for index,row in ProductInventory.iterrows():
cursor.executemany(""INSERT INTO table ([x]],[Y]) values (?,?)",tuple_of_tuples
谁能告诉我为什么性能提高不到 1%?还是一样的时间
几件事
为什么要对 ProductInventory 进行两次迭代?
executemany
调用不应该在你构建了整个 tuple_of_tuples 或其中的一批之后发生吗?
pyodbc 文档说 "running executemany() with fast_executemany=False is generally not going to be much faster than running multiple execute() commands directly." 所以你需要在两个例子中设置 cursor.fast_executemany=True
(更多 details/examples 见 https://github.com/mkleehammer/pyodbc/wiki/Cursor)。我不确定为什么在示例 2 中省略了它。
这是一个示例,说明您可以如何完成我认为您正在尝试做的事情。 math.ceil
和 end_idx = ...
中的条件表达式占最后一批,可能是奇数大小。因此,在下面的示例中,您有 10 行,批量大小为 3,所以最终有 4 个批次,最后一个只有 1 个元组。
import math
df = ProductInventory
batch_size = 500
num_batches = math.ceil(len(df)/batch_size)
for i in range(num_batches):
start_idx = i * batch_size
end_idx = len(df) if i + 1 == num_batches else start_idx + batch_size
tuple_of_tuples = tuple(tuple(x) for x in df.iloc[start_idx:end_idx, :].values.tolist())
cursor.executemany("INSERT INTO table ([x]],[Y]) values (?,?)", tuple_of_tuples)
示例输出:
=== Executing: ===
df = pd.DataFrame({'a': range(1,11), 'b': range(101,111)})
batch_size = 3
num_batches = math.ceil(len(df)/batch_size)
for i in range(num_batches):
start_idx = i * batch_size
end_idx = len(df) if i + 1 == num_batches else start_idx + batch_size
tuple_of_tuples = tuple(tuple(x) for x in df.iloc[start_idx:end_idx, :].values.tolist())
print(tuple_of_tuples)
=== Output: ===
((1, 101), (2, 102), (3, 103))
((4, 104), (5, 105), (6, 106))
((7, 107), (8, 108), (9, 109))
((10, 110),)
Trying to run in SQL azure so SQL Alchemy is not an easy connection method.
也许你只需要先跨过那个障碍。然后你可以使用 pandas to_sql 和 fast_executemany=True
。例如
from sqlalchemy import create_engine
#
# ...
#
engine = create_engine(connection_uri, fast_executemany=True)
df.to_sql("table_name", engine, if_exists="append", index=False)
如果您有可用的 pyodbc 连接字符串,您可以将其转换为 SQLAlchemy 连接 URI,如下所示:
connection_uri = 'mssql+pyodbc:///?odbc_connect=' + urllib.parse.quote_plus(connection_string)
我正在尝试使用 Pyodbc 将数据从数据帧加载到 SQL 服务器,它逐行插入并且非常慢。
我已经尝试了网上找到的 2 种方法(中),但我没有发现性能有任何改进。
尝试在 SQL 天蓝色中 运行 所以 SQL 炼金术不是一个简单的连接方法。请找到我遵循的方法,还有其他方法可以提高批量加载的性能。
方法一
cursor = sql_con.cursor()
cursor.fast_executemany = True
for row_count in range(0, df.shape[0]):
chunk = df.iloc[row_count:row_count + 1,:].values.tolist()
tuple_of_tuples = tuple(tuple(x) for x in chunk)
for index,row in ProductInventory.iterrows():
cursor.executemany("INSERT INTO table ([x]],[Y]) values (?,?)",tuple_of_tuples)
方法二
cursor = sql_con.cursor()
for row_count in range(0, ProductInventory.shape[0]):
chunk = ProductInventory.iloc[row_count:row_count + 1,:].values.tolist()
tuple_of_tuples = tuple(tuple(x) for x in chunk)
for index,row in ProductInventory.iterrows():
cursor.executemany(""INSERT INTO table ([x]],[Y]) values (?,?)",tuple_of_tuples
谁能告诉我为什么性能提高不到 1%?还是一样的时间
几件事
为什么要对 ProductInventory 进行两次迭代?
executemany
调用不应该在你构建了整个 tuple_of_tuples 或其中的一批之后发生吗?pyodbc 文档说 "running executemany() with fast_executemany=False is generally not going to be much faster than running multiple execute() commands directly." 所以你需要在两个例子中设置
cursor.fast_executemany=True
(更多 details/examples 见 https://github.com/mkleehammer/pyodbc/wiki/Cursor)。我不确定为什么在示例 2 中省略了它。
这是一个示例,说明您可以如何完成我认为您正在尝试做的事情。 math.ceil
和 end_idx = ...
中的条件表达式占最后一批,可能是奇数大小。因此,在下面的示例中,您有 10 行,批量大小为 3,所以最终有 4 个批次,最后一个只有 1 个元组。
import math
df = ProductInventory
batch_size = 500
num_batches = math.ceil(len(df)/batch_size)
for i in range(num_batches):
start_idx = i * batch_size
end_idx = len(df) if i + 1 == num_batches else start_idx + batch_size
tuple_of_tuples = tuple(tuple(x) for x in df.iloc[start_idx:end_idx, :].values.tolist())
cursor.executemany("INSERT INTO table ([x]],[Y]) values (?,?)", tuple_of_tuples)
示例输出:
=== Executing: ===
df = pd.DataFrame({'a': range(1,11), 'b': range(101,111)})
batch_size = 3
num_batches = math.ceil(len(df)/batch_size)
for i in range(num_batches):
start_idx = i * batch_size
end_idx = len(df) if i + 1 == num_batches else start_idx + batch_size
tuple_of_tuples = tuple(tuple(x) for x in df.iloc[start_idx:end_idx, :].values.tolist())
print(tuple_of_tuples)
=== Output: ===
((1, 101), (2, 102), (3, 103))
((4, 104), (5, 105), (6, 106))
((7, 107), (8, 108), (9, 109))
((10, 110),)
Trying to run in SQL azure so SQL Alchemy is not an easy connection method.
也许你只需要先跨过那个障碍。然后你可以使用 pandas to_sql 和 fast_executemany=True
。例如
from sqlalchemy import create_engine
#
# ...
#
engine = create_engine(connection_uri, fast_executemany=True)
df.to_sql("table_name", engine, if_exists="append", index=False)
如果您有可用的 pyodbc 连接字符串,您可以将其转换为 SQLAlchemy 连接 URI,如下所示:
connection_uri = 'mssql+pyodbc:///?odbc_connect=' + urllib.parse.quote_plus(connection_string)