我正在使用django 1.8.4写一个web应用程序。后端使用MySQL 5.6 (MyISAM)。最近表记录的数量达到100万条,查询所有不同的记录日期需要1-1.5秒。但是使用MySQL客户机,所需时间不到0.001秒。
<Django代码/strong>
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 total, Query took 0.0025 seconds.
更新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
)是必要的吗?我该如何解决这个问题?
无论如何,我在这里引发了一个跟踪问题。
根本原因
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 ORM中不支持DISTINCT ON,您可以在客户端进行:
set(Model1.objects.order_by('date').values_list('date', flat=True))