2

我有一个大约 170 万行、总计 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 秒。为我的 170 万行执行此操作需要 24 小时的计算时间。对于这个特定的任务,我使用字典的 hacky 方法大约快了 3 个数量级(而且,在这个例子中,我显然无法键入 date1 和 date2,所以我得到了与名称匹配的每一行,然后按日期过滤)。

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

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

谢谢。

4

3 回答 3

4

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

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

其次,你必须使用索引,在 (date1, date2, name) 中放置一个复合索引会显着加快速度

于 2012-03-14T02:23:56.150 回答
2

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

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

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

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 万次。

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

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

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

于 2012-03-14T02:15:43.183 回答
0

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

  1. 将所有数据放到 MySQL 表中。它应该对 170 万行表现良好。
  2. 添加您需要的索引,检查设置,确保它可以在大表上快速运行
  3. 从 Python 访问它
  4. ...
  5. 利润!
于 2012-03-14T02:20:53.383 回答