数据库表获取太多数据 - 需要另一种解决方案

时间:2010-10-03 13:12:20

标签: mysql ruby-on-rails ruby database-design

我有一个网站,人们可以添加自己喜欢的电视剧。有一个功能可以检查你看过的剧集。

每个已检查的剧集在数据库表格中创建一条记录(使用user_id,show_id和episode_id)。
这个表现在超过600.000行并且增长非常快!

我已设置索引,但我觉得查询此表时的性能越来越差。

我对新解决方案的想法:

所以而不是:

user_id | show_id | episode_id  
1 ....... 123 ......7675  
1 ....... 123 ......7676   
1 ....... 123 ......7677  
1 ....... 456 ......5678  
1 ....... 456 ......5679  
1 ....... 456 ......5680  

我可以这样做:

user_id | show_id | episode_ids  
1 ....... 123 ......7675,7676,7677  
1 ....... 456 ......5678,5679,5680

然后我必须将字符串拆分成一个数组,然后使用 array.include?(some-id)
这应该可以减轻数据库的负担,但Ruby可以处理更多更重的数组代码。

我是否在正确的轨道上?或者有人能想到更好的解决方案吗?

4 个答案:

答案 0 :(得分:13)

否否,这绝对不是构建这样一个数据库的方法。 varchar字段中以逗号分隔的列表是您应该考虑的最不理想的反模式。

这听起来像你的性能问题是基于猜测。所以相反:

  • 确定是否出现问题
  • 使用适当的仪器查找原因
  • 在非生产环境中测试可能的解决方案。

600k行没有(在一个有三个整数的表中)。真。即使是最小的服务器,这也可以适用于ram。从ram中查询表应该是如此之快,你不必担心它。

如果您越过第1步(确实存在问题),请进一步询问包含整个相关模式,确切查询,解释计划和时间数据的问题。

答案 1 :(得分:2)

您是否对数据进行非规范化是一个有争议的问题。它可以在特定情况下有其优点,但从关系的角度来看,它可能不应该是你的首选。相反,解决此问题的首选步骤应该是分析它并实现不改变数据结构但主要处理数据库系统及其环境的解决方案。因此:

  • 问题的根源是否真的是数据库?或者它是其他系统(网络,网络服务器,铁路等)?
  • 查询响应时间方面可以接受什么?查找数据库在任何情况下都应遵守的具体数字。
  • 哪些查询变慢?也许你有慢速,低效的查询,可以重构。制定查询计划,查看优化程序正在执行的操作。
  • 您是否以正确的方式使用索引?
  • 调整你的mysql实例。你可以通过调整实现很多目标。
  • 看到你可以在硬件方面做些什么(获得更多内存,更快的磁盘等)
  • 如果有任何
  • ,则为最常用的查询创建视图
  • 如果完成上述所有操作,您仍然可以进行分片。这会在您的应用程序之上增加一些复杂性,但它可以让您在不需要太多努力的情况下扩展系统。
  • 最终您可能会得出结论,您必须使用“真正可扩展的”分布式键/值存储(nosql)。但是在达到600k行之前,还有很长的路要走,直到达到这一点。

话虽如此 - 如果您发现您提出的解决方案是提高性能的最佳方法,请继续进行反规范化。关键是你应该了解所有选项并选择具有与性能相关的具体目标的最佳选项。

答案 2 :(得分:1)

以下是我如何构建表格:

USERS
userid INTEGER PRIMARY KEY 
username text/varchar/whatever

SHOWS
showid INTEGER PK
showname   varchar or nvarchar or text  [depending on what database I was using]
etc etc


EPISODES
episodeid INTEGER PK
showid    INTEGER  FK references SHOWS   [index this field]
ordinal   DECIMAL   [indicates which episode  -- DECIMAL makes it easier to insert later an episode you overlooked] 
episodename text/varchar/nvarchar whatever   
etc etc

SEENIT
id  INTEGER AUTOINCREMENT  PK
userid  INTEGER    foreign key ref USERS
episodeid  INTEGER foreign key ref EPISODES

您可以在(userid,episodeid)上放置备用唯一复合索引,或者使用单独的索引,一个在userid上,一个在episodeid上。我可能会选择后者。

答案 3 :(得分:0)

我会坚持使用标准化数据。这听起来更像是一个查询优化问题。请记住,mysql(假设您正在使用它)每个查询只使用一个索引,并且您可以通过设置复合索引获得更好的性能。 还可以在mysql查询浏览器中使用EXPLAIN语句。更多信息: http://dev.mysql.com/doc/refman/5.1/en/explain.html