mysql - 使用 Django queryset 查询日期对象存在性能问题

标签 mysql django performance orm

我正在使用 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 客户端中手动运行查询,它也会变得很慢。我注意到第二个查询进行了类型转换。

是否需要进行类型转换(datedatetime)?我该如何解决这个问题?

无论如何,我已经解雇了 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,然后使用其日期部分。性能影响与记录数量成比例。

解决方案

  1. 正如@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/

    相关文章:

    php - 用于库存管理的 MySQL 选择查询

    php - 使用 PHP PDO 将同一 mysql 列中的值打印到多个列中

    javascript - 在 django 模板中渲染之前去除 javascript 代码

    python - 创建对象后将 Id 从 CreateView 传递到另一个函数

    sql - 当 CASE 语句在 PostgreSQL 中有一个子句时,查询变慢

    c# - 处理 15000 个工作项的最佳方式,每个工作项需要 1-2 次 I/O 调用

    python - 原始 SQL 到 sqlalchemy 语法

    PHP/MySQL/JSON 编码帮助

    Django CMS - 如何检测主页?

    performance - activemq性能陷阱和注意事项