数据库表结构说明

更新于 2026-11-08 15:32:39 19 次浏览

本文档面向二次开发者,完整说明 BlogKit v1.0.0 的数据库表结构、索引设计与表间关系。全部字段与索引均以安装脚本 core/config/install.sql 为唯一权威来源;模型层的查询封装与数据读写职责参见 目录与文件说明,系统整体架构参见 系统介绍,备份与迁移的界面操作参见 使用手册。

一、概述

  • 存储引擎:全部表使用 InnoDB,支持事务与物理外键约束。
  • 字符集与排序规则:安装器建库时统一使用 utf8mb4 字符集、utf8mb4_unicode_ci 排序规则;各建表语句只声明 CHARSET=utf8mb4,排序规则继承数据库默认值。二次开发新建表时必须显式声明 COLLATE=utf8mb4_unicode_ci,否则可能引发排序规则混用错误,详见「五、注意事项」。
  • 表前缀:本文以默认前缀 bk_ 描述。安装时可在安装页自定义前缀,安装器会把 install.sql 中的 bk_ 全量替换为所填前缀后再执行;下文所有示例 SQL 也需按实际前缀替换。
  • 安装建表:新装系统由 install.php 执行 install.sql 一次性完成建表、外键创建与初始数据写入(管理员账号、默认分类、默认主题、全部系统配置、角色与权限种子、邮件模板、示例文章与页面等)。脚本开头先关闭外键检查(SET FOREIGN_KEY_CHECKS = 0)再清理同名残留表,保证重复安装不因外键冲突失败。
  • 版本演进:系统升级不重新执行完整安装脚本,而是通过后台「系统维护 → 数据迁移」由迁移引擎(core/lib/Migrate.php)比对新版建表定义,按表补建缺失表、按列补加缺失列与索引,并按权限 code 幂等补插种子数据;每次迁移的预览与执行都会写入 bk_migration_log 表留痕。
  • 外键策略:内容主链路(文章、评论、标签关联、登录令牌、角色授权)使用物理外键约束保证一致性;树形自关联(分类、评论、角色、权限的 parent_id)与用户到角色的引用为逻辑关联,不建物理外键。物理外键统一定义在 install.sql 尾部的 ALTER TABLE 语句中,全部 ON UPDATE CASCADE,删除行为分 RESTRICT 与 CASCADE 两级,见各表小节说明。

二、表清单总览

表名用途主要关联关系
bk_article文章category_id 到 bk_category.id、user_id 到 bk_user.id,均为物理外键
bk_category文章分类parent_id 自关联支持多级分类
bk_tag标签经 bk_article_tag 与文章多对多
bk_article_tag文章与标签关联article_id 到 bk_article.id、tag_id 到 bk_tag.id,均为物理外键
bk_user用户role 到 bk_role.id 为逻辑关联;被文章、评论、日志等表引用
bk_login_tokens登录保持令牌(记住我)user_id 到 bk_user.id,物理外键
bk_comments评论article_id 到 bk_article.id、user_id 到 bk_user.id 为物理外键;parent_id 自关联形成评论树
bk_page独立页面无关联,独立内容表
bk_config系统配置(键值对)无关联,全局键值存储
bk_plugin已安装插件无关联,运行时与插件目录扫描结果合并
bk_theme已安装主题无关联,运行时与主题目录扫描结果合并
bk_email_template邮件模板无关联,type 唯一
bk_role角色parent_id 自关联实现角色继承
bk_permission权限节点(菜单/操作)parent_id 自关联形成权限树,经 bk_role_permission 授权
bk_role_permission角色与权限关联role_id 到 bk_role.id、permission_id 到 bk_permission.id,均为物理外键
bk_friendlink友情链接无关联,独立表
bk_log运行日志user_id 到 bk_user.id 为逻辑关联,可为空
bk_log_archive历史日志归档(超 90 天)结构与 bk_log 对应,user_id 逻辑关联
bk_migration_log数据迁移审计日志无关联,记录每次迁移统计与 SQL
bk_cache_stats缓存监控统计无关联,按时间片记录命中率
说明:文章点赞(bk_like)、评论点赞(bk_comment_like)、用户关注(bk_user_follow)、阅读历史(bk_read_history)、文章收藏(bk_favorite)五张互动表已随「互动增强」插件迁出核心安装脚本,新装站点由插件安装时自动建表,老站升级装回插件即认领存量数据。插件私有表的建表与升级规范参见 插件开发指南。

三、逐表详解

除特别说明外,所有表均为 ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;时间字段统一使用 int(11) 存储 Unix 时间戳(bk_cache_stats 的 timestamp 为例外,使用 datetime 类型)。

3.1 bk_article 文章表

文章内容主表,前台列表与详情页、后台文章管理的核心数据源。

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
titlevarchar(255)文章标题
contentlongtext文章内容(HTML)
descriptiontext文章描述,用于 SEO 与列表摘要
excerpttext文章摘要
cover_imagevarchar(255)封面图路径
category_idbigint(20)分类 ID,物理外键指向 bk_category.id
user_idbigint(20)作者 ID,物理外键指向 bk_user.id
statustinyint(4),默认 1状态:1 发布,0 草稿
view_countint(11),默认 0浏览次数
like_countint(11),默认 0点赞数
comment_countint(11),默认 0评论数
top_typetinyint(4),默认 0置顶类型:0 普通,1 全局置顶,2 首页置顶,3 分类置顶
created_atint(11)创建时间(Unix 时间戳)
updated_atint(11)更新时间(Unix 时间戳)
is_deletedtinyint(4),默认 0是否软删除:0 正常,1 已删除(回收站)
slugvarchar(200),可空文章别名(SEO 友好 URL),为空时按 ID 访问
  • 索引:主键 id;slug 唯一索引(NULL 不参与唯一约束,允许多篇文章无别名);created_at、top_type 单列索引;组合索引 idx_status_created(status, created_at)、idx_category_status(category_id, status, created_at)、idx_user_status(user_id, status)覆盖列表页高频查询;全文索引 ft_search 覆盖 title、content、description 供站内搜索。
  • 物理外键:fk_article_category(category_id,删除分类为 RESTRICT,需先迁移该分类下的文章);fk_article_user(user_id,删除用户为 CASCADE,物理删除用户会级联删除其文章及其文章下的评论、标签关联)。
  • 初始数据:安装时写入一篇「欢迎使用 BlogKit」示例文章(属默认分类、管理员名下、全局置顶)。

3.2 bk_category 分类表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
namevarchar(50)分类名称
descriptionvarchar(255)分类描述
keywordsvarchar(255)分类关键词(SEO)
parent_idbigint(20),默认 0父分类 ID,0 表示顶级分类
sortint(11),默认 0排序值
slugvarchar(255),默认空串分类别名
is_menutinyint(4),默认 1是否显示在分类菜单:1 显示,0 隐藏
redirect_urlvarchar(500),默认空串跳转链接,填写后点击分类跳转到该链接
created_atint(11)创建时间(Unix 时间戳)
  • 索引与关联:主键 id;parent_id 普通索引;parent_id 为逻辑自关联(不建物理外键),支持多级分类树,文章经 bk_article.category_id 引用本表。
  • 初始数据:安装时写入「默认分类」(顶级,显示在菜单)。

3.3 bk_tag 标签表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
namevarchar(50)标签名称(唯一)
countint(11),默认 0使用次数(冗余计数,避免频繁统计)
created_atint(11)创建时间(Unix 时间戳)
  • 索引与关联:主键 id;name 唯一索引;经 bk_article_tag 与文章多对多。
  • 初始数据:安装时写入 4 个示例标签(博客系统、BlogKit、开源软件、个人博客)。

3.4 bk_article_tag 文章标签关联表

字段名类型说明
article_idbigint(20)文章 ID,联合主键之一
tag_idbigint(20)标签 ID,联合主键之一
  • 索引与关联:联合主键(article_id, tag_id);tag_id 普通索引(支持按标签反查文章);物理外键 fk_article_tag_article、fk_article_tag_tag,删除文章或标签时级联清理关联行。
  • 初始数据:为示例文章关联 4 个初始标签。

3.5 bk_user 用户表

全站用户(管理员、作者、普通用户)统一存储,字段较多,按用途分组说明。

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
usernamevarchar(50)用户名(唯一)
passwordvarchar(255)密码(存储哈希值,由安装器或注册流程写入)
emailvarchar(100)邮箱(唯一,可空)
nicknamevarchar(50)昵称
avatarvarchar(255)头像路径
biotext个人简介
websitevarchar(255)个人网站
roleint(11),默认 3角色 ID,逻辑关联 bk_role.id,默认普通用户
statustinyint(4),默认 1状态:1 正常,0 禁用
is_deletedtinyint(4),默认 0是否软删除:0 正常,1 已删除(用户回收站)
deleted_bybigint(20)删除者 ID
deleted_atint(11)删除时间
reset_tokenvarchar(255)密码重置令牌
reset_token_expireint(11)密码重置令牌过期时间
pending_emailvarchar(100)待验证的新邮箱(换绑流程)
email_verification_codevarchar(10)邮箱验证码
email_verification_expireint(11)邮箱验证码过期时间
last_read_comments_timeint(11),默认 0最后阅读评论消息的时间(消息已读位点)
last_login_atint(11),默认 0最后登录时间
notification_settingstext通知设置(JSON 格式,按消息类型开关)
privacy_settingstext隐私设置(JSON 格式,关注/粉丝/点赞/收藏可见范围)
register_ipvarchar(45)注册 IP 地址
register_user_agenttext注册 User-Agent
register_referervarchar(255)注册来源
register_device_typevarchar(20)注册设备类型
register_osvarchar(50)注册操作系统
register_browservarchar(50)注册浏览器
register_browser_versionvarchar(20)注册浏览器版本
register_device_fingerprintvarchar(32)注册设备指纹(IP 与 UA 的 MD5,用于设备注册频率限制)
created_atint(11)创建时间(Unix 时间戳)
updated_atint(11)更新时间(Unix 时间戳)
  • 索引:主键 id;username 唯一索引;email 唯一索引;role 普通索引。
  • 关联:role 到 bk_role.id 为逻辑关联(无物理外键,便于角色重建);注册信息字段供注册风控统计,删除/封禁等回收站操作依赖 is_deleted、deleted_by、deleted_at 三字段。
  • 初始数据:安装时写入管理员账号一行(role 为 1 管理员),用户名、密码哈希、邮箱由站长在安装页填写,经占位符替换写入。

3.6 bk_login_tokens 登录令牌表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
user_idbigint(20)用户 ID,物理外键指向 bk_user.id
tokenvarchar(64)登录令牌(明文,用于查询)
token_hashvarchar(255)令牌哈希
expires_atint(11)过期时间(Unix 时间戳)
created_atint(11)创建时间(Unix 时间戳)
  • 索引与关联:主键 id;token 唯一索引;user_id、expires_at 普通索引(定期清理过期令牌);物理外键 fk_login_tokens_user,删除用户时级联清理其全部令牌。本表为「记住我」自动登录凭证,token 存明文用于查询,token_hash 存哈希用于校验。

3.7 bk_comments 评论表

文章评论主表,parent_id 自关联组成「主评论 + 回复」两级结构。

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
article_idbigint(20)文章 ID,物理外键指向 bk_article.id
user_idbigint(20)评论人 ID,物理外键指向 bk_user.id
contenttext评论内容
statustinyint(4),默认 0状态:1 已审核,0 待审核
created_atint(11)创建时间(Unix 时间戳)
updated_atint(11),可空更新时间(Unix 时间戳)
parent_idbigint(20),默认 0父评论 ID,0 表示主评论
ip_addressvarchar(45)评论人 IP 地址
user_agenttext评论人浏览器信息
like_countint(11),默认 0点赞数
is_deletedtinyint(4),默认 0是否软删除:0 正常,1 已删除(评论回收站)
is_toptinyint(4),默认 0是否置顶:0 未置顶,1 已置顶
  • 索引:主键 id;article_id、user_id、status、parent_id、created_at、updated_at、is_deleted、is_top 单列索引;组合索引 idx_article_status(article_id, status, created_at)、idx_user_created(user_id, created_at)覆盖文章评论列表与用户评论列表。
  • 物理外键:fk_comments_article、fk_comments_user,物理删除文章或用户时级联删除评论;parent_id 为逻辑自关联。
  • 说明:评论点赞表 bk_comment_like 已迁至「互动增强」插件,本表 like_count 为冗余计数。

3.8 bk_page 页面表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
titlevarchar(255)页面标题
contentlongtext页面内容(HTML)
descriptiontext页面描述(SEO)
keywordsvarchar(255)页面关键词(SEO)
slugvarchar(100),可空页面别名,为空时使用 ID 访问
statustinyint(4),默认 1状态:1 发布,0 草稿
is_menutinyint(4),默认 1是否显示在页面菜单:1 显示,0 隐藏
created_atint(11)创建时间(Unix 时间戳)
updated_atint(11)更新时间(Unix 时间戳)
  • 索引与关联:主键 id;slug 唯一索引;无其他关联,独立内容表。
  • 初始数据:安装时写入「关于我们」「隐私政策」「使用条款」三个示例页面(slug 分别为 about、privacy、terms)。

3.9 bk_config 配置表

系统配置键值存储,后台全部设置分页的落库位置;文件默认值见 app/Config/default.php,数据库值优先。

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
namevarchar(50)配置项名称(唯一键名)
valuetext配置项值
descriptionvarchar(255)配置项描述
typevarchar(20),默认 string配置项类型:string、integer、boolean、textarea、array
  • 索引与关联:主键 id;name 唯一索引;无其他关联。
  • 初始数据:安装时写入全部分组的配置项,涵盖站点信息、伪静态、分页、站点状态与维护模式、RSS、隐私政策与条款、LOGO、评论与反垃圾、注册与登录、SEO(首页/文章/分类/标签/页面/搜索/用户主页/归档/404)、robots 与站点地图、邮件 SMTP、验证码、文件上传、会话、安全、缓存、备份份数、版权与备案、时区、搜索、后台 IP 白名单等。

3.10 bk_plugin 插件表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
namevarchar(50)插件名称
slugvarchar(50)插件标识(唯一,与目录名一致)
descriptiontext插件描述
versionvarchar(20)插件版本
statustinyint(4),默认 0状态:1 启用,0 禁用
settingstext插件设置(JSON 格式)
created_atint(11)创建时间(Unix 时间戳)
installed_atint(11)安装时间(Unix 时间戳)
  • 索引与关联:主键 id;slug 唯一索引;无其他关联。已安装插件的注册与状态存储,与插件目录扫描结果在运行时合并,启用判定以本表 status 为准;插件安装脚本可自建私有数据表。

3.11 bk_theme 主题表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
namevarchar(50)主题名称
slugvarchar(50)主题标识(唯一,与目录名一致)
descriptiontext主题描述
versionvarchar(20)主题版本
statustinyint(4),默认 0状态:1 启用,0 禁用
settingstext主题设置(JSON 格式)
created_atint(11)创建时间(Unix 时间戳)
installed_atint(11)安装时间(Unix 时间戳)
  • 索引与关联:主键 id;slug 唯一索引;无其他关联,结构与 bk_plugin 对应。
  • 初始数据:安装时写入「默认主题」一行(slug 为 default,status 为 1,settings 与 theme.json 的默认值保持一致,保证新装即生效)。

3.12 bk_email_template 邮件模板表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
namevarchar(50)模板名称
typevarchar(50)模板类型(唯一),如 registration、password_reset、comment_notify
subjectvarchar(255)邮件主题模板,支持 {site_name} 等占位变量
contenttext邮件内容模板(HTML),支持占位变量
is_defaulttinyint(4),默认 0是否默认模板
statustinyint(4),默认 1状态:1 启用,0 禁用
created_atint(11)创建时间(Unix 时间戳)
updated_atint(11)更新时间(Unix 时间戳)
  • 索引与关联:主键 id;type 唯一索引(一种业务类型一个模板);无其他关联。发送时经变量替换后交由 Mail 类投递。
  • 初始数据:安装时写入 7 个模板:注册确认、密码重置、评论通知、文章审核通知、管理员通知、用户通知、邮箱验证。

3.13 bk_role 角色表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
namevarchar(50)角色名称(唯一)
descriptionvarchar(255)角色描述
parent_idbigint(20),默认 0父角色 ID,0 表示无父角色
statustinyint(1),默认 1状态:1 启用,0 禁用
created_atint(11)创建时间(Unix 时间戳)
updated_atint(11)更新时间(Unix 时间戳)
  • 索引与关联:主键 id;name 唯一索引;parent_id、status 普通索引;parent_id 为逻辑自关联组成继承链,子角色运行时合并父角色全部授权;bk_user.role 与 bk_role_permission.role_id 引用本表。
  • 初始数据:安装时写入 6 个角色并按固定 ID 插入:1 管理员(拥有所有权限)、2 游客、3 普通用户(继承游客)、4 作者(继承普通用户)、5 编辑(继承作者)、6 评论员(挂在游客下,仅评论管理,不沿内容链继承)。

3.14 bk_permission 权限节点表

后台权限节点,type 区分菜单与操作,parent_id 组成侧栏权限树。

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
namevarchar(50)权限名称
codevarchar(50)权限编码(唯一标识,鉴权逻辑依据)
typetinyint(1)权限类型:1 菜单,2 操作
parent_idbigint(20),默认 0父权限 ID,0 表示顶级分组
pathvarchar(100)菜单路径(如 admin.php?action=article),操作类为空
iconvarchar(50)菜单图标
sortint(11),默认 0排序值
statustinyint(1),默认 1状态:1 启用,0 禁用
is_systemtinyint(1),默认 0内置权限标记:1 为系统种子权限,禁止删除与改码,由安装与迁移引擎按 install.sql 种子自动标记
created_atint(11)创建时间(Unix 时间戳)
updated_atint(11)更新时间(Unix 时间戳)
  • 索引:主键 id;code 唯一索引;parent_id、type、status 普通索引;parent_id 为逻辑自关联,经 bk_role_permission 与角色多对多。
  • 初始数据:种子仅存核心菜单与操作节点(仪表盘、内容管理、用户管理、外观扩展、系统设置、系统维护各组及其下操作权限),「应用市场」「系统升级」两行单独插入避免与固定 ID 冲突;插件声明的菜单(互动管理、通知管理、审计日志、API 管理等)由侧栏渲染时从已启用插件的 plugin.json 运行时合并,不写入本表。

3.15 bk_role_permission 角色权限关联表

字段名类型说明
role_idbigint(20)角色 ID,联合主键之一
permission_idbigint(20)权限 ID,联合主键之一
created_atint(11)授权时间(Unix 时间戳)
  • 索引与关联:联合主键(role_id, permission_id);permission_id 普通索引(按权限反查角色);物理外键 fk_rp_role、fk_rp_permission,删除角色或权限时级联清理授权行。
  • 初始数据:管理员角色获得全部启用权限;编辑角色获得内容管理全组(含发布、审核预留操作位);评论员角色获得评论管理菜单及其下操作。授权语句采用 INSERT IGNORE,保证幂等。

3.16 bk_friendlink 友情链接表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
namevarchar(100)链接名称
urlvarchar(255)链接地址
descriptiontext链接描述
logovarchar(255)链接 LOGO 图片路径
sortint(11),默认 0排序值
statustinyint(4),默认 1状态:1 启用,0 禁用
created_atint(11)创建时间(Unix 时间戳)
updated_atint(11)更新时间(Unix 时间戳)
  • 索引与关联:主键 id;status、sort 普通索引;无其他关联,独立表,数据用于前台侧栏与友链页。

3.17 bk_log 运行日志表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
timeint(11)日志时间(Unix 时间戳)
leveltinyint(4)日志级别(数字)
level_namevarchar(20)日志级别名称(如 info、error)
categoryvarchar(50)日志分类
messagetext日志消息
contexttext上下文信息(JSON 格式)
ipvarchar(45)用户 IP 地址
user_agenttext用户浏览器信息
user_idbigint(20)用户 ID,可空,逻辑关联 bk_user.id
request_uritext请求 URI
formatvarchar(20),默认 text日志格式
  • 索引与关联:主键 id;time、level、category、user_id 普通索引(支持后台日志检索与清理);user_id 为逻辑关联(日志可能晚于用户删除存在,不设外键避免阻断清理),由日志组件分级、分类写入。

3.18 bk_log_archive 日志归档表

字段名类型说明
idint AUTO_INCREMENT主键
timeint日志时间(Unix 时间戳)
leveltinyint,默认 1日志级别(数字)
level_namevarchar(20)级别名称
categoryvarchar(50)日志分类
messagetext日志消息
contexttext上下文数据(JSON 格式)
ipvarchar(45)IP 地址
user_agentvarchar(500)用户代理
user_idint,默认 0用户 ID,逻辑关联
request_urivarchar(500)请求 URI
formatvarchar(20),默认 text日志格式
  • 索引与关联:主键 id;idx_time、idx_level、idx_category、idx_user_id 单列索引;idx_time_category(time, category)、idx_time_level(time, level)组合索引,支持归档报表按时间与分类/级别聚合;user_id 为逻辑关联,无物理外键。本表存放超过 90 天的历史日志,字段与 bk_log 对应但体积字段收紧为 varchar 以节省空间。

3.19 bk_migration_log 迁移审计日志表

字段名类型说明
idbigint(20) AUTO_INCREMENT主键
version_fromvarchar(20)迁移前版本,可空
version_tovarchar(20)目标版本
actionvarchar(20)操作类型:preview 预览,run 执行
successtinyint(1),默认 1是否成功:1 成功,0 失败
new_tablesint(11),默认 0新增表数量
new_columnsint(11),默认 0新增列数量
new_indexesint(11),默认 0新增索引数量
new_fkint(11),默认 0新增外键数量
new_config_itemsint(11),默认 0新增配置项数量
enum_changesint(11),默认 0ENUM 变更数量
errors_countint(11),默认 0错误数量
sql_executedtext执行的 SQL 语句(JSON 格式)
error_detailstext错误详情
duration_msint(11),默认 0执行耗时(毫秒)
created_atint(11)创建时间(Unix 时间戳)
  • 索引与关联:主键 id;created_at 普通索引;无其他关联,由迁移引擎写入每一次数据迁移操作的执行情况。

3.20 bk_cache_stats 缓存监控统计表

字段名类型说明
idint(11) AUTO_INCREMENT主键
timestampdatetime统计时间
hitsint(11),默认 0缓存命中次数
missesint(11),默认 0缓存未命中次数
setsint(11),默认 0缓存设置次数
deletesint(11),默认 0缓存删除次数
cache_sizebigint(20),默认 0缓存占用大小(字节)
hit_ratedecimal(5,2),默认 0.00缓存命中率(百分比)
  • 索引与关联:主键 id;timestamp 普通索引;无其他关联。按时间片记录缓存命中与操作次数,供后台缓存设置页展示监控图表;缓存组件在运行时检测本表,缺失时自动重建(建表语句显式声明 COLLATE utf8mb4_unicode_ci),过期统计按缓存设置中的保留天数自动清理。

四、常用关联查询示例

以下示例均使用默认前缀 bk_,自定义前缀的站点请自行替换。

4.1 文章列表联查(文章 + 分类 + 作者 + 标签聚合)

SELECT a.id, a.title, a.view_count, a.created_at,
       c.name AS category_name, u.nickname AS author,
       (SELECT GROUP_CONCAT(t.name ORDER BY t.id SEPARATOR '、')
          FROM bk_article_tag at2
          JOIN bk_tag t ON t.id = at2.tag_id
         WHERE at2.article_id = a.id) AS tags
FROM bk_article a
LEFT JOIN bk_category c ON c.id = a.category_id
LEFT JOIN bk_user u ON u.id = a.user_id
WHERE a.is_deleted = 0
  AND a.status = 1
ORDER BY a.top_type DESC, a.created_at DESC
LIMIT 10;

说明:标签通过子查询聚合,避免多表 GROUP BY 带来的聚合列问题;查询条件命中 idx_status_created 组合索引。

4.2 评论树查询(主评论与回复两级)

-- 第一步:查询文章下的主评论(parent_id = 0),置顶优先
SELECT c.id, c.content, c.like_count, c.is_top, c.created_at,
       u.nickname, u.avatar
FROM bk_comments c
LEFT JOIN bk_user u ON u.id = c.user_id
WHERE c.article_id = 1
  AND c.parent_id = 0
  AND c.is_deleted = 0
  AND c.status = 1
ORDER BY c.is_top DESC, c.created_at ASC;

-- 第二步:按主评论 ID 集合查询全部回复,应用层按 parent_id 分组渲染
SELECT c.id, c.parent_id, c.content, c.created_at, u.nickname
FROM bk_comments c
LEFT JOIN bk_user u ON u.id = c.user_id
WHERE c.article_id = 1
  AND c.parent_id IN (/*  ID  */)
  AND c.is_deleted = 0
  AND c.status = 1
ORDER BY c.parent_id, c.created_at ASC;

说明:系统采用两级评论结构,回复只挂主评论(parent_id 指向主评论 ID),不存在更深层的嵌套。

4.3 用户权限联查(用户 + 角色 + 权限)

SELECT DISTINCT p.id, p.name, p.code, p.type, p.path
FROM bk_user u
JOIN bk_role_permission rp ON rp.role_id = u.role
JOIN bk_permission p ON p.id = rp.permission_id
WHERE u.id = 1
  AND p.status = 1
ORDER BY p.type, p.sort;

说明:该查询只返回用户所属角色的直接授权;角色继承(子角色合并父角色授权)由应用层在运行时合并,纯 SQL 无法直接体现继承链。

五、注意事项

  1. 排序规则混用:排序规则以数据库默认值生效(安装器按 utf8mb4_unicode_ci 建库)。若在 MySQL 8 环境手工建库(默认排序规则为 utf8mb4_0900_ai_ci)后执行安装脚本,再自建未显式声明 COLLATE 的新表,新旧表 JOIN 字符串列时会报 Illegal mix of collations 错误。因此自建表必须显式写 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;排查时可对照 information_schema 逐表确认排序规则一致。
  2. 自定义表前缀:前缀在安装时确定且写入配置,二次开发读写数据应统一走模型或数据库封装的表名拼接,不要在代码里硬编码 bk_ 前缀。个别内核位置(如缓存监控组件对 bk_cache_stats 的检测与写入)按默认前缀硬编码,自定义前缀的站点会额外出现一张 bk_cache_stats 表,属于已知行为,不影响功能,但做表结构盘点时请知悉。
  3. 物理外键与删除顺序:删除 bk_category 受 RESTRICT 约束,须先将该分类下的文章迁移到其他分类;物理删除 bk_user 会级联删除其文章、评论与登录令牌。日常的删除操作走回收站软删除(is_deleted 标记),不触发物理级联,数据可恢复;只有物理删除(如直接执行 SQL 或清空回收站后的清理)才会触发级联。
  4. 备份与恢复:后台「数据备份」基于 SHOW TABLES 与 SHOW CREATE TABLE 遍历当前数据库全量导出(含插件自建表),恢复时会重建表结构与数据;恢复前请关闭外键检查或按依赖顺序导入(先 bk_user、bk_category、bk_role、bk_permission,再 bk_article、bk_comments、bk_article_tag、bk_role_permission 等子表)。备份保留份数由配置 backup_retain_count 控制(默认 5 份),大数据量站点建议额外使用数据库自带的 mysqldump 做冷备。恢复操作会覆盖现有数据,执行前务必确认备份文件完整。
  5. 修改表结构须同步安装脚本:新增字段或新表时,除执行 ALTER 外,必须同步更新 core/config/install.sql(建表语句、种子数据)并评估是否需要通过「数据迁移」机制为存量站点补列,否则新装站点与升级站点的结构会不一致。
  6. 升级走数据迁移:版本升级时不要手工执行 SQL 改表,统一使用后台「系统维护 → 数据迁移」,迁移引擎会按预览、执行两步完成结构同步并写入 bk_migration_log 审计记录,出错的 SQL 与错误详情可在日志中追溯。