2

好吧,所以我喜欢用 PHP 和 MySQL 制作论坛软件,尽管有一件事一直困扰着我,而且只有一件事;

论坛主页,您可以在其中查看论坛列表。每个论坛都会显示论坛名称、在该论坛中发表的帖子数量、在该论坛中发表的讨论数量以及该论坛中的最后一张海报。问题在于,当所有这些东西都存储在不同的表中时,获取所有这些数据。得到它不是什么大问题,根本不是真正的问题,但有效地做到这一点是我所追求的。

我目前的做法是这样的;将当前的帖子、讨论和最后一张海报的数量静态存储在论坛表本身中,而不是从不同的表中抓取数据——“帖子”、“讨论”、“论坛”等。然后当用户帖子,它会更新“论坛”表,将帖子数量增加 1 并更新最后一张海报,如果他们正在进行新的讨论,也会将讨论增加 1。出于某种原因,这对我来说似乎效率低下和肮脏,但也许只是我。

这是另一种我担心效率极低的方法;实际上去每个表 - “帖子”,“讨论”,“论坛” - 并获取数据。问题是,一页上可能有数百个论坛......而且我必须使用 COUNT 语句来获取帖子或讨论的数量,这意味着我必须使用子查询 - 更不用说第三个子查询来获取最后一张海报。话虽这么说...查询将类似于以下伪代码:

SELECT foruminfo, (
    SELECT COUNT(id)
    FROM posts
    WHERE forumId = someid
), (
    SELECT COUNT(id)
    FROM discussions
    WHERE forumId = someid
), (
    SELECT postinfo
    FROM posts
    WHERE forumId = someid
    ORDER BY postdate
    DESC LIMIT 1
)
FROM forums
ORDER BY position DESC;

因此,如果我列出了数百个论坛,那么基本上这些子查询可以运行数百次。每秒有数百名用户查看该页面,这不会造成相当大的压力吗?我不完全确定子查询是否会导致与普通查询相同的负载量,但如果确实如此,那么它似乎肯定会非常低效。

有任何想法吗?:(

4

1 回答 1

2

我之前已经建立了一个大型论坛系统,使其高性能的关键是尽可能地去规范化任何东西。

您无法JOIN在真正流行的页面上实际使用。您必须将发出的查询数量保持在最低限度。你永远不应该使用子选择。始终确保您的索引涵盖了您的确切用例,仅此而已。运行时间超过 1-5 毫秒的查询可能太慢,无法在大规模运行的站点上运行。当由于负载严重时,运行一个 15 毫秒的查询突然需要十倍的时间来运行一个 150 毫秒或更长的时间,而优化的 1 毫秒查询将需要一个可接受的 10 毫秒。你的目标是让他们一直都是 0.00,这是可能的。

请记住,每当您执行查询并等待响应时,您都无法执行任何其他操作。如果你有点粗心,你的请求会比你处理它们的速度更快,整个系统都会崩溃。

保持你的模式简单,甚至愚蠢的简单,我的意思是考虑你的页面布局,你显示的信息,并使模式尽可能准确地匹配。将其剥离为最基本的必需品。以尽可能接近最终输出的格式表示它,而无需做出不必要的妥协。

如果您要显示用户名、头像、帖子标题、帖子数量、发布日期,那么这就是您在数据库中拥有的字段。是的,你仍然会有一个单独的用户数据库,但是你可以将任何东西和所有东西转换成一个简单的结构,让它变得像这样简单:

SELECT id, username, user_avatar, post_title, post_count, post_time FROM posts
  WHERE forum_id=?
  ORDER BY id DESC

通常你必须加入反对users来获得他们的名字,也许另一个表来获得他们的特定头像,以及讨论表来获得帖子计数。您可以通过更改存储策略来避免所有这些。

在我正在使用的情况下,要求能够在未来和过去发布东西,所以我必须创建一个独立于 ID 的特定“排序键”,比如你的position. 如果您不是这种情况,只需使用id主键进行排序,如下所示:

INDEX post_order (forum_id, id)

使用SUMorCOUNT是完全不可能的。您需要计数器缓存列。这些东西可以保存特定论坛中的消息数量。是的,它们会像任何非规范化数据一样偶尔偏离同步,因此您需要添加工具来检查它们,并在需要时完全重建它们。通常,您可以将其作为每天运行一次的 cron 作业来执行,以修复可能发生的任何轻微损坏。大多数情况下,如果您的实现正确,它们将完全同步。

其他需要注意的事情,如果可以的话,将帖子分成线程。你的桌子越小,它们就会越快。筛选所有帖子以查找每个线程的顶级帖子非常缓慢,尤其是在流行的系统上。

另外,如果可以的话,可以在Memcached之类的东西中缓存任何你可以逃脱的东西。例如,除非添加或删除朋友,否则用户的朋友列表不会改变,因此您不需要不断地从数据库中选择该列表。最快的数据库查询是您从未做过的,对吧?

要正确执行此操作,您需要了解每个页面的布局以及其中的信息。不太受欢迎的页面需要较少的优化,但必须仔细检查主线中的任何内容。像很多事情一样,可能有一个 80/20 规则正在运行,其中 80% 的流量只命中 20% 的代码库。那就是你想要达到最佳状态的地方。

于 2013-05-01T04:07:29.140 回答