【问题标题】:How to optimize this MySQL table?如何优化这个 MySQL 表?
【发布时间】:2011-02-28 03:47:05
【问题描述】:

这是为即将到来的项目准备的。我有两张表 - 第一张记录照片,第二张记录照片的排名

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 中有一些额外的代码来分割排名/时间(和排序),但这对我来说看起来不错。

这是优化表以提高性能的正确方法吗?你会推荐什么?

【问题讨论】:

  • 排名是否与其他任何东西有关?喜欢给它的用户吗?如果是这样,这种关系有多重要? IE?你需要存储用户游戏的排名吗?
  • 排名与照片无关。它是由计算机算法计算和更改的! :)
  • @Col:你的cmets总是让我微笑! :) 实际上,id 看起来更像这样:4606886418,现在大约有 200 万张照片。每个人的等级变化50+次。所以,虽然可能不算太大,但也不能说是小。
  • 你只是不知道最基本的计算机技能:价值和它的表现之间的区别。 int 类型字段总是占用 4 字节,无论它持有什么值,1,10 或 4606886418。而你仍然有这些愚蠢的 :, 的,它们也会发生.和时间戳!傻逼,一开始没注意。时间戳,不是取相同的 4 字节,而是取全长 10 字节的字符串
  • @lost_in_code,不用担心 col 的 cmets。他/她喜欢虐待初学者。祝你好运;)

标签: php mysql database optimization


【解决方案1】:

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

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

【讨论】:

  • 其实rank表中的数据是永远不会更新的,因为它是用来显示统计的。
【解决方案2】:

我认为通过“缓存”current_rank 中的最后一个排名可以很好地避免数据库“命中”过度规范化(一遍又一遍地查询排名表)。如果很少查询(您所说的分析/报告),永远不会更新但只是在最后插入记录,那么排名是否会大幅增长并不重要:即使是一个非常轻的盒子,在该表中拥有数百万行也没有问题。

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

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

告诉我:一个纯日志表中的数百万条记录绝对没有问题。

【讨论】:

  • 我的错,没有提到照片所有者的所有者可以使用日志(他们可以查看排名统计信息)。所以,可能会有很多查询。
  • 那么它就不那么明确了,但我仍然认为第一个解决方案会更好(更新性能是关键,更新不应该锁定选择)。我可能会使用每日排名_旧而不是一个月。
【解决方案3】:

第一个。期间。

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

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

【讨论】:

【解决方案4】:

您的第一个设计对于关系数据库是正确的。键列中的冗余是可取的,因为它为您在验证和查询排名的方式上提供了更多的灵活性。您可以在 SQL 中进行排序、计数、平均等操作,而无需编写任何 PHP 代码来从周日开始以六种方式拆分字符串。

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

【讨论】:

    【解决方案5】:

    您说排名仅与图像相关联,在这种情况下,您只需要表 1 并实时更新排名。表 2 只存储了不必要的数据。这种方法的缺点是用户不能改变他的投票。

    【讨论】:

      【解决方案6】:

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

      这真的取决于你的需要。

      如果您想构建数据库时只考虑性能(速度或 RAM 消耗或...),您应该只相信数字。为此,您必须使用预期的数据“量”来分析您的查询(您可以使用您编写的一些脚本生成数据)。要分析您的查询,请了解如何读取以下 2 个查询的结果:

      • EXPLAIN extended...
      • SHOW STATUS

      然后学习如何改进数字(mysql设置、数据结构、硬件等)。

      作为初学者,我真的推荐以下两篇很棒的文章:

      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/

      如果您想构建标准化的学术美感:只需遵循书籍和一般建议即可。 :)

      【讨论】:

        【解决方案7】:

        你说第二张表是用来分析/statistics的,所以它实际上不是需要存储在db中的东西。我的建议是去掉第二个表并使用日志工具来记录排名变化。

        【讨论】:

        • 我忘了提到用户可以访问第二个表中的数据。已编辑问题。
        【解决方案8】:

        在这两个选项中——就像我之前的每个人所说的那样——它必须是选项 1。

        您真正应该关心的是应用程序本身的瓶颈。用户是否会经常参考历史数据,还是只为少数选定用户显示?如果答案是每个人都可以看到排名的历史数据,那么选项 1 就足够了。如果您不打算经常参考历史排名,那么您可以创建第三个“存档”表,在更新排名之前,您可以将原始排名表的行复制到存档表。这可确保被调用的主表上的行数保持最少。

        请记住,如果您正在更新行,并且有成千上万的行,那么在您的代码(PHP/Python/等)中获取结果、截断表并将结果插入而不是更新可能会更有成效它逐行进行,因为这将是一个潜在的瓶颈。

        您可能还想查找分片(水平分区)-http://en.wikipedia.org/wiki/Shard_%28database_architecture%29

        永远不要忘记做好索引。

        希望有所帮助。

        【讨论】:

          【解决方案9】:

          如果您的照片有 100 万张选票,您的第二个设计非常危险。 PHP 可以处理吗?

          使用第一个设计,您可以在数据库级别进行所有数学运算,这将返回一个小的 result set

          【讨论】:

            猜你喜欢
            • 2010-11-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-12-17
            • 1970-01-01
            • 2012-09-28
            相关资源
            最近更新 更多