【问题标题】:Best structure for MySQL table to hold statistical dataMySQL 表保存统计数据的最佳结构
【发布时间】:2017-01-08 02:52:37
【问题描述】:

我需要一种解决方案,让我能够跟踪 Web 应用程序 (PHP5 / MySQL5.7) 中的每一次点击(以及点击的链接和日期)。最简单的解决方案显然是一个简单的表格:

CREATE TABLE stats_data (
    id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    log_date DATETIME NOT NULL DEFAULT NOW(),
    link VARCHAR(512) NOT NULL
)

我不知道这会如何提高性能,因为预计每天的点击量很可能超过 10000。

  1. 这是一个可靠的解决方案吗?比如说,在存储 5 个月的数据之后?
  2. 哪些优化可以让这个解决方案表现得更好?
  3. 如果不是,有什么更好的解决方法?

【问题讨论】:

  • 将link VARCHAR(512) 更改为link_id INT 是一项明显的优化。
  • 这真的取决于您将使用的查询。请描述它们,或向我们展示暂定的SELECT 声明。 (5 个月后的 150 万条记录并不多。)
  • 问题已解决,如下面接受的答案所示。谢谢。

标签: mysql performance web-applications statistics scalability


【解决方案1】:

这主要取决于您的用例。你想在这个数据集上运行什么查询?

我肯定会推荐一些面向文档的数据库(如 Redis 或 MongoDb),但正如我所说,这取决于您将如何使用您的数据。

如果您想坚持使用 MySQL,我有一些关于如何使该解决方案更可靠的建议。

  1. 每次点击时不要将每次点击都保存到数据库中,而是将其存储到缓存中(例如 memcached)并每小时保存一次到 MySQL 中
  2. 为每个月制作自己的表,以免在一个大表中进行搜索。并每月备份该表。

【讨论】:

  • 用例是从其中提取统计数据。在我的 Web 应用程序中,我希望让用户查看(例如)特定月份、日期或自定义期间的点击次数。查询(插入除外)大部分时间都是在特定日期范围内获取行。 1. 调查一下,谢谢。 2. 我喜欢这个主意,再次感谢。
  • 如何将数据保存到一些原始表中并使用一些日常程序 (cron) 将有价值的数据聚合到一些轻量级表中(比如一个表用于每天的点击次数,另一个用于唯一的数量访问者。那么您将不会受到原始表大小的负担,因为您只会保存点击次数,然后在午夜聚合,在最好的情况下,删除聚合行。您可以将它们保存到其他数据库(例如)进行备份它们供以后使用(如果出现一些新的用例)。
  • 也许另一个重要因素是您想在解决方案上投入多少时间 :) 因为抽象和聚合优化可以是无限的 :D
  • 是的,我已经考虑过让某种 cron 工作来做到这一点,但问题如下。通过聚合,我猜您的意思是将点击次数(例如每天)相加,然后将其放入新表中。这个想法是我们也想跟踪点击的链接,这可能是每个条目的唯一链接。这要么意味着我们摆脱链接并只存储点击次数,要么我们最终只是将表格复制到另一个表格中。如果我错了,请纠正我。
  • 关于聚合,它总是取决于用例。没有最好的解决方案,只是将查询计算分散到时间中。我经常在大型项目中使用它的策略——一张表用于存储原始数据和完整数据,还有一些夜间例行程序填充另一张表以供阅读。我从不想丢弃收集到的数据,因为您经常会在将来某个时候需要它。但是在这么大的表中搜索是没有意义的。因此,我进行了一系列转换,在我最复杂的经验中,最终将一张大表破坏为大约 20 个更轻的表 - 商业智能
【解决方案2】:

我想您可以将链接放在单独的表中,并将您的表引用作为外键。应该可以更快地检查特定链接的点击次数。

根据您希望数据的准确性,您还可以将其聚合到另一个表中,可能是某种夜间运行的操作(预定的 sp 应该可以工作)。 这样,您可以拥有一个表格,例如,您可以在其中查看链接在特定时间间隔内被点击的次数,一天或一小时或任何适合您需要的时间。我在工作中使用了这种方法,我们在负载非常重的应用程序中存储有关 Web 服务调用的统计数据,并且它一直运行良好,没有任何性能问题。

【讨论】:

    【解决方案3】:

    您可以采取一些措施来确保性能:

    通过按日期列对数据进行分区,您可以按小时/天/周/月/年“分离”数据......任何你想要的......

    例子:

    CREATE TABLE members (
    firstname VARCHAR(25) NOT NULL,
    lastname VARCHAR(25) NOT NULL,
    username VARCHAR(16) NOT NULL,
    email VARCHAR(35),
    joined DATE NOT NULL
    )
    PARTITION BY RANGE( YEAR(joined) ) (
      PARTITION p0 VALUES LESS THAN (1960),
      PARTITION p1 VALUES LESS THAN (1970),
      PARTITION p2 VALUES LESS THAN (1980),
      PARTITION p3 VALUES LESS THAN (1990),
      PARTITION p4 VALUES LESS THAN MAXVALUE
    )
    

    因此,假设您按周分隔数据,当您搜索日期等于“2016-08-25”的日志时,该记录将仅搜索日期介于“2016-08-22”和'2016-08-28'.

    希望对你有帮助。

    【讨论】:

    • 谢谢!这可能是我正在寻找的。上面的答案建议按月创建表格。很容易做到这一点。但是分区看起来更优雅,假设它实现了相同的目标?换句话说,我认为“分区”是否能够容纳几百万行(即一个月的 f 数据)?谢谢你的索引提示,顺便说一句。我还将链接移动到另一个表,并将 link_id 列设置为该表的外键。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多