加速嵌套的 Django ORM 查询

Speeding up nested Django ORM queries

我在我的 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 库,我需要找到我的应用程序中当前没有条目的用户数量 table(及其对应的 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

我的会话 table 包含 1.7M 行,而用户 table 包含 408K 行。上面的代码花费了异常大量的处理时间(即几分钟),并最终在生产中给我一个 500 错误(在开发中的有限数据集上正常工作)。

在解决问题之前,我觉得我还应该优化查询以获得结果的成本更低。

您认为我的代码需要哪些明显的优化?我知道我可以通过从 total_users 中减去 logged_in_users 的数量来找到 logged_out_users 的数量。但是如何获取他们所有的 ID?

[更新]:在评论中进行了一些讨论后,问题询问了有关检索(和计数)已注销 Userid 的问题]s(即根本没有 Session table 条目的用户)。

所以:

# 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()