2012-06-30 23 views
2

我有postgresql數據庫,我正在更新大約100000條記錄。我使用session.merge()來插入/更新每條記錄,並在每1000條記錄後進行一次提交。提交過程中刪除錯誤查詢

i=0 
for record in records: 
    i+=1 
    session.merge(record) 
    if i%1000 == 0: 
     session.commit() 

此代碼正常工作。在我的數據庫中,我有一個帶有UNIQUE字段的表,並且有一些重複記錄插入到它中。發生這種情況時會出現錯誤,稱該字段不是唯一的。由於我一次插入1000條記錄,因此回滾不會幫助我跳過這些記錄。有什麼辦法可以跳過session.merge()爲重複記錄(除了解析所有記錄找到重複的記錄當然)?

+0

我懷疑「解析所有記錄以找到重複記錄」是保持ACID和UNIQUE語義的唯一方法。另一方面,讀取100'000的唯一ID字段並檢查客戶端代碼中的重複項將比替代方案快得多,並且可以在假設合併的情況下在「容許緩慢」和「方式太慢」之間做出區別桌子在你下面並沒有太多變化。 – msw

+0

@msw是的,即時通訊卡在岩石和困難的地方之間。合併表不改變 –

回答

0

這是最適合我的選項,因爲具有重複唯一鍵的記錄數量最少。

def update_exception(records, i, failed_records): 
    failed_records.append(records[i]['pk']) 
    session.rollback() 
    start_range = int(round(i/1000,0) * 1000) 
    for index in range(start_range, i+1): 
     if records[index]['pk'] not in failed_records: 
      ins_obj = Model() 
      try: 
       session.merge(ins_obj) 
      except: 
       failed_records.append(json_data[table_name][index-1]['pk']) 
       pass 

說,如果我在2375遇到錯誤我存儲在failed_records 2375記錄的主鍵「PK」,然後我再次作出從2000年到2375這似乎不是做快得多提交一個接一個。

+0

同樣,這是我發現特定於我的需求的解決方案。我沒有遇到許多重複唯一字段值的記錄。任何想法如何優化它是受歡迎的 –

3

我想你已經知道了這一點,但讓我們從一條教條開始:你指定該字段必須是唯一的,所以你必須讓數據庫檢查唯一性或處理錯誤,不要讓它發生。

檢查的獨特性:

if value not in database: 
    session.add(value) 
session.commit() 

不檢查的獨特性和捕捉異常。

try: 
    session.add(value) 
    session.commit() 
except IntegrityError: 
    session.rollback() 

第一個有競爭條件。我傾向於使用第二種模式。

現在,回到實際問題,如果您想確保數據庫中某列的唯一性,那麼顯然您必須讓db確保加載的值的實際唯一性,或者讓數據庫給你一個錯誤,你處理它。

這顯然比將100k對象添加到會話並將它們全部提交慢很多,但這就是數據庫的工作原理。

您可能想要考慮按摩正在加載數據庫的數據,然後再嘗試加載它,以確保唯一性。這樣,當你加載它時,你可以放棄檢查唯一性的需要。如果您正在從csv或文本文件加載,那麼使用命令行工具很容易。

1

您可能需要考慮從PostgreSQL文檔中的this example開始寫一個函數。

+0

我不太明白。我如何在sqlalchemy中做到這一點?我可以在sqlalchemy中訪問這個函數嗎?或者我將它作爲一個sql腳本來運行? (im python,postgres和sqlalchemy的noob) –

+0

我不知道sqlalchemy,但我認爲你會讓我們另一個工具(如psql或pgadmin)來創建函數,並從sqlalchemy中引用函數。 – kgrittn

+0

即時通訊不知道我知道如何做到這一點。你能指導我怎麼做嗎? –

2

您可以使用SAVEPOINT(通過begin_nested()公開SQLAlchemy)進行「部分回滾」。你可以這樣做只是這樣的:

for i, record in enumerate(records): 
    try: 
     with session.begin_nested(): 
      session.merge(record) 
    except: 
     print "Skipped record %s" % record 
    if not i % 1000: 
     session.commit() 

筆記上面:

  1. 在Python中,我們從來沒有的 「I = I + 1」 的事情。使用enumerate()
  2. with session.begin_nested():begin_nested()相同,則commit()如果沒有例外,或者rollback()如果是這樣。