【问题标题】:Slow Python Django Mysql Update Query慢速 Python Django Mysql 更新查询
【发布时间】:2017-10-09 19:28:57
【问题描述】:

我有一个包含 user_id、update_time 等列的用户表,并且 一个动作表,它有列 user_id、action 和 create_time 表。

    class User(models.Model):
        user_id = models.CharField(db_index = True, max_length = 255, unique = True, null = False)
        update_time = models.DateTimeField(db_index = True, default = timezone.now, null = True, blank = True)

    class Action(models.Model):
        user_id = models.CharField(db_index = True, max_length = 255, null = False)
        action = models.CharField(db_index = True, max_length = 15, unique = False, null = False)
        create_time = models.DateTimeField(db_index = True, auto_now_add = True, null = True)

我想在 update_time 列中保存用户的上次活动时间。我每天都会收到很多用户的很多操作。所以我在插入操作时不更新用户表 update_time 列。我通过后台作业更新 update_time 列,该作业找到与 user_id 对应的所有操作的 create_time 的最大值,并在 user 表中更新他的 update_time 列。

后台作业为此目的在代码/查询下方运行。但是这段代码的性能并不是那么好。谁能帮我优化它,或者更好的 MySQL 查询,甚至是 Django ORM 查询的格式,或者任何不同的策略来做这件事?

    days_limit = datetime.now() - timedelta(1)
    query = "UPDATE user a JOIN (SELECT user_id, MAX(create_time) AS last_create_time FROM user_action WHERE create_time >= %s GROUP BY user_id) b ON a.user_id = b.user_id SET a.update_time = last_create_time WHERE a.update_time < last_create_time"
    cursor = connection.cursor()
    print cursor.execute(query, [str(days_limit)])

【问题讨论】:

  • 谢谢。但没有一个对我有用 1. user_id 不能是整数。它是 Android 应用程序 2 的设备 ID。不能使用外键,因为有时操作行是在用户 3 之前创建的。更新其主键引用的单行会很快,但每次更新它是多余的 4. user_id 上的多列索引并且 create_time 似乎是不错的解决方案,但操作表太大而无法在没有足够停机时间的情况下执行更改查询。当我们添加更多数据库时将尝试第 4 次
  • 如果您仔细查看我的回答,它是基于您在此处给出的问题。您未能创建一个最小的非常完整的示例。
  • 如果您不关心数据完整性,为什么还要使用 SQL?你为什么不使用像 mongo 这样的东西??

标签: mysql django python-2.7 django-models


【解决方案1】:

问题 #1

class User(models.Model):
    user_id = models.CharField(db_index = True, max_length = 255, 

如果这是一个数字 user_id 而不是用户名,则此列没有任何意义。它应该被删除。加速 mysql 查询的关键方法之一是减少数据的大小和磁盘上的索引。该列似乎是多余的,如果需要保留它应该是 int。

问题 #2

class Action(models.Model):
    user_id = models.CharField(db_index = True, max_length = 255, null = False)

如上所述,但您真正应该拥有的是

class Action(models.Model):
    user_id = models.ForeignKey(User)

因为没有外键,两个模型之间没有关系,这就是为什么你不得不使用原始查询而不是 ORM 查询

问题 #3

我每天都会收到很多用户的很多操作。所以我不更新 插入操作时的用户表 update_time 列

如果您有正确的表结构,那么每天进行多次更新就不会很慢。更新其主键引用的单行实际上会非常快。比您现在使用的复杂连接查询快得多。

如果您真的担心这样的更新需要几毫秒,您可以使用 celery 在后台运行它。

问题 #4

 UPDATE user a JOIN 
  (SELECT user_id, MAX(create_time) AS last_create_time FROM user_action WHERE create_time >= %s GROUP BY user_id) b 
 ON a.user_id = b.user_id SET a.update_time = last_create_time WHERE a.update_time < last_create_time"

为了加快速度,您需要在 user_id 和 create_time 上建立多列索引,但 user_id 列是多余的......

【讨论】:

  • 谢谢。但没有一个对我有用 1. user_id 不能是整数。它是 Android 应用程序 2 的设备 ID。不能使用外键,因为有时操作行是在用户 3 之前创建的。更新其主键引用的单行会很快,但每次更新它是多余的 4. user_id 上的多列索引create_time 似乎是不错的解决方案,但操作表太大而无法在没有足够停机时间的情况下执行更改查询。当我们添加更多数据库时将尝试第 4 次
猜你喜欢
  • 1970-01-01
  • 2016-01-10
  • 1970-01-01
  • 2021-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多