PbootCMS 数据库索引优化:解决列表页查询慢的问题(记录篇)

    某 PbootCMS 站点内容表 ay_content 数据量 378MB、6,562 行,列表页打开极慢。经索引诊断,发现索引设计存在严重问题,导致 MySQL 无法高效执行列表页查询。

    一、索引诊断结果

    索引名列基数(去重值)问题
    PRIMARYid5050✅ 正常
    content_scodescode14⚠️ 单列,只有 14 个栏目值
    content_subcodesubcode1❌ 基数 1,完全无用
    content_acodeacode1❌ 基数 1,完全无用
    content_filenamefilename1❌ 基数 1,完全无用
    content_datedate5050⚠️ 单列
    content_sortingsorting1❌ 基数 1,完全无用
    content_statusstatus2⚠️ 低基数
    content_title_indextitle5050✅ 正常

    二、核心问题分析

    PbootCMS 列表页的查询逻辑是:

    SELECT * FROM ay_content WHERE scode = ? ORDER BY date DESC LIMIT n

    但当前索引设计存在致命缺陷:

    • scode 是单列索引(只能定位到该栏目的行)
    • date 是另一个单列索引(只能排序)

    MySQL 无法同时用两个单列索引做“过滤 + 排序”——它只能选一个走,另一个走全表扫描 + filesort。378MB 的表每次列表页都全扫一遍再排序,难怪慢。

    另外:378.9MB / 6,562 行 ≈ 平均每行 58KB。正常 CMS 内容表应该在 5~10KB/行。说明要么有大量长文本/BLOB 字段,要么表碎片严重(可后续通过 OPTIMIZE TABLE 清理)。

    三、修复方案:添加复合索引

    在 phpMyAdmin 的 SQL 标签里执行以下命令:

    ALTER TABLE ay_content ADD INDEX idx_scode_date (scode, date);

    执行时间取决于表大小(378MB),预计需要 10~30 秒,期间该表会被短暂锁写(读不受影响)。建议在访问低峰期执行。

    四、验证索引是否生效

    SHOW INDEX FROM ay_content;

    输出里应该多出一行 idx_scode_date,列显示为 scode + date,即表示添加成功。

    五、补充建议

    • 删除冗余索引:content_subcode、content_acode、content_filename、content_sorting 基数均为 1,完全无用,建议删除以提升写入性能
    • 清理表碎片:OPTIMIZE TABLE ay_content(低峰期执行,会锁表)
    • 检查字段类型:平均行 58KB 偏大,排查是否有 TEXT/BLOB 字段存储了非必要的大数据

    说明:
          • 以上索引诊断基于 PbootCMS 内容表 ay_content 的实际结构。
          • 添加复合索引后,列表页查询将同时使用 scode 过滤和 date 排序,大幅提升性能。
          • 建议在操作前备份表结构,并在低峰期执行。
          • 具体执行时间以实际服务器性能为准。