2012-02-22 408 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行,即使未使用该行,也会将该行的第一项转换为字符串。
相关问题