我不得不使用 PHP 和 MySQL 为一个每天浏览量超过一百万的网站设计一些分页策略。我分阶段研究策略:
多列索引我应该在尝试物化视图之前先完成此操作。
生成物化视图。我创建了一个 cron 作业,它对我正在使用的文档表进行了常见的非规范化。我会SELECT ... INTO OUTFILE ... 然后创建新表,并将其旋转:
SELECT ... INTO OUTFILE '/tmp/ondeck.txt' FROM mytable ...;
CREATE TABLE ondeck_mytable LIKE mytable;
LOAD DATA INFILE '/tmp/ondeck.txt' INTO TABLE ondeck_mytable...;
DROP TABLE IF EXISTS dugout_mytable;
RENAME TABLE atbat_mytable TO dugout_mytable, ondeck_mytable TO atbat_mytable;
这将写竞争mytable 的锁定时间降至最低,并且分页查询可能会在atbat 物化视图上敲打。我已经简化了上述内容,省略了不重要的实际操作。
Memcache 然后我创建了一个关于我的数据库连接的包装器,以将这些分页结果缓存到 memcache 中。这是一个巨大的性能胜利。但是还是不够好。
批量生成 我编写了一个 PHP 守护程序并将分页逻辑提取到其中。它将检测mytable 的更改并定期从最旧的更改记录重新生成到最新记录的所有页面到网络服务器的文件系统。使用一点mod_rewrite,我可以检查该页面是否存在于磁盘上,并提供它。这也让我能够通过让 Apache 检测 If-Modified-Since 标头并使用 304 响应代码来有效地利用 反向代理。 (显然,我删除了任何允许用户选择每页结果数量的选项,这是一个不重要的功能。)
更新:
RE count(*): 使用 MyISAM 表时,COUNT 并没有造成问题,因为我能够减少表上的读写争用量。如果我在做 InnoDB,我会创建一个触发器,用行数更新相邻表。根据 INSERT 或 DELETE 语句,该触发器只会 +1 或 -1。
RE 页面选择器(指轮) 当我转向主动查询缓存时,指轮查询也被缓存,而在批量生成页面时,我使用的是临时表——所以计算指轮没有问题。很多指轮计算简化了,因为它变成了一种可预测的文件系统模式,实际上只需要最大的页码。最小的页码始终为 1。
Windowed thumbweel 只要你知道你的最大值页数。