2010-06-05 43 views
6

这是为即将到来的项目。我有两个表 - 第一个保存的照片轨道,而第二个跟踪照片的排名如何优化这个MySQL表?

Photos: 
+-------+-----------+------------------+ 
| id | photo  | current_rank  | 
+-------+-----------+------------------+ 
| 1  | apple  | 5    | 
| 2  | orange | 9    | 
+-------+-----------+------------------+ 

照片等级不断定期更改的,这是跟踪它的表:

Ranks: 
+-------+-----------+----------+-------------+ 
| id | photo_id | ranks | timestamp | 
+-------+-----------+----------+-------------+ 
| 1  | 1   | 8  | *   | 
| 2  | 2   | 2  | *   | 
| 3  | 1   | 3  | *   | 
| 4  | 1   | 7  | *   | 
| 5  | 1   | 5  | *   | 
| 6  | 2   | 9  | *   | 
+-------+-----------+----------+-------------+ * = current timestamp 

为了报告/分析目的,每个等级都被跟踪。 [编辑]用户将有权访问需求统计。

我跟一个在这个领域有经验的人交谈过,他告诉我要存储像上面这样的行列是要走的路。但我还不确定。

这里的问题是数据冗余。将会有数万张照片。照片排名以小时为单位进行更改(很多时间 - 在几分钟内)用于最近的照片,但较少用于较老的照片。以这样的速度,该表格将在数月内拥有数百万条记录。由于我没有处理大型数据库的经验,这让我有点紧张。

我想到了这一点:

Ranks: 
+-------+-----------+--------------------+ 
| id | photo_id | ranks    | 
+-------+-----------+--------------------+ 
| 1  | 1   | 8:*,3:*,7:*,5:* | 
| 2  | 2   | 2:*,9:*   | 
+-------+-----------+--------------------+ * = current timestamp 

这意味着在PHP一些额外的代码分裂列/时间(和排序),但是这看起来挺合我意。

这是一个正确的方法来优化表的性能?你会推荐什么?

+0

是排名连接到其他任何东西?像谁给它的用户?如果有的话,这种关系有多重要?即?你需要存储用户游戏的排名吗? – 2010-06-05 13:19:49

+0

排名与其他任何内容都没有关联,只是照片。这是计算机算法计算和更改! :) – Yeti 2010-06-05 13:27:39

+1

@Col:你的评论总是让我微笑! :)其实ID看起来更像这样:** 4606886418 **,现在有大约200万张照片。每个人的等级变化50+次。所以,尽管这可能不太大,但也不能称之为小。 – Yeti 2010-06-05 14:10:20

回答

7

第一个。期。

其实你会失去更多。存储在int列中的时间戳只占用4个字节的空间。

虽然存储在字符串格式中的相同时间戳将占用10个字节。

+0

我忘了提及时间戳不是unix时间戳,它是日期时间。那是一样的吗? – Yeti 2010-06-05 14:41:55

+0

@为你的功课放弃:http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html – 2010-06-05 16:33:04

2

我会坚持你的第一个方法。在第二行中,你会在行中存储大量数据,随着时间的推移,它会得到更多的排名!也就是说,如果一张照片获得成千上万的排名。

第一种方法也更易于维护,也就是说,如果您想删除排名。

+1

实际上排名表中的数据从不更新,因为它用于显示统计信息。 – Yeti 2010-06-05 13:30:45

+0

谢谢彼得(德彼得) – Phliplip 2011-05-14 23:14:32

1

我认为数据库过度正常化(一遍又一遍地查询等级表)很好地避免了'缓存'current_rank中的最后一个等级。如果它很少被查询(你说过的分析/报告),从未更新过,但最后只是插入记录:即使是非常轻的盒子在该表中有数百万行也没有问题,所以排名无所谓。

您可能需要在磁盘上的不同位置进行大量更新,可能会导致性能下降。

当然,如果您需要所有旧数据,并且始终使用photo_id,则可以计划安排到另一个表rankings_old的计划运行,可能包含photo_id,年,月,一个月结束时的排名(包括时间戳)所以很容易检索旧数据,但是在rankings_old或rankings中不需要更新,只能在表的末尾插入。

并从我身上:在纯粹的日志记录表中百万记录应该是绝对没有问题的。

+0

我的坏,没有提到日志是可用的照片所有者(他们可以查看等级统计)。所以,可能会有很多疑问。 – Yeti 2010-06-05 14:44:04

+0

然后它不太明确,但我仍然认为第一个解决方案会更好(更新性能是关键,更新不应该锁定选择)。我可能会每天排名靠前,而不是一个月。 – Wrikken 2010-06-05 15:07:09

2

您的第一个设计对于关系数据库是正确的。关键字列中的冗余是可取的,因为它使您在验证和查询排名时有更大的灵活性。您可以在SQL中进行排序,计数,平均值等,而不需要编写任何PHP代码来从星期天的六种方式分割字符串。

这听起来像你想使用非SQL数据库,如CouchDB或MongoDB。这些允许您在照片的记录中存储半结构化的排名列表,并随后高效地查询排名。需要注意的是,您并不知道排名格式正确,就像您使用SQL一样。

0

您声明排名仅与图片链接,在这种情况下,您所需要的只是表格1并且实时更新排名。表2仅存储不必要的数据。这种方法的缺点是用户不能改变他的投票。

1

标准化数据或非标准化数据。你会发现数以千计的文章。 :)

这真的取决于您的需求。

如果你只想建立你的数据库只考虑性能(速度或内存消耗或......),你应该只信任这些数字。要做到这一点,你必须用期望的数据“音量”来分析你的查询(你可以用你写的一些脚本来生成数据)。要分析你的查询,学习如何阅读2个以下查询的结果:

  • EXPLAIN extended...
  • SHOW STATUS

然后学习如何做才能提高数字(MySQL的设置,数据结构,硬件等)。

担任首发,我真心奉劝这2篇大文章:

  1. http://www.xaprb.com/blog/2006/10/12/how-to-profile-a-query-in-mysql/
  2. http://ajohnstone.com/archives/mysql-php-performance-optimization-tips/

如果你想建立正常化的学术美:只要按照书和一般建议。 :)

0

你说第二个表是用于分析/统计,所以它实际上不是需要存储在数据库中的东西。我的建议是摆脱第二张表,并使用日志记录工具记录等级变化。

+0

我忘了提及用户可以访问第二个表中的数据。编辑了这个问题。 – Yeti 2010-06-05 21:47:13

1

出了两种选择 - 就像每个人在我面前说 - 它必须选择1

你真正应该关心什么是应用程序本身的瓶颈。用户是经常参考历史数据,还是只显示少数选择用户?如果答案是每个人都能看到队伍的历史数据,那么选项1就足够了。如果您不打算经常参考历史等级,那么您可以创建第三个“存档”表,在更新等级之前,可以将原始等级表的行复制到存档表。这可以确保正在调用的主表上的行数保持最小。请记住,如果你正在更新行,并且有成千上万的数据,那么在你的代码(PHP/Python/etc)中获得结果可能会更有成效,截断表并插入结果,而不是逐行更新它,因为这将是一个潜在的瓶颈。

您可能要查找分片以及(水平分割) - http://en.wikipedia.org/wiki/Shard_%28database_architecture%29

永远不要忘记指数好。

希望有帮助。

0

您的第二个设计是非常危险的情况下,您有100万张照片的投票。 PHP可以处理吗?

随着第一个设计,你可以做数据库级别的所有数学,这将返回给你一个小的result set