我正在尝试使用SQLSoup(SQLAlchemy扩展)来更新SQL Server 2008数据库中的记录。我正在使用pyobdc进行连接。有许多问题使得很难找到相关的例子。
我在一个非常大的表(200万+记录)中重新投影几何字段,因此无法使用许多更新字段的标准方法。我需要从几何字段中提取坐标到文本,转换它们并将它们传回。所有这一切都很好,所有单个部分都在工作。
但是我想在每一行上执行SQL Update语句,同时逐个循环遍历记录。我假设这会锁定记录集,或者连接正在使用 - 就像我使用下面的代码一样,它在成功更新第一条记录后挂起。
有关如何创建新连接,重用现有连接或以其他方式实现此建议的任何建议都表示赞赏。
s = select([text("%s as fid" % id_field),
text("%s.STAsText() as wkt" % geom_field)],
from_obj=[feature_table])
rs = s.execute()
for row in rs:
new_wkt = ReprojectFeature(row.wkt)
update_value = "geometry :: STGeomFromText('%s',%s)" % (new_wkt, "3785")
update_sql = ("update %s set GEOM3785 = %s where %s = %i" %
(full_name, update_value, id_field, row.fid))
conn = db.connection()
conn.execute(update_sql)
conn.close() #or not - no effect..
现在更新的工作代码如下所示。它在一些记录上工作正常,但挂在整个表上,所以我猜它是在读取太多数据。
db = SqlSoup(conn_string)
#create outer query
Session = sessionmaker(autoflush=False, bind=db.engine)
session = Session()
rs = session.execute(s)
for row in rs:
#create update sql...
session.execute(update_sql)
session.commit()
我现在遇到连接繁忙的错误。
DBAPIError :(错误)('HY000','[HY000] [Microsoft] [ODBC SQL Server驱动程序]连接正忙于另一个hstmt(0)的结果(SQLExecDirectW)')
看起来这可能是ODBC驱动程序的问题 - http://sourceitsoftware.blogspot.com/2008/06/connection-is-busy-with-results-for.html
进一步更新:
在使用分析器的服务器上,它显示select语句,然后第一个更新语句是“正在启动”但不完整。 如果我将Select语句设置为返回前10行,则它会完成并运行更新。
SQL: Batch Starting Select...
SQL: Batch Starting Update...
我认为这是pyodbc和SQL Server驱动程序的问题。如果我删除SQL Alchemy并使用pyodbc执行相同的SQL,它也会挂起。即使我为更新创建了一个新的连接对象。
我还尝试过SQL Server Native Client 10.0驱动程序,它允许使用MARS - Multiple Active Record Sets,但它没有任何区别。最后,我采用了“分页结果”并使用pyodbc和SQL更新这些批次(见下文),但我认为SQLAlchemy能够自动为我做这个。
答案 0 :(得分:1)
尝试使用Session。
rs = s.execute()
然后变为session.execute(rs)
,您可以使用session.execute(update_sql)
替换最后三行。我还建议您使用autocommit配置Session,并在结束时调用session.commit()
。
答案 1 :(得分:1)
我可以建议,当您的进程挂起时,在Sql框中执行sp_who2
,看看发生了什么。检查阻塞的spid,看看你是否可以在Sql代码中找到可以提示正在发生的事情的任何内容。如果你发现一个阻止他人的spid,你可以做一个dbcc inputbuffer(*spidid*)
,看看它是否告诉你它执行了什么查询。否则,您还可以附加Sql探查器并跟踪您的呼叫。
在某些情况下,它也可能是导致阻塞的Sql服务器上的并行性。除非这是一个数据仓库,否则我建议关闭你的Max DOP,(将其设置为1)。让我知道,当我在早上再次检查这件事并且你需要帮助时,我会很乐意提供帮助。
答案 2 :(得分:1)
在找到另一个解决方案之前,我使用单个连接和自定义SQL来返回记录集,并批量更新这些记录。我不认为我在做什么是一个特殊的独特案例,所以我不知道为什么我不能同时处理多个结果集。
下面有效,但非常非常慢......
cnxn = pyodbc.connect(conn_string, autocommit=True)
cursor = cnxn.cursor()
#get total recs in the database
s = "select count(fid) as count from table"
count = cursor.execute(s).fetchone().count
#choose number of records to update in each iteration
batch_size = 100
for i in range(1,count, batch_size):
#sql to bring back relevant records in each batch
s = """SELECT fid, wkt from(select ROW_NUMBER() OVER(ORDER BY FID ASC) AS 'RowNumber'
,FID
,GEOM29902.STAsText() as wkt
FROM %s) features
where RowNumber >= %i and RowNumber <= %i""" % (full_name,i,i+batch_size)
rs = cursor.execute(s).fetchall()
for row in rs:
new_wkt = ReprojectFeature(row.wkt)
#...create update sql statement for the record
cursor.execute(update_sql)
counter += 1
cursor.close()
cnxn.close()