我正在使用 django 1.8.4 编写一个 web 应用程序。后端使用MySQL 5.6 (MyISAM)。最近表记录数达到100万条,查询所有不同的记录日期需要1-1.5秒。但使用MySQL客户端,需要不到0.001秒。
Django 代码
class Model1(models.Model):
date = models.DateField(db_index=True)
# benchmark code
db_dates = Model1.objects.dates("date", kind="day")
MySQL 查询:
SELECT date FROM `table1` group by date ORDER BY `date` ASC
MySQL 客户端显示:总计 620,查询花费了 0.0025 秒。
更新 1
关于@e4c5提示,我转储了django查询。实际上,查询中存在类型转换。这就是速度慢的根本原因。
{u'time': u'1.989',
u'sql': u"SELECT DISTINCT CAST(DATE_FORMAT(`model1_table`.`date`, '%Y-%m-%d 00:00:00') AS DATETIME) AS `datefield` FROM `model1_table` WHERE `model1_table`.`date` IS NOT NULL ORDER BY `datefield` ASC"}
即使我在 MySQL 客户端中手动运行查询,它也会变得很慢。我注意到第二个查询进行了类型转换。
是否需要进行类型转换(date
到 datetime
)?我该如何解决这个问题?
无论如何,我已经解雇了 issue here用于跟踪。
最佳答案
根本原因
Django 在内部生成这样的查询:
SELECT DISTINCT
CAST(
DATE_FORMAT(`model1_table`.`date`, '%Y-%m-%d 00:00:00') AS DATETIME
) AS `datefield`
FROM `model1_table` WHERE `model1_table`.`date` IS NOT NULL
ORDER BY `datefield` ASC"
显然,所有 DATE 字段都会首先转换为 DATETIME,然后使用其日期部分。性能影响与记录数量成比例。
解决方案
- 正如@e4c5提到的,我们可以使用
results = set(obj.date for obj in Model1.objects.distinct('date'))
但这仅适用于 PostgreSQL。它不适用于 MySQL。我们将收到错误:“此数据库后端不支持 DISTINCT ON 字段”。
- @BurhanKhalid 的答案将检索所有日期对象给客户端,这也很慢。我很快发现我们可以添加一个
distinct
来过滤服务器端的结果。
这是我的修改版本。
results = set(Model1.objects.order_by('date').values_list('date', flat=True).distinct())
现在从 150 万条记录中查询不同日期字段只需要 0.004 秒。酷!
关于mysql - 使用 Django queryset 查询日期对象存在性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32795047/