【问题标题】:MySQL table organization and optimization (Rails)MySQL 表组织和优化 (Rails)
【发布时间】:2011-07-12 06:39:04
【问题描述】:

过去几个月我一直在学习 Ruby on Rails,之前没有任何编程经验。最近,我一直在考虑数据库优化和表组织。我知道有很多关于这个主题的好书,但我通常会通过示例/边做边学。

这是一个假设的情况:

假设我正在为一个拥有 250,000 名成员(用户)的小众社区构建社交网络。用户可以参加活动。假设有 50,000 个过去/现在/未来事件。与 Facebook 活动非常相似,用户可以参加任意数量的活动,并且一个活动可以有任意数量的参与者。

在数据库中,会有一个用户表和一个事件表。不知何故,我必须在用户和事件之间创建关联。我可以在用户表中创建一个“事件”列,这样每个用户行都将包含一个事件 ID 的散列,或者我可以在事件表中创建一个“参加者”列,这样每个事件行都将包含一个用户 ID 的散列.

然而,这些解决方案似乎都不理想。在用户的个人资料页面上,我想显示与他们关联的事件列表,如果我在事件表中包含“参加者”列,则需要扫描 50,000 个事件行以获取所述用户的用户 ID。同样,在活动页面上,我想显示活动的参与者列表,如果我在 users 表中包含“events”列,则需要扫描 250,000 个用户行以获取所述活动的活动 ID。

选项 3 是创建第三个表,其中包含每个活动的参与者信息 - 但我不知道这将如何解决任何问题。

这些不是问题吗? Rails 使访问所有这些信息变得容易,但我想我担心规模。我完全有可能低估了现代数据库/服务器等的速度和处理能力。扫描 250,000 个用户行以查找特定事件 ID 需要多长时间 - 10 毫秒? 100 毫秒? 1000 毫秒?我想这还不错。我是不是想多了?

【问题讨论】:

  • 通过适当的索引,一个查询可以在一秒钟内处理 5000 万条记录。

标签: mysql ruby-on-rails optimization


【解决方案1】:

这是用户和事件之间典型的多对多关系。

您需要第三个表(比如 UserEvent 或更好的 UserAttendsEvent 或只是参加),该表将为每个用户和用户参加的每个事件都有一行。

所以它至少有一个 userID 和一个 eventID,它们都是 User 和 Event 表的外键。

在这两个字段上添加索引可能对您的查询有好处,因为您计划拥有数百万行。

UserEvent 还可能包含其他数据,例如用户注册活动的时间、她在活动上花费的金额、她是否喜欢活动等等。

关键是每一行都有关于“参加”的信息。谁参加了(userID),参加了什么(eventID),他到达的时间,花费的金额等。您不想将这些信息放在用户表和事件表中。

由于您担心性能,我将添加一个数据库如何搜索特定查询的示例。假设我们想要找到所有参加(或计划参加)活动“U2 音乐会在雅典,2011 年 7 月”并且与我生日相同的所有用户。

database plan:
1. use eventTitle index in table Event 
     to find that the event has id 47519 
   (good for us that we have created such an index).
2. use eventID index in table Attends 
     to find all (469) userids that have attended eventid 47519.
3. use the userid index in table User
     to find all the info of the 469 users.
4. search the info (birthdate) from those
     to keep only those (3) that have birthday July 24th.
     (we have not created any index that can be used here)

所以,数据库访问磁盘只是为了搜索索引和读取我们需要的数据。不要读取所有数据并在其中搜索。

在更复杂的查询中,或者因为查询需要表中的所有数据,或者如果尚未创建所需的索引或某些索引没有用,或者如果 db 查询优化器认为它更快,它可能会扫描表或部分然后搜索数据。但如果已定义“正确”索引(适合您的计划使用),查询将很快。

【讨论】:

  • 澄清一下 - 单行将包含一个用户 ID 和一个事件 ID?那么如果 3 个用户每人参加 5 个活动,那么 UserEvent 表中将有 15 行?
  • 没错。这是一种很常见的做法。
【解决方案2】:

“在用户个人资料页面上,我想显示与他们关联的事件列表,如果我在事件表中包含“参加者”列,则需要扫描 50,000 个事件行以获取所述用户的用户 ID 。”

如果每个用户 ID 不是唯一键,它必须扫描 50,000 个事件行,我当然希望它是唯一键。如果每个用户 ID 都是唯一键,那么它很快。事件表也是如此:每个事件都有一个唯一的 ID,这也是它的唯一键。

您必须使这些 ID 成为唯一的键,否则您将陷入困境。

-- 皮特

【讨论】:

  • 是的,每个用户都有一个唯一的 ID,每个事件都有一个唯一的 ID。 Rails 按照惯例这样做 - 对吧?我以为这部分是假设的,我只是不知道这种数据库查询需要多长时间。
【解决方案3】:

老问题,但在我寻找其他东西时添加了细节。

在 Rails 中,这是通过模型中的“has_and_belongs_to_many”子句处理的,它为您创建多对多解析表。此处的文档:http://guides.rubyonrails.org/association_basics.html

使用解析实体,数据库实际上不会扫描整个表来查找信息,它使用 b-tree 索引来查找所需的特定行 - 因此多对多确实可以直接修复您提出的性能问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 1970-01-01
    • 2011-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多