加速嵌套的 Django ORM 查询
Posted
技术标签:
【中文标题】加速嵌套的 Django ORM 查询【英文标题】:Speeding up nested Django ORM queries 【发布时间】:2017-03-21 16:37:12 【问题描述】:我在我的 Django 项目中使用方便的Django sessions library。这允许我通过 ORM 查询处理 Session 对象。
我可以为每个 Session 对象访问的属性是:
Column | Type | Modifiers
---------------+--------------------------+-----------
session_key | character varying(40) | not null
session_data | text | not null
expire_date | timestamp with time zone | not null
user_id | integer |
user_agent | character varying(200) | not null
last_activity | timestamp with time zone | not null
ip | inet | not null
user_id
来自 Django User
模型。
使用 Session 库,我需要在我的应用程序中找到当前在 Session 表中没有条目的用户数(以及他们对应的IDs
)。
我通过以下方式进行了尝试:
logged_in_users = set(Session.objects.values_list('user_id',flat=True))
logged_in_users = [user_pk for user_pk in logged_in_users if user_pk is not None]
logged_out_users = set(User.objects.exclude(id__in=logged_in_users).values_list('id',flat=True))
num_logged_out = len(logged_out_users) #passed to template to display
My Session 表包含 1.7M 行,而 User 表包含 408K 行。上面的代码需要异常大量的处理时间(即几分钟),最终在生产中给我一个 500 错误(在开发中的有限数据集上正常工作)。
在解决问题之前,我觉得我还应该优化查询以更便宜地获得结果。
您认为我的代码需要哪些明显的优化?我知道我可以通过从total_users
中减去logged_in_users
的数量来找到logged_out_users
的数量。但是获取他们所有的 ID 呢?
【问题讨论】:
user_id
是 ForeignKey
到 User
模型还是只是一个整数?
这是一个 FK。表定义包括Foreign-key constraints: "user_id_refs_id_898fa0fe" FOREIGN KEY (user_id) REFERENCES auth_user(id) DEFERRABLE INITIALLY DEFERRED
【参考方案1】:
[更新]:在 cmets 中进行了一些讨论后,该问题询问了有关检索(和计数)已注销 User
s 的 id
s(即不在Session
表中有一个条目)。
所以:
# Get a (flat) list of user ids where the user entry in not null
logged_in_users = Session.objects.filter(user__isnull=False).values_list('user__id', flat=True).distinct()
# Get a (flat) list of user ids excluding the previous logged ones (thus, this list will contain the logged out users)
logged_out_users = User.objects.exclude(id__in=logged_in_users).values_list('id', flat=True).distinct()
# Count the logged out users
logged_out_users_count = logged_out_users.count()
这个怎么样:
# Fetch all user_id values from the Session table where the user ForeignKey has
# no value (thus, it's null)
null_user_ids = Session.objects.filter(user__isnull=True).values_list('user__id', flat=True)
# Count the null users
no_of_users = null_user_ids.count()
【讨论】:
已更新。这是否为您澄清?您询问了当前在会话表中没有条目的用户。这意味着user
条目是null
。
那不是为 fk user
为 None
的行过滤会话表吗?未经授权的用户使用user_id = None
在会话表中创建条目
是的。嗯,不完全是None
,但数据库说它是null
。
因此User
表中可能有用户在Session
表中根本没有条目(例如,他们已注销)。那些会被这个捕获吗?
由于他们在Session
表中没有条目,并且上面的查询“扫描”了Session
表,因此这些用户不会出现在结果中。以上是关于加速嵌套的 Django ORM 查询的主要内容,如果未能解决你的问题,请参考以下文章
python 之 Django框架(orm单表查询orm多表查询聚合查询分组查询F查询 Q查询事务Django ORM执行原生SQL)