WP DEVELOP

EP163. “自定义数据库表章节导论:post meta 为何会慢”

首页 WordPress 开发课程 插件开发 CH3:数据库存储 · EP163
约 11 分钟· #EP163#插件开发 CH3:数据库存储
🔒 登录后可标记已读

插件开发第三章(也是最后一章)的开场:什么时候该放弃 WordPress 的自定义文章类型(custom post type),改用自己手写的自定义数据库表。用一个 10 万条宠物领养数据的演示站直观对比:不带筛选条件的基础查询,两种方案速度差不多;但只要加上「按某个自定义字段筛选」(比如「species=cat 且 favColor=green」),custom post type 版本要 1.2 秒,自定义表版本只要十分之一秒出头——快了近十倍。这一讲不写代码,用课程提供的 pets-custom-post-type 演示插件实际跑一遍、翻数据库表结构,理解「为什么会慢」,为后面几讲真正动手写自定义表打基础。


涉及文件

  • pets-custom-post-type/pets-custom-post-type.php (课程提供的演示插件,仅用来观察对比,不用照抄或修改)
  • pets-custom-post-type/inc/CreatePets.php (演示插件的批量生成假数据逻辑)

代码实现

演示插件的核心结构(仅供理解,不是本讲要写的代码)

add_action('init', 'ourInit');

function ourInit() {
  register_post_type('pet', array(
    'label' => 'Pets',
    'public' => true,
    'menu_icon' => 'dashicons-buddicons-activity',
    'show_in_rest' => true,
    'supports' => array('title', 'editor', 'custom-fields')
  ));
}

function insertPetPosts() {
  for ($i = 0; $i < 84000; $i++) {
    $pet = generatePet();

    wp_insert_post(array(
      'post_type' => 'pet',
      'post_title' => $pet['name'],
      'post_status' => 'publish',
      'meta_input' => array(
        'species' => $pet['species'],
        'favFood' => $pet['favFood'],
        'birthYear' => $pet['birthyear'],
        'weight' => $pet['weight'],
        'favColor' => $pet['favColor'],
        'favHobby' => $pet['favHobby']
        )
    ));
  }
}

关键概念:

  • 每个宠物就是一篇 pet 文章类型的文章:名字是文章标题,剩下 6 个属性(species/favFood/birthYear/weight/favColor/favHobby)全部通过 wp_insert_post()meta_input 存成 post meta——这是标准的 WordPress 数据建模方式:一切都是「文章 + 元数据」
  • 插件自带一个默认注释掉的 add_action('admin_head', 'insertPetPosts'),取消注释、刷新一次后台就会批量生成假数据(本讲提醒:本地开发机器可以设很大的数字来体验 10 万条数据,但千万不要在真实付费主机上设一个很大的数字,会拖垮甚至跑超时整个网站)
  • 数据库层面观察到的现象(用 LocalWP 自带的 Adminer/phpMyAdmin 看两张表):
    • wp_posts 表:不管有多少宠物,这张表本身每篇文章只占一行,「查前 100 篇 post_type = pet 的文章」这种基础查询几乎不受数据量影响,一直很快
    • wp_postmeta 表:每篇宠物文章会在这张表里产生 6 行(species 一行、favFood 一行……),这张表的行数是 文章数 × 每篇的元数据个数 在暴涨,宠物越多这张表膨胀得越厉害
  • 为什么「按 species=dog 筛选」会变慢:不带筛选条件的基础查询,WordPress 只需要在 wp_posts 表里找 post_type = pet 的记录,这一列可以被索引、查询效率跟数据量增长关系不大;但一旦要按某个 meta 值筛选,WordPress 必须先去 wp_postmeta 表里找「meta_key = 'species'meta_value = 'dog'」的记录——即使 meta_key 这一列可以被索引,meta_value 存的是不区分类型的通用字符串字段,没法像专属列那样被高效索引和比较,数据量一大,这种查询的耗时会随着 wp_postmeta 表的行数线性甚至更快地增长
  • 对比自定义数据库表的设计:如果换成自己建一张 pets 表,每个宠物只占一行,species/favColor 等 6 个属性各自是这张表里专属的一列——查询「species=dog」时数据库只需要在这一张、行数等于宠物总数的表里查一个专属列,不需要跨表关联、也不需要在一个塞满各种不同 meta_key 的通用表里筛选,这是自定义表能快上近十倍的根本原因
  • custom post type 换来的东西不是白拿的:牺牲了一部分极端场景下的查询性能,换来的是 WordPress 免费提供的一整套现成能力——后台管理界面的增删改查、REST API 端点、跟角色权限系统的绑定等等,这些如果全部换成自定义表都要自己从零实现
  • 什么时候真的该用自定义表:作者给出的判断标准是必须同时满足两个条件:① 需要按某个自定义字段去筛选/搜索(不只是存起来,是要按它查询);② 预期这类文章的数量会变得非常大(几千、几万甚至更多)。只满足其中一个条件(比如字段很多但文章总量不大,或者文章很多但从不需要按自定义字段筛选)都不构成换用自定义表的理由——作者估计十次里有九次,用 WordPress 自带的自定义文章类型仍然是更明智的选择

[截图:phpMyAdmin/Adminer 里对比 wp_posts 表(每篇宠物只占一行)和 wp_postmeta 表(每篇宠物膨胀成 6 行)的行数差异]


常见坑

  • 在真实的付费虚拟主机上把演示插件里批量生成假数据的数量设得很大(比如十万)——本地开发机器上没问题,但真实主机很可能直接超时或者拖垮整个网站
  • 只看到「自定义表快十倍」就觉得所有场景都该用自定义表——忽略了自定义表要放弃 WordPress 免费提供的后台界面、REST API、权限绑定等一整套能力,开发成本会指数级上升
  • 误以为只要数据量大就该换自定义表——真正的判断标准是「数据量大」「需要按自定义字段查询」两个条件同时成立,缺一不可

延伸 / 后续讲座会用到

接下来几讲要动手写这个自定义数据库表版本的宠物领养插件,从建表开始一步步实现。


Sources

Udemy:

  • Become a WordPress Developer: Unlocking Power With Code — Section 27, EP163