在 MySQL 中存储视图/统计信息的最佳方式

Posted

技术标签:

【中文标题】在 MySQL 中存储视图/统计信息的最佳方式【英文标题】:Best way to store views / stats in MySQL 【发布时间】:2011-05-10 09:38:51 【问题描述】:

我没有在“视图”表中存储单个页面视图的网站:

CREATE TABLE `views` (
  `view_id` bigint(16) NOT NULL auto_increment,
  `user_id` int(10) NOT NULL,
  `user_ip` varchar(15) NOT NULL,
  `view_url` varchar(255) NOT NULL,
  `view_referrer` varchar(255) NOT NULL,
  `view_date` date NOT NULL,
  `view_created` int(10) NOT NULL,
  PRIMARY KEY  (`view_id`),
  KEY `view_url` (`view_url`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

这是非常基本的,存储 user_id(用户在网站上的 id)、他们的 IP 地址、url(没有域以稍微减小表的大小)、推荐 url(现在并没有真正使用它)可能会去掉它)、日期(当然是 YYYY-MM-DD 格式)和视图发生时的 unix 时间戳

当然,该表变得相当大(目前有 400 万行,而且它是一个相当年轻的网站)并且在其上运行查询很慢。

为了一些基本的优化,我现在创建了一个“views_archive”表:

CREATE TABLE `views_archive` (
  `archive_id` bigint(16) NOT NULL auto_increment,
  `view_url` varchar(255) NOT NULL,
  `view_count` smallint(5) NOT NULL,
  `view_date` date NOT NULL,
  PRIMARY KEY  (`archive_id`),
  KEY `view_url` (`view_url`),
  KEY `view_date` (`view_date`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

这将忽略用户信息(和推荐网址)并存储每天查看网址的次数。这可能是我们通常希望使用数据的方式(每天查看页面的次数),因此应该使查询非常快,但即使我主要使用它来替换“视图”表(对现在我想我可以按小时显示上周/月左右的页面浏览量,然后显示除此之外的每日浏览量,因此只需要“浏览量”表来包含上周/月的数据)但它仍然很大表。

总之,长话短说,我想知道您是否可以给我一些关于如何最好地处理 mysql 站点中的统计信息/页面视图存储的提示,目标是保持表的大小(s ) 在数据库中尽可能小,并且仍然能够轻松(并且至少相对快速)查询信息。我看过一些分区表,但该站点没有安装 MySQL 5.1。您可以提供的任何其他提示或想法将不胜感激。

【问题讨论】:

嗯,你的服务器不是有一个已经保存所有这些数据的访问日志吗?有很多用于 Web 访问日志的日志查看器/摘要器。是否有令人信服的理由不使用其中之一? view_created 列的用途是什么? view_created 列 MicWafflestix 的用途是如果我想每小时显示浏览量(比如今天每小时查看一篇文章的次数)。我想我可以使用 DATETIME 代替 INT(10) 时间戳,但我不确定这对我有多大帮助。 那么我可能还会将 view_date 和 view_created(那里的命名法有些混乱)合并到一个 DATETIME 列中。原生类型在 SQL 中总是一个好主意。 【参考方案1】:

假设您的应用程序是一个博客,并且您想要跟踪博客文章的浏览量,您可能会有一个名为 blog_posts 的表。在此表中,我建议您创建一个名为“views”的列,在此列中,您将存储该帖子有多少视图的静态值。您仍将使用 views 表,但这仅用于跟踪所有视图(并检查它们是否“唯一”)。

基本上,当用户访问博客帖子时,它会检查views 表以查看是否应该添加它。如果是这样,它还将增加blog_posts 中博客文章相应行中的“视图”字段。这样,您只需参考每个帖子的“视图”字段即可快速查看它有多少视图。您可以更进一步,通过设置 CRON 作业来重新计算和验证所有视图并在一天结束时相应地更新每个 blog_posts 行来添加冗余。或者,如果您愿意,您还可以在每次更新时重新计数,如果精确到秒是 key

如果您的网站是阅读密集型网站,并且您经常需要计算每篇博文的浏览量(再次假设这是您的应用程序 :-)),则此解决方案效果很好。

【讨论】:

【参考方案2】:

您可能希望有一个仅用于页面的表,并让用户视图引用该表。另一种可能的优化是将用户 IP 存储在不同的表中,可能是一些会话表信息。这应该会减少您的查询时间。您在存档表的正确轨道上;同样的优化也应该有所帮助。

【讨论】:

我喜欢这个主意。似乎是一些非常基本、可靠的数据结构优化(而不是升级 mysql 或使用 nosql 表或其他一些我担心我必须做出的重大改变)。我还刚刚在 MySQL 中发现了 INET_ATON() 函数,它可以帮助我减少存储 IP 地址的大小(可以使用 INT 而不是 VARCHAR)。无论如何,就短期而言,我认为您提到的解决方案将大大有助于解决我的问题。谢谢。 @Charlie:不客气。在大范围内,小的优化真的开始产生很大的不同。同时,一些真正复杂的优化并没有提供通常预期的回报。我发现首先进行简单、直接的优化通常能让我在 90% 的路上找到一个好的解决方案,如果不是全部的话。【参考方案3】:

MySQL 的存档存储引擎

http://dev.mysql.com/tech-resources/articles/storage-engine.html

它非常适合日志,写入速度很快,一个缺点是读取速度有点慢。但它非常适合日志表。

【讨论】:

前几天我看了一点。看起来很有趣,但在我当前的 MySQL 安装中它不被“支持”(通过 SHOW ENGINES; 查询检查)。我会要求托管人员打开它或其他任何东西并使用它。感谢您的提示。

以上是关于在 MySQL 中存储视图/统计信息的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章

每天存储数百万条可分组用于统计目的的数据的最佳方式是啥?

在活动网站中检索外部 torrent 统计信息的最佳方式

MySQL的统计信息学习总结

MYSQL 内存排查

生成mysql统计信息

MySQL索引统计信息更新相关的参数