2009-05-13 5 views
0

Мне нужно запустить несколько относительно простых операторов SQL-обновления, чтобы обновить один столбец в таблице Oracle с 14,4 миллионами строк. Один оператор выполняет функцию, написанную на Java, и JVM исчерпывает память, поскольку я делаю обновление на всех 14.4 миллиона строк.Запуск операторов обновления Oracle в пакетном режиме

Вы написали своего рода пакетную PL/SQL-процедуру, которая может разбить это простое обновление на множество, скажем, 10K записей за партию? Я знаю, что если я смогу перенести свои обновления после множества записей, это будет намного быстрее, и у меня не будет нехватки памяти. Я уверен, что есть простой способ сделать это, используя FOR loop и row_num, но я не добился большого прогресса.

Вот два заявления, мне нужно работать для каждой партии п записей:

первый:

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); 

второй:

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

ответ

1

ли первоначальный выбор для извлеките какой-либо атрибут группировки, чтобы в итоге вы получили группы с нужным количеством строк. Поэкспериментируйте с предложением группировки, например, последние три цифры почтового кода или что-то полу-случайное.

Завершите работу над предложением группировки, используя параметр как параметр для ограничения строк, предназначенных для каждого оператора обновления. зафиксировать в конце каждой итерации.

+0

Если бы мы могли видеть столбцы в vr_location, мы можем быть в состоянии предложить что-то. –

+0

Столбцы в VR_LOCATION включают столбец zip_co, который является FK обратно в таблицу zip_code. Я собираюсь взять совет stili и использовать его, чтобы получить подмножества данных. Речь идет не о попытке сделать все в одном наборе, а о том, как заставить JVM обрабатывать 20-30K строк одновременно без сбоев. – Dylan

1

Вы (или ваш DBA) должен размер отмененных правильно и сделать это как одной транзакции SQL

Преимущества:

  • согласованность чтения на столе в то время как это происходит
  • вы сохранить возможность отката транзакции в случае, если что-то не работает

Если вы находитесь в какой-то загрузочной среде, где вам не все равно затем используйте CTAS (создайте таблицу как выбор), чтобы создать новую таблицу с измененным значением, построить индексы, ограничения и т. д., а затем поменять имена таблиц. В эти дни 14 миллионов строк не так велики.

+0

Не похоже на проблему UNDO, но с хранимой процедурой java, не освобождающей память. –

+0

Да, это то, что JVM убивает мою память. Работа с ноутбуком с 4 ГБ оперативной памяти, половина из которых используется oracle, а остальная часть разделена между ОС, Java и т. Д. Но я упомянул об этом своему администратору базы данных.Кроме того, это не производство: мне нужно внести некоторые данные для 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

Смежные вопросы