Большой поиск по базе данных Sqlite - PullRequest
2 голосов
/ 16 июня 2009

Как можно реализовать эффективный поиск в большой базе данных 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). Так что регулярные выражения не едят время.

Запрос оболочки Sqlite3:

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

работает примерно за секунду. Таким образом, основное потребление времени происходит из-за неэффективного извлечения данных ORM из базы данных. Я предполагаю, что SQLObject захватывает здесь все строки, в то время как Sqlite затрагивает только необходимые поля.

Ответы [ 6 ]

3 голосов
/ 16 июня 2009

Лучшим способом было бы переработать вашу логику, чтобы сделать выборку в базе данных, а не в вашей программе на Python.

Вместо того, чтобы делать Item.select (), вы должны переработать его, чтобы сделать Item.select ("" "name LIKE ....

Если вы сделаете это и убедитесь, что у вас есть индексированные столбцы name и skim, он вернется очень быстро. 90000 записей - не большая база данных.

2 голосов
/ 16 июня 2009

30 секунд для получения 90 000 строк могут быть не такими уж плохими.

Вы оценили время, необходимое для выполнения следующих действий?

    for item in Item.select():
        pass

Просто чтобы посмотреть, является ли время БД, сетевым временем или временем приложения?

Если ваша БД SQLite физически очень велика, вы могли бы просто посмотреть на множество физических операций ввода-вывода, чтобы прочитать все эти данные базы данных.

0 голосов
/ 26 ноября 2009

Изначально было выполнено регулярное выражение через Python для y_serial, но это был отброшен в пользу SQLite GLOB (который намного быстрее). GLOB похож на LIKE за исключением того, что его синтаксис более условный: * вместо%,? вместо _.

См. Сноски на http://yserial.sourceforge.net/ для более подробной информации.

0 голосов
/ 17 июня 2009

Я бы определенно принял предложение Рида передать фильтр в SQL (но забудьте об индексной части).

Я не думаю, что выбор только указанных полей или всех полей имеет значение (если у вас много больших полей). Могу поспорить, что SQLObject создает / создает экземпляры 80K-объектов и помещает их в Session / UnitOfWork для отслеживания. Это определенно может занять некоторое время.

Также, если вам не нужны объекты в вашем сеансе, должен быть способ выбрать только те поля, которые вам нужны, с помощью создания пользовательского запроса, чтобы не создавались Item объекты, а только кортежи.

0 голосов
/ 17 июня 2009

Учитывая ваш пример и развивая ответ Рида, ваш код может выглядеть примерно так:

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 записей и, возможно, выполнять две операции регулярного выражения для каждой записи.

Вы можете найти некоторую информацию здесь о методе .contains () здесь .

А также Руководство по языку SQL-выражений SQLAlchemy здесь .

Конечно, в приведенном выше примере предполагаются имена переменных для вашего itemsTable и столбца, в котором он находится (nameColumn и skimColumn).

0 голосов
/ 16 июня 2009

Если вам действительно нужно использовать регулярное выражение, вы ничего не сможете сделать, чтобы значительно ускорить его.

Лучше всего было бы написать функцию sqlite, которая выполняет сравнение для вас в движке db вместо Python.

Вы также можете переключиться на db-сервер, такой как postgresql, который поддерживает SIMILAR.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...