2013-04-14 60 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」與增加arraysizeoutputtypehandler該字符串轉換爲Unicode。從另一種方法調用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秒內完成。這正是我期望的基於我試圖替換的舊腳本的性能。

由於新工具可以將多個數據庫模式作爲輸入參數,因此我還通過提供相同模式進行了六次測試。記錄的執行時間均表明,該問題只發生在第一次迭代:

:: 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調試器來逐步執行這一步,看起來行for row in cursor:負責約10分鐘的執行。我也注意到在這段時間內,python.exe進程的內存使用量不斷增加。

現在的問題是在該行的同一代碼的執行時間是如此的不同(儘管相當重複的)會發生什麼?當Cursor用作迭代器時,cx_Oracle在內部執行什麼樣的操作?我在包裝代碼中導致了什麼錯誤?誠然,我從來沒有見過任何類似的發生是由於舊的腳本並沒有使用類也不是發電機,而只是從遊標進行fetchall

非常感謝提前。

回答

0

不知道這是否適用於你的問題,但設置一個大ARRAYSIZE光標的時候,我只是一個嚴重的性能問題,加強昨天。

我不得不使用cursor.fetchall()和cursor.fetchmany()兩種方法。

的cursor.fetchall()已服用0.1秒來完成,cursor.fetchmany()1,5秒。

一些調試後,我發現我fetch_many之前(設置cursor.arraysize一個大值(100.000))。這會導致cxOracle驅動程序爲arrayize數量的行分配mem空間。結合使用大量varchar2(4000)列的查詢,這可以總結爲在每次調用之前分配的一些x * 100MB,然後釋放。

也可能是你的問題。