2011-02-05 16 views
2

SQLSoup(SQLAlchemyエクステンション)を使用して、SQL Server 2008データベースのレコードを更新しようとしています。私はpyobdcを接続に使用しています。関連する例を見つけることを困難にするいくつかの問題があります。ループ内のSQL Alchemyでレコードを更新する方法

非常に大きなテーブル(200万件以上のレコード)のジオメトリフィールドを再投影しているため、フィールドを更新する標準的な方法の多くは使用できません。ジオメトリフィールドからテキストに座標を抽出し、それらを変換して戻す必要があります。これはすべて問題なく、すべての個々の部分が機能しています。

しかし、レコードごとに1つずつループしながら、各行で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() 

接続エラーが発生するようになりました。

これはODBCドライバに問題がある可能性がありように見えます

DBAPIError: (Error) ('HY000', '[HY000] [Microsoft][ODBC SQL Server Driver]Connection is busy with results for another hstmt (0) (SQLExecDirectW)')

から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を実行すると、ハングすることもあります。更新のための新しい接続オブジェクトを作成したとしても。

また、MARS-Multiple Active Record Setsを許可することを目的としたSQL Server Native Client 10.0ドライバを試しましたが、違いはありませんでした。結局、私は "結果をページング"し、pyodbcとSQLを使ってこれらのバッチを更新していましたが(下記参照)、SQLAlchemyが自動的にこれを行うことができたと思いました。

+0

は、なぜあなたは、単一のUPDATEステートメントとして、純粋なSQLでそれを書きませんか?私には見えます。 –

+0

フィールドのonの内容は、SQL以外の独立した関数で処理する必要のあるバイナリオブジェクトです。なんらかの種類のカーソルが必要です。 – geographika

+1

@geographikaこれまでのところ、あなたの投稿は5年前から投稿されました。 - 私はpyodbcとODBCドライバ11を使用してSqlサーバーへのSQL錬金術接続を介してノートブックでSQLマジックを使用しようとしています....しかし、正確に同じエラーメッセージを取得する – whytheq

答えて

1

Sessionをお試しください。

rs = s.execute()となり、最後の3行をsession.execute(update_sql)に置き換えることができます。また、自動コミットをオフにしてセッションを設定し、最後にsession.commit()を呼び出すことをお勧めします。

+0

私の更新されたコードは、いくつかのレコードで正常に動作しますが、数百のレコードでハングします。 – geographika

+0

クライアント側でログを有効にできますか?サーバー上のすべてのステートメントのログを取得できる場合は、さらに優れています。 –

+0

ループで新しいセッションを作成するのはなぜですか?同じセッションを使用することは、少なくとも同じように機能し、すべての更新が同じトランザクションに属するようにすることもできます。 –

1

プロセスがハングすると、sp_who2をSqlボックスに表示し、何が起きているのかを確認できますか?ブロックされたspidを確認し、何が起こっているかを示唆するものがSqlコード内にあるかどうかを確認してください。あなたが他人をブロックしているspidを見つけたら、dbcc inputbuffer(*spidid*)を実行して、そのクエリが実行されたことがわかるかどうか確認してください。それ以外の場合は、SQLプロファイラを接続して呼び出しをトレースすることもできます。

場合によっては、ブロックを引き起こすSqlサーバー上の並列処理でもかまいません。これがデータウェアハウスでない限り、Max DOPをオフにすることをお勧めします(1に設定)。私に知らせてください。朝にこれをもう一度チェックして助けが必要な時は、私は喜んで助けます。

+0

ご返信ありがとうございます。上記のSQLプロファイラの詳細が追加されました。 – geographika

+0

問題ありません。私は錬金術の知識が全くないので、私はそれについてコメントすることはできません。しかし、私が出会ったこれらのLINQタイプのアプリケーションの多くにこの問題があります。可能であれば、ライターをブロックしないようにリーダーを設定できるかどうかを確認してください。したがって、 "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"を設定すると、読み込みが書き込みをブロックしていないか、可能であれば同じ効果を持つWITH(NOLOCK)に設定されます。 – Ryk

+0

エラー:( 'HY000'、 '[HY000] [Microsoft] [SQL Serverネイティブクライアント10.0]接続が別のコマンド(0)(SQLExecDirectW)の結果でビジー状態です') – geographika

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() 
+0

これを試してお知らせください。 s = "テーブルWITH(NOLOCK)"と ".... FROM%s"からのカウントとしてcount(fid)を選択する機能WITH(NOLOCK).... " – Ryk

関連する問題