获取数据库记录的已排序子集的最佳方法

时间:2018-04-17 21:58:21

标签: sql database amazon-dynamodb

方案

假设我正在构建Messenger应用程序的数据库。让两个表,一个User表和一个Conversation表。每个对话都有一个参与用户列表,每个用户都有一个他们所在的对话列表。简而言之,用户和对话表之间存在多对多关系。

现在假设我想在打开应用程序时按降序按时间顺序加载用户对话列表的前10个对话。假设表中的#Conversations>> #用户拥有的对话>> 10,一种强制方式是加载用户列表中的每个会话,然后在内存中对它们进行排序,最后返回前10个。我认为这是普通SQL引擎处理这种查询的方式。

我担心的是,当#Conversations用户变得非常大时,此操作变得太耗费资源。是否有更快的方法可以实现相同的结果(从表中获取已排序的记录子列表)以及可能的其他数据库设置?

示例

例如,假设用户有300个会话,我们希望按顺序翻阅这些会话。上述方法可以将所有300个会话下载到磁盘,然后在本地进行排序,或者让服务器进行排序。第一种方法使用太多带宽,信息可能不是最新的,第二种方法要求每次我们分页时从数据库中提取所有300个对话。

问题

我的问题是:我对这个特殊情况的关注是否有效?如果是这样,我应该如何修改我的数据库设置以避免此问题?一些现有的例子如Facebook Messenger如何处理这个?如果没有,为什么这不是性能问题?

修改

我在问到一个问题之后意识到在RDBMS中我们只需要创建第三个表来存储多对多关系,并在此表上构建索引就可以解决这个问题。但是,支持在列中存储列表的NoSQL数据库(更具体地说,AWS DynamoDB)在这种情况下是否优于传统的RDBMS?

2 个答案:

答案 0 :(得分:3)

看起来您提供的表格列表不足以代表您尝试提取的数据。假设对话中只能有一个创建者,那么该用户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的两个表上的复合索引)。实际上,这个查询很可能会被满足而无需引用表 - 结果可以完全从索引中计算出来。使用带有count和skip值的MySQL TOP修饰符可以让你非常有效地处理分页。

答案 1 :(得分:2)

  

有没有更快的方法来获得相同的结果(获取一个排序的   来自表的记录子列表),可能还有其他数据库   设置?

是的,有。

这个"额外的数据库设置"被称为"索引"。我认为每个关系DBMS都允许创建索引。

可以有多种类型的索引,但最常见的是b树索引,其中数据存储在平衡树中,这允许快速查找必要的元素并按照顺序读取数据。索引已排序。

索引是除了主表数据之外由磁盘上的数据库引擎存储和维护的补充结构。您通常可以在同一个表上创建许多不同的索引。在运行特定查询时,引擎会尝试选择最合适的索引。不同的查询可能使用不同的索引。

由于在基础数据发生变化时必须维护索引结构,这意味着通常创建索引有助于SELECT查询,但有点慢UPDATEDELETE和{{1} }}。这就是为什么它通常需要权衡,需要一些技巧来确定应该存在哪些索引集。这在很大程度上取决于运行的查询类型及其相对重要性。

有关如何在适当索引的帮助下实现高效分页的具体示例,请查看来自网站的Pagination Done the Right Way,即Use the index, Luke

它还有一个很好的介绍Anatomy of an SQL Index和许多其他有用的文章。

  

我对这个特殊情况的关注是否有效?

它对于300行无效,但随着表的大小增加,它变得越来越重要。对于3亿行,最有可能是相当重要的。