大型Sqlite数据库搜索

时间:2009-06-16 17:46:19

标签: python sql database search performance

如何实现高效的大型Sqlite数据库搜索(超过90000个条目)?

我正在使用Python和SQLObject ORM:

    import re
    ...

    def search1():
        cr = re.compile(ur'foo')
        for item in Item.select():
            if cr.search(item.name) or cr.search(item.skim):
                print item.name

此功能运行时间超过30秒。我应该如何让它跑得更快?

UPD :测试:

    for item in Item.select():
        pass

...几乎与我的初始函数相同(0:00:33.093141到0:00:33.322414)。所以regexps没时间吃。

Sqlite3 shell查询:

    select '' from item where name like '%foo%';

运行大约一秒钟。因此,主要的时间消耗发生是由于从数据库中获取的ORM数据效率低下。我猜SQLObject在这里抓取整行,而Sqlite只触及必要的字段。

6 个答案:

答案 0 :(得分:3)

最好的方法是重写逻辑,在数据库中而不是在python程序中进行选择。

而不是做Item.select(),你应该重做它来做Item.select(“”“命名LIKE ....

如果你这样做,并确保索引名称和脱脂列,它将很快返回。 90000个条目不是一个大型数据库。

答案 1 :(得分:2)

获取90,000行的30秒可能并不是那么糟糕。

您是否已对执行以下操作所需的时间进行基准测试?

    for item in Item.select():
        pass

只是看时间是DB时间,网络时间还是申请时间?

如果您的SQLite数据库在物理上非常大,您可能只需要很多物理I / O来读取所有数据库内容。

答案 2 :(得分:0)

如果你真的需要使用正则表达式,那么你无法做任何事情来加速它的发展。

最好的方法是编写一个sqlite函数,在db引擎中执行比较,而不是Python。

您也可以切换到支持SIMILAR的postgresql等db服务器。

http://www.postgresql.org/docs/8.3/static/functions-matching.html

答案 3 :(得分:0)

根据您的示例并扩展Reed的答案,您的代码可能看起来有点像:

import re
import sqlalchemy.sql.expression as expr

...

def search1():
    searchStr = ur'foo'
    whereClause = expr.or_(itemsTable.c.nameColumn.contains(searchStr), itemsTable.c.skimColumn.contains(searchStr))
    for item in Items.select().where(whereClause):
        print item.name

转换为

SELECT * FROM items WHERE name LIKE '%foo%' or skim LIKE '%foo%'

这将使数据库为您完成所有过滤工作,而不是获取所有90000记录并对每条记录执行两次正则表达式操作。

You can find some info here on the .contains() method here

以及SQLAlchemy SQL Expression Language Tutorial here

当然上面的示例假定您的itemsTable及其所拥有的列(nameColumn和skimColumn)的变量名称。

答案 4 :(得分:0)

我肯定会建议Reed将过滤器传递给SQL(尽管忘记了索引部分)。

我不认为只选择指定的字段或所有字段会有所不同(除非你有很多大字段)。我敢打赌,SQLObject创建/实例化80K对象并将它们放入Session / UnitOfWork进行跟踪。这肯定需要一些时间。

此外,如果您的会话中不需要对象,则必须有一种方法可以使用自定义查询创建选择所需的字段,以便不创建Item个对象,而只创建元组。

答案 5 :(得分:0)

最初通过Python做正则表达式被认为是y_serial,但那 被放弃了有利于SQLite的GLOB(这要快得多)。 GLOB与LIKE类似,只是它的语法更多 常规:*代替%,?而不是_。

有关详细信息,请参阅http://yserial.sourceforge.net/处的尾注。