2009-05-13 5 views
0

比較的簡単なSQL更新文をいくつか実行して、Oracle表の1列を1440万行に更新する必要があります。 1つのステートメントはJavaで書かれた関数を実行し、私は1440万行すべての更新を行っているのでJVMはメモリ不足になります。Oracleの更新文をバッチ・モードで実行する

この単純な更新を、バッチごとに、たとえば10Kレコードのセットに分割することができる一種のバッチPL/SQLルーチンを作成しましたか?私はレコードの束の後に私の更新をコミットすることができれば、それはより速く行くだろうと私は記憶を使い果たしていないことを知っている。私はFOR looprow_numを使ってこれを行う簡単な方法があると確信していますが、それほど進歩はありません。への最初の選択を行います

update vr_location set usps_address = mylib.usaddress_utils.parse_address(usps_address); 

答えて

1

最初の1:第二

update vr_location l set l.usps_address=(
    select mylib.string_utils.remove_duplicate_whitespace(
    house_number || ' ' || pre_street_direction || ' ' || street_name || ' ' || 
    street_description || ' ' || post_street_direction) 
from vr_address a where a.address_pk=l.address_pk); 

ここ

は私が n個レコードのバッチごとに実行する必要のある2つのステートメントです何らかの種類のグループ化属性を取得して、目的の行数のグループになるようにします。たとえば、郵便番号の最後の3桁または半ランダムなものなど、グループ化句を試してみてください。

各更新ステートメントの対象となる行を制限するための句をパラメータとして使用して、グループ化句をループします。各繰り返しの最後にコミットします。

+0

我々はvr_locationの列を見ることができれば、我々は何かを提案することができるかもしれません。 –

+0

VR_LOCATIONの列には、zip_coテーブルがあるFKであるzip_co列が含まれています。私はstiliのアドバイスを取って、これを使ってデータのサブセットを得るつもりです。 1つのセット・ベースのステートメントですべてを実行しようとすると、クラッシュすることなく一度に20〜30Kの行を処理するJVMを取得することについてはそれほど重要ではありません。 – Dylan

1

あなた(またはあなたのDBA)が適切にUNDO大きすべきであり、単一のSQLトランザクションとしてこれを行う

利点は以下のとおりです。

  • は、テーブルの上に一貫性を読んで、これはあなたが保持
  • を実行しながら、何かが失敗した場合にトランザクションをロールバックする機能

いずれかの気にしないローディング環境これらを使用してCTAS(select as create table)を使用して、変更された値を持つ新しいテーブルを作成し、インデックスや制約などを構築してからテーブル名を入れ替えます。最近1400万行はそれほど大きくはありません。

+0

UNDO問題のようには聞こえませんが、Javaストアドプロシージャはメモリを解放しません。 –

+0

JVMが私の記憶を殺しているのです。 4GBのRAMを搭載したラップトップで作業し、その半分はOracleで使用され、残りはOS、Javaなどに分割されますが、これを私のDBAに説明しました。また、これはプロダクションではありません。私はexp/impのためのいくつかのデータをプロダクションテーブルに書き込む必要があります。 – Dylan

0

まあ、私はあなたの推薦を取ったので、それを行うために少しPythonをやったので、物事を完了しなければならなかった。私はcx_Oracleを使用して、トランザクションを適切に制御できるようになりました。明らかにPL/SQLは良くなっていましたが、わかりません。 Pythonは私の新しいハンマーです。すべてが爪です!

#!/usr/bin/env python 
import csv 
import time 
import cx_Oracle 

# Parses USPS addresses from voter addresses 
# and inserts them into VR_LOCATION table ready 
# for geocoding. Does batches by zipcode 
def LoadZips(): 
    zipcodes = [] 
    zips = open('OH_ZIP_CODES.txt','r') 
    for line in zips: 
     zip = line[0:5] 
     if zip not in zipcodes: 
      zipcodes.append(zip) 
    zips.close() 
    return zipcodes 

def UpdateAddresses(ziplist): 
    counter = 1 
    total = len(ziplist) 

    for zipcode in ziplist: 
     orcl = cx_Oracle.connect('voter/[email protected]') 
     curs = orcl.cursor() 
     countsql = "select count(*) from vr_location where zip_co = '%s'" % zipcode 
     concatsql = """update vr_location l set l.usps_address=(
        select mizar.string_utils.remove_duplicate_whitespace(
         house_number 
         ||' '||pre_street_direction 
         ||' '||street_name 
         ||' '||street_description 
         ||' '||post_street_direction) 
        from vr_address a where a.address_pk = l.address_pk) 
       where zip_co = '%s'""" % zipcode 
     parsesql = """update vr_location set usps_address = mizar.usaddress_utils.parse_address(usps_address) 
       where zip_co = '%s'""" % zipcode 
     curs.execute(countsql) 

     records_affected = curs.fetchone()[0] 
    if records_affected == 0: 
     print "No records for zipcode %s" % zipcode 
     counter += 1 
     continue 

    print "[%s] %s of %s: %s addresses" % (zipcode, counter, total, records_affected) 
    curs.execute(concatsql) 
    orcl.commit() 
    curs.execute(parsesql) 
    orcl.commit() 
    curs.close() 
    counter += 1 

    # Uncomment this to debug - just steps through X zipcodes  
    #if counter == 3: 
    # print "Cleaning up..." 
    # break 


if __name__ == "__main__": 
    start = time.clock() 
    zipcodes = LoadZips() 
    print "Processing addresses in %s zip codes" % len(zipcodes) 
    UpdateAddresses(zipcodes) 

Blog post on the topic

関連する問題