#python #django #database #sqlite #lookup
#python #django #База данных #sqlite #поиск
Вопрос:
Я запускаю веб-сервис, в котором пользователь отправляет слово в качестве запроса, и я использую это слово для фильтрации записей в моей базе данных (по умолчанию Django SQLite). Отношение слова к записи является взаимно однозначным. Это означает, что есть два возможных случая:
- Слово существует в базе данных -> Вернуть связанный
Entry
. - Слово не существует -> Выбросить исключение.
Затем следующий поиск должен вернуть набор запросов с 1 или 0 объектами:
Entry.objects.filter(word__iexact=word)
Ожидаемое поведение:
Случаи 1 и 2 не отличаются заметно по скорости.
Текущее поведение:
- Случай 1 занимает не более половины секунды.
- Случай 2 занимает вечность, около 1-2 минут.
Я нахожу это загадочным. Если существующее word
можно искать независимо от того, где оно находится в базе данных, то почему случай 2 занимает вечность? Я не специалист по django или базам данных, поэтому мне кажется, что я здесь что-то упускаю. Стоит ли просто настраивать базу данных другого типа, чтобы посмотреть, поможет ли это?
Вот соответствующая часть моего кода. Я определяю вспомогательную функцию, которая вызывается из представления:
mysite/myapp/utils.py
from .models import Entry
def get_entry(word):
if Entry.objects.filter(word__iexact=word).exists():
queryset = Entry.objects.filter(
word__iexact=word
) # Case insensitive exact lookup
entry = queryset[0] # Retrieve entry from queryset
return entry
else:
raise IndexError
Комментарии:
1. Сколько записей в вашей базе данных?
2. Имейте в виду, что SQLite обычно не используется для серьезных веб-приложений в производстве. В основном это удобный инструмент для разработки.
3. Вспомогательные функции способствуют ошибочному коду. Это один из примеров: вся ваша вспомогательная функция может быть сведена к одной строке с помощью более чистого api:
Entry.objects.filter(word__iexect=word).first()
, который возвращает None или item . Итак, почему вы вызываете IndexError?4. Вот почему я использовал комментарий. И я задал вопрос, потому что я подозревал, что вы используете IndexError для «повторной попытки» и что нет никакой разницы, кроме цикла, выполняемого после сбоя.
5. Ваш запрос по существу сканирует таблицу в поисках соответствующей записи. Если он найдет его, он может прекратить поиск раньше, но если этого не произойдет, он должен пройти через всю таблицу. Я подозреваю, что имеет значение, где слово находится в таблице, и что для некоторых существующих слов запрос все равно займет много времени. Вы можете попробовать поискать «индекс django sqlite без учета регистра» или что-то в этом роде, чтобы ускорить выполнение этих запросов.
Ответ №1:
Это нормально, особенно с несколькими миллионами записей в sqlite, и я предполагаю, что без индекса.
Пропущенное слово всегда должно проходить через все записи, если нет полезного индекса. Найденное слово завершится, как только будет найдено. Нет заметной разницы, если слово, которое вы ищете, является последним словом в порядке таблицы.
И это на самом деле потому, что вы используете срез, поэтому срез использует ОГРАНИЧЕНИЕ, и база данных может перестать искать первое совпадение.
Комментарии:
1. Означает ли это, что мне лучше просто стиснуть зубы и установить другую базу данных?
2. Вы должны хотя бы указать индекс в поле. Но я бы не стал спокойно спать с миллионами записей в sqlite. Похоже, что это так.
3. Возможно, добавьте это в ответ, чтобы другие могли его увидеть