2013-04-14 2 views
0

데이터베이스에 대해 일련의 동적 생성 쿼리를 실행하고 결과를 가져 오는 최종 쿼리를 최종적으로 수행하는 구성 요소를 작성했습니다. 이 모든 로직은 생성기에 래핑됩니다. 다른 구성 요소는이 생성기에 연결하여 결과를 파일 (이 테스트의 경우 탭으로 구분 된 텍스트 파일)에 스풀링 할 수 있습니다.cx_Oracle 커서가 몇 분 동안 멈춤 루프

def cycle(self, schema, matchprofile, fixedcond): 

    cursor = self.cursor 
    cursor.set_schema(schema) 
    cursor.execute('TRUNCATE TABLE schema.table') 
    metaatts = self.get_metaattributes(schema) 

    for condset in matchprofile: 
     condsql = self.dostuffwith(self, matchprofile, fixedcond) 
     qry = self.qrybase.replace('<<condset>>', condset).replace('<<condsql>>', condsql) 
     cursor.execute(qry)    # queries performing logic aganst database 

    cursor.execute(self.finalqry)   # select query extracting results 

    for row in cursor: 
     yield Row(row, metaatts.copy()) 

    if self.counts: 
     self.counter.addto(cursor.rowcount) 

cursor는 서브 클래스 'cx_Oracle.Cursor가'증가 arraysize 유니 코드 문자열로 변환하는 outputtypehandler 함께 여기 발생기 함수의 코드가있다. cycle은 여러 입력 스키마의 출력을 하나의 스트림으로 묶는 다른 메서드에서 호출됩니다.

cycles = itertools.imap(self.cycle, schemas, itertools.repeat(matchprofile), itertools.repeat(fixedcond)) 
rows = itertools.chain.from_iterable(cycles) 

저는 이것을 Python 2.6에서 실행합니다.

이미 전체 스크립트를 수십 번 실행했으며 대부분의 경우 데이터베이스 스키마를 완료하는 데 약 11-12 분이 걸렸습니다. 이것은 예상 이상입니다. 예상치 못한 나에게, 일부 시도에서 스크립트는 약 55 초 만에 완료되었습니다. 그것은 제가 대체하려고하는 레거시 스크립트의 성능을 기반으로 기대했던 것입니다.

새 도구는 입력 매개 변수로 여러 데이터베이스 스키마를 사용할 수 있으므로 동일한 스키마를 6 번 제공하여 테스트를 수행했습니다. 나는 또한 합리적인 생산 실행을 프로파일 관리

:: 1597 records in 11:33 
:: 1597 records in 0:56 
:: 1597 records in 0:55 
:: 1597 records in 0:55 
:: 1597 records in 0:55 
:: 1597 records in 0:55 

:: total 9582 records in 16:10 

...

109707 function calls (109627 primitive calls) in 57.938 CPU seconds 

Ordered by: internal time 

ncalls tottime percall cumtime percall filename:lineno(function) 
    12 56.154 4.679 56.154 4.680 {function execute at 0x010074B0} 
    1 0.819 0.819 0.819 0.819 ora.py:194(__init__) 
    1 0.387 0.387 0.387 0.387 {function parse at 0x010075B0} 
    1598 0.331 0.000 56.543 0.035 DuplicateDetector.py:219(cycle) 
    1598 0.118 0.000 0.118 0.000 {method 'writerow' of '_csv.writer' objects} 
30295 0.029 0.000 0.029 0.000 {_codecs.utf_8_decode} 
    1598 0.025 0.000 56.720 0.035 dsv.py:146(generate) 
30310 0.022 0.000 0.029 0.000 {method 'encode' of 'unicode' objects} 

... 과도한 타이밍 : 로그인 한 실행 시간은 문제가 첫 번째 반복에서 발생 표시했다.

109707 function calls (109627 primitive calls) in 701.093 CPU seconds 

Ordered by: internal time 

ncalls tottime percall cumtime percall filename:lineno(function) 
    1598 644.514 0.403 699.827 0.438 DuplicateDetector.py:219(cycle) 
    12 55.247 4.604 55.248 4.604 {function execute at 0x010084B0} 
    1 0.783 0.783 0.783 0.783 ora.py:194(__init__) 
    1 0.283 0.283 0.283 0.283 {function parse at 0x010085B0} 
    1598 0.121 0.000 0.121 0.000 {method 'write' of '_csv.writer' objects} 
30295 0.036 0.000 0.036 0.000 {_codecs.utf_8_decode} 
    1598 0.025 0.000 700.006 0.438 dsv.py:146(generate) 
30310 0.022 0.000 0.028 0.000 {method 'encode' of 'unicode' objects} 
30295 0.021 0.000 0.057 0.000 utf_8.py:15(decode) 

그것은 첫 번째 경우에 데이터베이스 작업의 시간 후자의 대부분, 실행 시간의 대부분을하면서 cycle 발전기에 소요되는 것을 분명하다. Idle 디버거를 사용하여이 단계를 단계별로 실행했으며 약 10 분의 실행 시간은 for row in cursor:입니다. 나는 또한 그 시간 동안 python.exe 프로세스의 메모리 사용량이 지속적으로 증가한다는 것을 알아 차렸다.

이제는 동일한 코드의 실행 시간이 매우 다르기 때문에 그 행에서 어떤 문제가 발생합니까? Cursor가 반복자로 사용될 때 cx_Oracle은 내부적으로 어떤 종류의 연산을 수행합니까? 이 오류를 일으키는 배치 코드에서 내가 실수했을 수있는 점은 무엇입니까? 틀림없이 클래스 나 생성자를 사용하지 않은 이전 스크립트에서는 비슷한 것을 발견하지 못했지만 단순히 커서에서 fetchall을 수행했습니다.

미리 감사드립니다.

답변

0

이 문제가 귀하의 문제에 해당되는지 모르겠지만 어제 커서를 사용하여 큰 배열을 설정할 때 심각한 성능 문제가 발생했습니다.

cursor.fetchall() 및 cursor.fetchmany()를 사용하는 두 가지 방법이 있습니다.

커서 .fetchall()은 커서를 끝내기 위해 0.1 초가 걸렸습니다. cursor.fetchmany() 1.5 초.

일부 디버깅 후 fetch_many() 전에 cursor.arraysize를 큰 값 (100.000)으로 설정하는 것으로 나타났습니다.이렇게하면 cxOracle 드라이버가 행의 arraysize num에 대한 mem 공간을 할당합니다. varchar2 (4000) 열이 많은 쿼리와 결합하여 각 호출 전에 x * 100MB를 할당 한 다음 해제합니다.

문제 일 수도 있습니다.