![](/img/trans.png)
[英]Using cursor.execute arguments in pymssql with IN sql statement
[英]pymssql/pyodbc performance (cursor.execute) is very slow when querying large SQL Server table
我们对 SQL Server 有一个很大的看法(大约有 500M 记录)。 由于它不适合内存,我正在考虑使用如下所示的 fetchmany 分块处理:
with pymssql.connect(host, user, pass, db) as conn:
query = f"SELECT * FROM view_name;"
with conn.cursor() as cursor, futures.ThreadPoolExecutor(3) as executor:
cursor.execute(query)
chunk_size = 5000
data = cursor.fetchmany(chunk_size)
while data:
future_rs = executor.submit(process_chunk, data)
data = cursor.fetchmany(chunk_size)
但是,看起来cursor.execute
实际上在我可以调用 fetchmany 之前尝试获取所有行,因为它非常慢。
我对文档的理解是cursor.execute
应该只准备查询而不是实现完整结果?
您将如何在可管理的时间内处理如此大的表/视图?
PS:我也试过pyodbc
,这是同样的问题。 正如预期的那样,更改查询以select top 100 * from view_name
很快。
好的,经过相当多的调试会话后,我有了一个解决方案。
部分问题被证明是非常缓慢的底层视图。 我误判了这一点,因为像 DBeaver 这样的数据库客户端返回结果的速度非常快(可能是因为它在后台应用分页查询?)。 无论如何,我试图用cursor.fetchmany
做的cursor.fetchmany
,我用数据库功能做了。
SQL Server 12 及更高版本使用OFFSET
和FETCH NEXT
具有非常好的分页功能。 所以我的解决方案看起来像这样:
offset = 0
offset_increment = 200000
def get_chunk(cursor, offset):
query = f"""
SELECT * FROM table ORDER BY some_col
OFFSET {offset} ROWS FETCH NEXT {offset_incriment} ROWS ONLY;
"""
return cursor.execute(query).fetchall()
with futures.ThreadPoolExecutor(6) as executor:
chunk = get_chunk(query, offset)
while chunk:
executor.submit(process_chunk, chunk)
offset += offset_increment
chunk = get_chunk(query, offset)
所以这里的实现是:
OFFSET
和FETCH NEXT
以获取有限数量的行。 这是我的解决方案背后的基本思想。 上面的代码只是一个例子,实际上我不得不根据资源使用情况(主要是内存)在我的项目中做更多的调整。 您也可以使用ProcessPoolExecutor
进行多处理而不是线程处理。 想法是一样的,代码需要一些更改,因为多处理只需要可挑选的对象。
因此,在块中同时使用分页和处理结果,您可以非常轻松地处理大型表/视图:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.