Django lazy запросов ...
но я не могу этого сделать, так как это занимает около 1,4 секунды, потому что наборы запросов Django ленивы.
Лень запросов Django фактически не оказывает (почти) никакого влияния на производительность.Они ленивы в том смысле, что они откладывают , запрашивая базу данных до , вам нужен результат (например, когда вы начинаете итерацию по нему).Но тогда они извлекут все строки.Таким образом, при каждом извлечении следующей строки нет издержек, все строки извлекаются, и затем Python выполняет итерацию по ней довольно быстро.
Таким образом, лень составляет , а не для строки за строкой.основание строки: не перемещает курсор каждый раз, когда вы хотите получить следующую строку.Таким образом, связь с базой данных (вполне) ограничена.
... и почему она не имеет значение (с точки зрения производительности)
Если количество строк неОгромный (50 000 или более), переход к словарю также должен произойти довольно быстро.Поэтому я подозреваю, что издержки, вероятно, связаны с самим запросом.Тем более, что Django должен «десериализовать» элементы: превратить ответ в кортежи, поэтому, хотя может иметь дополнительные издержки, обычно это будет разумно по сравнению с работой, которая уже выполняется без словарь понимания.Обычно один кодирует задачи в запросах, если они приводят к минус данным, которые передаются в Python.
Например, выполняя подсчет в базе данных, база данных будет возвращать целое число на строку вместофильтруя несколько строк, мы также уменьшаем количество строк (поскольку обычно не все строки соответствуют заданным критериям).Кроме того, в базе данных обычно есть механизмы быстрого поиска, которые увеличивают WHERE
с, GROUP BY
с, ORDER BY
с и т. Д. Но постобработка потока для другого объекта обычно требует такой же величины времени для базы данных.
Таким образом, словарь должен понимать:
<b>{
d[:2]: d[3]
for d in</b> gaming_machine.objects.filter(
Q(points=100) | Q(points=192),created__startswith=today
).values_list(
'machine_no','points'
).annotate(
Count('machine_no')
)
<b>}</b>
Ускорение запросов
Поскольку проблема, вероятно, находится в базе данных, вы, вероятно, захотите рассмотреть некоторые возможности для ускорения.
Создание индексов
Как правило, лучший способ повысить производительность запросов - это создать index для столбцов, которые вы фильтруете по часто , ииметь большое число различных значений.
В этом случае база данных создаст структуру данных, которая хранит для каждого значения этого столбца список строк, соответствующих этому значению.Таким образом, в результате вместо чтения всех строк и выбора соответствующих, база данных может мгновенно получить доступ к структуре данных и, как правило, узнать в разумные сроки, какие строки имеют это значение.
Обратите внимание, что это обычно только помогаетесли столбец содержит большое количество различных значений: если, например, столбец содержит только два значения (в 1% случаев значение равно 0
, а в 99% случаев 1
) и мы фильтруем по очень распространенному значению, это не даст большого ускорения, поскольку набор, который мы должны обработать, имеет примерно одинаковый размер.
Таким образом, в зависимости от того, насколько различны значения, мы можем добавитьиндексы для полей points
и created
:
class gaming_machine(models.Model):
machine_no = models.Integer()
score = models.Integer(<b>db_index=True</b>)
created = models.DateTimeField(auto_now_add=True<b>, db_index=True</b>)
Улучшение запроса
Во-вторых, мы также можем стремиться улучшить сам запрос, хотя это может зависеть от базы данных.(если у нас есть два запроса q1
и q2
, то возможно, что q1
работает быстрее, чем q2
в базе данных MySQL, и q2
работает для примерабыстрее чем q1
в базе данных PostgreSQL).Так что это довольно сложно: конечно, есть вещи, которые обычно работают в целом, но трудно дать гарантии.
Например, иногда x IN (100, 192)
работает быстрее, чем x = 100 OR x = 192
(см. здесь ).Кроме того, здесь вы используете __startswith
, который может работать хорошо - в зависимости от того, как база данных хранит временные метки - но это может привести к вычислительно дорогостоящему запросу, если сначала нужно преобразовать datetime
.В любом случае, использование created__date
более декларативно, так как дает понять, что вы хотите, чтобы дата created
была равна сегодняшнему, поэтому, возможно, более эффективный запрос:
{
d[:2]: d[3]
for d in gaming_machine.objects.filter(
<b>points__in=[100, 192], created__date=today</b>
).values_list(
'machine_no','points'
).annotate(
Count('machine_no')
)
}