2012-02-22 69 views
10

我當前正在使用pyodbc從數據庫中選擇一大列行。然後將結果複製到一個大的列表中,然後我嘗試遍歷列表。在放棄Python之前,嘗試用C#創建它之前,我想知道是否有某件事情我做錯了。遍歷大列表時,Python運行速度很慢

clientItems.execute("Select ids from largetable where year =?", year); 
allIDRows = clientItemsCursor.fetchall() #takes maybe 8 seconds. 

for clientItemrow in allIDRows: 
    aID = str(clientItemRow[0]) 
    # Do something with str -- Removed because I was trying to determine what was slow 
    count = count+1 

一些詳細信息:

  • for循環正在運行以每秒約5圈,這似乎出奇的慢我。
  • 所選的總行數是〜489,000。
  • 它運行的機器有很多RAM和CPU。它似乎只運行一個或兩個內核,RAM爲1.72GB的4GB。

任何人都可以告訴我什麼是錯的?腳本運行緩慢嗎?

感謝

+1

'clientItemRow [0]'真的很大嗎? 489,000行是低的,但5行/秒的速度慢得可笑。另外,如果我錯了,有人可以糾正我,但我敢肯定你的代碼只能在一個內核上運行,但仍應該比每秒5次更快。此外,您可以使用內置的cProfile來查看您打到瓶頸的位置。 – prelic 2012-02-22 20:09:03

+0

至於CPU的使用情況 - 如果你用取得的結果做了一些奇特的事情,你可以通過使用Python的多處理模塊來獲得更多的CPU核心 - 但是我們可以首先理解這種交互方式。 – jsbueno 2012-02-22 20:09:20

+0

'type(allIDRows)'返回什麼? – tMC 2012-02-22 20:10:09

回答

17

這不應該是用Python自身名單慢 - 但也許ODBC的驅動程序返回了試圖成爲一個聰明的「懶」對象,但只是變得緩慢。嘗試只是在做

allIDRows = list(clientItemsCursor.fetchall())

在你的代碼和後進一步基準。

+0

哇。我繼續做了這個改變,每秒鐘的數字超過了1000。這真是太神奇了。將接受這個答案。 – nycynik 2012-02-22 20:09:33

+5

找到pyodbc項目的網頁並將其作爲錯誤輸入會是一件好事。如果fetchall沒有返回一個列表,它應該比列表更有效率,而不是顯示擋板 – jsbueno 2012-02-22 20:16:24

+0

偉大的答案,讓我想到的是列表存儲這種收集數據的最快方式?一個集合,元組,dict(帶有虛擬值)等比這個列表更快嗎? – Lostsoul 2012-02-22 20:41:35

1

,因爲你第一次加載所有結果在內存中,在一個列表進行迭代這可能是緩慢的。嘗試迭代遊標。

而且不,腳本不應該是慢。

clientItemsCursor.execute("Select ids from largetable where year =?", year); 
for clientItemrow in clientItemsCursor: 
    aID = str(clientItemrow[0]) 
    count = count + 1 
+1

這與我所建議的方向相反 - 只有測試纔會說明,我希望O.P.能讓我們更新。無論如何,列表中的迭代不應該慢,但是可能'對於cursor.fetchall()中的clientItemRow():...',因爲您建議更好。 – jsbueno 2012-02-22 20:08:06

+1

我嘗試過這種薄荷醇,而且它一點都不快。這符合pyODBC文檔。迭代它們仍然非常緩慢。 – nycynik 2012-02-22 20:13:32

1

這裏需要更多的調查

(如果你開始將在中間的東西,但只是迭代的大名單應該是快速Python列表可以很慢)...考慮下面的腳本:

bigList = range(500000) 
doSomething = "" 
arrayList = [[x] for x in bigList] # takes a few seconds 
for x in arrayList: 
    doSomething += str(x[0]) 
    count+=1 

這與您的腳本非常相似,減去數據庫內容,並且需要幾秒鐘才能在我的非常快的機器上運行。

0

當你直接連接到你的數據庫(我的意思是你得到一個SQL提示符)時,多少個secods運行這個查詢?

當查詢結束後,你會得到類似這樣的消息:

NNNNN rows in set (0.01 sec) 

所以,如果時間是如此之大,和您的查詢速度慢作爲「原生」,可能是你必須在創建索引那張桌子。

0

因爲你是

  1. 獲取所有的結果
  2. 分配內存和分配的值是內存中創建列表allIDRows
  3. 遍歷該列表和計數這是緩慢的。

如果execute返回一個遊標,那麼使用遊標是有好處的,並且在你回收內容並在mem分配上節省時間時開始計數。

clientItemsCursor.execute("Select ids from largetable where year =?", year); 
for clientItemrow in clientItemsCursor: 
    count +=1 

其他提示:

  • 同比創建索引
  • 使用「選擇... COUNT(*),以獲得該年度的計數」這很可能會在優化D b。
  • 如果不需要,刪除aID行,即使未使用該行,也會將該行的第一項轉換爲字符串。