场景
假设我正在为 Messenger 应用构建数据库。假设有两个表,一个 User 表和一个 Conversation 表。每个 session 都有一个参与用户的列表,每个用户都有一个他们所在的 session 列表。简而言之,Users 和 Conversations 表之间存在多对多关系。
现在假设我想在打开应用程序时按时间降序加载用户对话列表的前 10 个对话。假设 # Conversations in table >> # Conversations a user has >> 10,一种蛮力方法是加载用户列表中的每个对话,然后在内存中对它们进行排序,最后返回前 10 个。我认为这就是方法一个普通的 SQL 引擎将处理这样的查询。
关注
我担心的是,当 #Conversations 用户变得非常大时,此操作会变得过于消耗资源。是否有任何更快的方法可以通过可能的额外数据库设置来实现相同的结果(从表中获取已排序的记录子列表)?
示例
例如,假设一个用户有 300 个对话,我们希望按顺序翻阅这些对话。上述方法要么将所有 300 个对话下载到磁盘然后在本地进行排序,要么让服务器进行排序。第一种方法使用太多带宽,信息可能不是最新的,第二种方法需要每次我们页面时从数据库中提取所有 300 个 session 。
问题
我的问题是:我对这个特殊案例的担忧是否有效?如果是这样,我应该如何修改我的数据库设置以避免这个问题? Facebook Messenger 等现有示例如何处理此问题?如果不是,为什么这不是性能问题?
编辑
问完问题后我意识到,在 RDBMS 中,我们只需创建第三个表来存储多对多关系,并在该表上构建索引就可以解决这个问题。但是,在这种情况下,支持按列存储列表的 NoSQL 数据库(更具体地说,AWS DynamoDB)是否比传统 RDBMS 有优势?
最佳答案
您提供的表格列表似乎不足以表示您尝试提取的数据。假设对话的创建者 不超过一个,那么用户 ID 可以安全地存储在那里。
但是表的可能结构将包括一个“评论”表,其中(至少)具有以下字段:
* Primary key -- record id for _this_ comment
* conversation_id -- reference to the conversation this comment is part of
* user_id -- The user ID of the person making this comment
* parent_id -- The comment that preceded this one (presuming threaded conversations)
* create_dt -- Datetime that the comment was added to the thread
* comment_body -- The actual comment itself.
如果情况确实如此,您将看到如下所示的查询:
SELECT DISTINCT conversation_id FROM
(
SELECT conversation_id, create_dt
FROM Conversation
WHERE person_id = {DesiredPerson}
UNION
SELECT conversation_id, create_dt
FROM Comment
WHERE person_id = {DesiredPerson}
} ORDER BY create_dt DESC
LIMIT 10
...将给出 DesiredPerson 参与的最近 10 个对话的 ID。
与您的看法相反,数据库优化器足够聪明,查询最终不会要求对两个查询进行完全评估以产生所需的结果。如果表上有适当的索引,这应该是一个非常有效的查询(例如,conversation_id + create_dt 的两个表上的复合索引)。事实上,完全不必引用表就可以满足此查询——结果可以完全根据索引计算得出。将 MySQL TOP 修饰符与计数值和跳过值一起使用应该可以让您非常有效地处理分页。
关于sql - 获取已排序的数据库记录子集的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49888114/