在合理的时间内在Python中查询(漂亮)大关系数据?

时间:2012-03-14 02:05:03

标签: python database sqlite indexing bigdata

我的电子表格大约有1.7万行,总计1 GB,需要对其执行各种查询。对Python最熟悉的是,我的第一种方法是将一堆字典组合在一起,以便于我试图进行的查询。例如。如果我需要能够访问具有特定区号和年龄的每个人,我会制作一个areacode_age二维字典。我最终需要相当多的这些,这使我的内存占用量增加(大约10GB),即使我有足够的RAM来支持这一点,但这个过程仍然很慢。

此时,好像我在玩傻逼的游戏。 “这就是关系数据库的用途,对吧?”,我想。我导入了sqlite3并将我的数据导入到内存数据库中。我认为数据库是为了速度而构建的,这将解决我的问题。

事实证明,做“SELECT(a,b,c)FROM foo WHERE date1< = d AND date2> e AND name = f”这样的查询需要0.05秒。为我的1.7米行执行此操作需要24小时的计算时间。对于这个特定的任务,我对词典的hacky方法快了大约3个数量级(在这个例子中,我无法明确地键入date1和date2,所以我得到的每一行都与名称匹配,然后按日期过滤)。

所以,我的问题是,为什么这么慢,我怎么能让它快?什么是Pythonic方法?我一直在考虑的可能性:

  • sqlite3太慢了,我需要更重量级的东西
  • 我需要以某种方式更改我的架构或我的查询更多...优化?
  • 到目前为止我尝试的方法完全错误,我需要一种全新的工具
  • 我在某处读过,在sqlite 3中,重复调用cursor.execute要比使用cursor.executemany慢得多。事实证明,executemany甚至与select语句不兼容,所以我认为这是一个红色的鲱鱼。

感谢。

3 个答案:

答案 0 :(得分:4)

  

sqlite3太慢了,我需要更重量级的东西

首先,sqlite3速度快,有时比MySQL快

其次,你必须使用索引,在(date1,date2,name)中放一个复合索引会使事情显着提升

答案 1 :(得分:2)

  

但事实证明,做一个像“SELECT(a,b,c)FROM”这样的查询   foo WHERE date1< = d AND date2> e AND name = f“需要0.05秒   对于我的1.7米行,这需要24小时的计算时间。我的hacky   使用字典的方法快了大约3个数量级   这个特殊的任务(在这个例子中,我无法键入date1   和date2显然,所以我得到的每一行都与名字相符   然后按日期过滤。

你真的尝试这个并且观察它需要24小时吗?处理时间不一定与数据大小成正比。

您是否建议您可能需要运行SELECT (a, b, c) FROM foo WHERE date1<=d AND date2>e AND name=f 170万次?您只需运行一次,它将返回与您的查询匹配的整个行子集。

170万行不小,但对于完全在本地计算机内存中的数据库来说肯定不是问题。 (没有慢速磁盘访问;没有慢速网络访问。)


证明在布丁中。这对我来说非常快(大部分时间用于生成大约1000万个随机浮点数。)

import sqlite3, random

conn = sqlite3.connect(":memory:")
conn.execute("CREATE TABLE numbers (a FLOAT, b FLOAT, c FLOAT, d FLOAT, e FLOAT, f FLOAT)");
for _ in xrange(1700000):
    data = [ random.random() for _ in xrange(6) ];
    conn.execute("INSERT INTO numbers VALUES (?,?,?,?,?,?)", data)

conn.commit()

print "done generating random numbers"

results = conn.execute("SELECT * FROM numbers WHERE a > 0.5 AND b < 0.5")
accumulator = 0
for row in results:
    accumulator += row[0]

print ("Sum of column `a` where a > 0.5 and b < 0.5 is %f" % accumulator)

编辑:好的,所以你真的需要运行170万次。

在这种情况下,您可能需要的是索引。引用维基百科:数据库索引:

  

数据库索引是提高数据速度的数据结构   数据库表上的检索操作,代价是写入速度较慢   并增加了存储空间。可以使用一个或多个创建索引   数据库表的列,提供快速随机的基础   查找和有效访问有序记录。

你会像CREATE INDEX dates_and_name ON foo(date1,date2,name)这样做,然后(我相信)像往常一样执行其余的SELECT语句。试试这个,看看它是否加快了速度。

答案 2 :(得分:0)

由于您已经在谈论SQL,最简单的方法是:

  1. 将所有数据都放到MySQL表中。它应该在170万行中表现良好。
  2. 添加所需的索引,检查设置,确保它run fast on big table
  3. 从Python访问
  4. ...
  5. 利润!