资讯动态

商品分类表设计:从pms_catelog.sql看树形结构与查询优化

发布时间:2026/10/19 5:22:27 来源:尧图企业网站定制
接手商城项目的第一天我就被同事甩过来一个看起来不起眼的文件pms_catelog.sql。说这是商品分类模块的建表脚本让我先跑起来。当时没太在意觉得无非就是建几张表、灌几条数据。直到后来排查一个商品分类树加载超慢的问题翻回去看这张表的设计才发现里面每个字段都不是随便拍的整个分类体系能不能撑住后续的查询、维护、扩展全看这一张表打的地基。如果你也在做电商类的后台系统或者正在学习商城项目的数据库设计这张 pms_catelog.sql 值得你多看两眼。它不是单纯的表结构定义而是整个商品中心里“分类”这个核心主数据的源头。看完这篇你会明白这张表为什么这么建、数据怎么组织、遇到树形分类的查询该怎么写以及什么情况下这张表的设计会变成坑。1. 分类表在商城系统里的真实地位1.1 为什么商品分类是一等公民做电商系统尤其是 B2C 或 B2B2C 这类带前台商城的项目商品分类基本决定了用户怎么逛、商品怎么挂、数据怎么分析。别小看“分类”这两个字它贯穿了几乎所有的核心链路。用户在首页点“手机”这个分类系统要能快速查出该分类下有哪些商品商家后台要维护商品的分类归属运营需要按分类统计销量搜索模块要用分类信息做关键词联想推荐系统要用分类约束商品池。任何一个环节出了问题最直接的反馈就是用户体验崩了或者是后台数据混乱。所以商品分类表是商品中心最基础、最核心的主数据表之一。它的结构设计如果不合理小则查询性能堪忧大则整个商品体系没法扩展比如新增一个三级分类都要改表结构那就彻底失败了。我刚接手项目那会儿pms_catelog.sql 里建的核心表就是商品分类表。这张表的设计思路是典型的“单表自关联”树形结构也就是用一个 parent_cid父分类 ID字段把分类之间的上下级关系串起来。所有分类不论是一级、二级、三级都放在同一张表里通过父 ID 互相引用。这种设计最直观的好处是针对分类的增删改操作只需要操作一条记录不像某些老系统那样一级分类一张表、二级分类一张表搞出十几张结构相同的表维护起来想哭。你新增一个三级分类就是插入一条 parent_cid 指向某个二级分类的记录简单直接。1.2 表名的命名暗号pms_catelog 还是 pms_category看到 pms_catelog.sql 这个文件名有同学可能会犯嘀咕catalog 是不是拼错了这里我要说实话这算开源项目里比较常见的一个“历史遗留拼写”。很多项目早期命名的人把 catalog 拼成了 catelog后期为了不改一堆代码引用就将错就错沿用下来。我做项目的时候也遇到过类似情况数据库里的表名、字段名一旦定了后面再改成本很高所以经常是“错”着用。但这不影响我们学习这张表的结构反而提醒了我们一个做项目的重要原则命名这种事越早定好规范越好一旦上了线改名的代价远超想象。你在面试或者看代码的时候看到 catelog 这种拼写不用觉得奇怪知道它是 catalog 的意思就行。2. 核心表结构设计与字段解读2.1 逐字段拆解 pms_category 的建表逻辑打开 pms_catelog.sql 后核心的建表语句大概是这样的CREATE TABLE pms_category ( cat_id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 分类id, name varchar(50) DEFAULT NULL COMMENT 分类名称, parent_cid bigint(20) DEFAULT NULL COMMENT 父分类id, cat_level int(11) DEFAULT NULL COMMENT 层级, show_status tinyint(4) DEFAULT NULL COMMENT 是否显示[0-不显示1显示], sort int(11) DEFAULT NULL COMMENT 排序, icon varchar(255) DEFAULT NULL COMMENT 图标地址, product_unit varchar(50) DEFAULT NULL COMMENT 计量单位, product_count int(11) DEFAULT NULL COMMENT 商品数量, PRIMARY KEY (cat_id), KEY idx_parent_cid (parent_cid) ) ENGINEInnoDB AUTO_INCREMENT0 DEFAULT CHARSETutf8mb4 COMMENT商品三级分类;下面我一个字段一个字段说讲清楚它是干嘛的以及为什么需要它。cat_id 是主键bigint 类型自增。商品分类这种主数据数据量虽然不会像订单表那样千万级暴涨但会频繁作为商品表、品牌表、属性表的外键引用。用 bigint 能保证足够大的容量避免十年八年后自增主键爆掉这属于给自己留后路的做法。至于为什么不用雪花 ID 之类的分布式 ID因为分类的创建场景通常是后台管理员手动维护单库单表完全够用自增主键简单可靠还能保证插入时的有序性。name 是分类名称。这个字段看起来没什么好说的但实际使用中有一个容易被忽视的点。农商城的商品分类有些会加前后缀比如“手机 数码 配件”这种带空格分隔的如果不做统一规范后面做搜索匹配时要处理各种乱七八糟的格式。我的习惯是存入 name 之前做 trim并且限制录入时的字符类型中文分类名一般 2~10 个字的范围比较合理。parent_cid 是父分类 ID这是整棵分类树的“关节”。一级分类的 parent_cid 为 0二级分类的 parent_cid 指向它对应的一级分类 ID三级分类再指向二级分类 ID。通过这个字段你在代码里用一条 SQL 不断迭代查询父 ID就能拼出完整的分类层级。cat_level 表示层级一般取值 1、2、3。有同学会说既然有 parent_cid我逐层往上查就能知道当前分类是几级为什么还要冗余一个 cat_level这里面的核心原因是性能。如果你要一次性查出某个分类下面所有三级子分类的列表直接用 cat_level 过滤会比递归查询父 ID 快得多。做项目要明白一个原则在一些高频查询场景下适度冗余字段比“纯范式化”更实际。show_status 控制分类是否在前台显示。这个字段在运营场景里太关键了。一个分类刚建好但是商品还没准备好这时候你不想让用户在首页看到它但又不能删掉它怎么办直接把 show_status 置为 0 即可。这就相当于一个“软开关”让运营可以自由控制分类对用户可见还是隐藏。sort 字段控制分类在页面上的展示顺序。比如一级分类“手机”希望排第一“电脑办公”排第二那就把 sort 设成 1 和 2。这个字段背后其实有一个现实问题数据库表的默认顺序是按主键 ID 升序也就是插入的顺序。但是运营对分类的展示排序跟录入顺序往往是两码事。如果没有 sort 字段你想调整分类顺序就只能改表数据操作起来很痛苦。有了 sort只需要 update 一行数字前端一刷新页面顺序就变了。icon 存分类的图标地址。这个字段体现了前端体验的细节。商城首页的分类导航每个分类左边通常有一个小图标比如手机分类画个手机轮廓这是通过 icon 字段实现的。字段类型是 varchar(255)存的是图片的 URL 地址。这里要注意的是如果用本地存储要考虑图片迁移的问题如果走对象存储那要约定好 URL 的拼接规则不能写死环境相关的 IP 和域名。product_unit 是计量单位比如“台”“件”“箱”。这个字段有意思的地方在于它一方面给前台展示提供描述信息另一方面在某些下单场景里单位也会影响价格展示的方式。比如按箱卖的饮料和按瓶卖的饮料如果分类层级规划合理你可以在分类这一层就定好默认单位新增商品时就不用每个商品都填单位了。product_count 是商品数量统计字段。这个字段和 cat_level 一样属于典型的冗余字段。你可能会想商品数量不是应该 count 商品表里分类 ID 等于当前分类的记录数吗为什么要单独存一个字段问题在于商城前台的导航分类下面经常会显示“共 N 件商品”如果每次请求都实时去商品表 count数据库的压力非常大。所以很多系统会在分类表里冗余一个 product_count 字段通过定时任务或消息队列异步更新。这类字段在面试里经常会被拿出来聊因为它直观反映了“读写分离”和“冗余设计”的理念。2.2 主键、索引与存储引擎的取舍建表语句末尾有 PRIMARY KEYcat_id和 KEY idx_parent_cidparent_cid这里有两个细节值得展开。第一个细节是主键用bigint(20)而不是int(11)。商品分类这类的数据虽然量不大但它被外键引用的频率非常高。如果以后系统升级做分库分表bigint 的容量可以更好地兼容分布式 ID 的转换。而且 bigint 在 InnoDB 引擎下和 int 的性能差异在分类表这种规模下几乎可忽略但安全性提升是实打实的所以“能用 bigint 就不用 int”是我个人的习惯。第二个细节是给 parent_cid 建了普通索引 idx_parent_cid。这个索引是树形结构查询的生命线。你查某个分类下的所有子分类SQL 的 where 条件通常就是WHERE parent_cid ?如果没有这个索引每次查询都要全表扫描等到商品分类涨到几千条的时候虽然也不算多但叠加上商品表、品牌表的关联查询响应时间就会被放大。建上索引之后这类查询走索引效率完全不一样。存储引擎选择了 InnoDB这事不用纠结太久。InnoDB 支持事务支持外键支持行级锁所有现代互联网项目的 OLTP 场景选它都是稳妥的选择。分类表虽然不是高频更新表但属于会被并发读取的核心主数据用 InnoDB 从稳定性上讲没毛病。字符集这块我多说一句。脚本里用的 utf8mb4这是 MySQL 里真正意义上的“完整 UTF-8”能存储 emoji 表情、生僻字等等。做商城项目用户输入什么字符都有可能分类名里万一有表情符号如果字符集用旧的 utf8 就会报错或乱码。所以看到 utf8mb4 你要知道这是现代 MySQL 建表的一个标准动作不是随便选的。3. 数据脚本的落地执行3.1 执行前的基础确认拿到 pms_catelog.sql不要直接一股脑丢进命令行。先确认三件事MySQL 版本、目标数据库、执行工具编码。这个脚本是在 MySQL 5.7 以上的环境里设计的新版本 8.0 也完全兼容但要注意 8.0 对字符集默认值处理有所区别。如果是 8.0建议建库时显式指定 UTF8MB4CREATE DATABASE IF NOT EXISTS mall DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;目标数据库要提前定好。很多新人会把建表脚本直接跑在 root 用户默认的 test 库里之后项目配置的数据库连接串又指向另一个库结果就是表建了但项目启动后永远提示“table not exist”。这种问题查起来很冤。我建议在执行前打开脚本文件确认里面有没有USE database_name;这一句。如果没有自己先执行USE 你项目的库名;。执行工具编码要确认。命令行下执行 SQL 脚本如果终端编码和脚本编码不一致轻则中文注释乱码重则 SQL 解析出错。我的习惯是如果脚本里有中文注释或中文数据就先在客户端工具里设置连接编码SET NAMES utf8mb4;这条命令告诉 MySQL 客户端接下来发送和接收的数据使用 utf8mb4 编码避免控制台和数据库之间的编码错乱。3.2 一步步执行导入脚本确认完基础环境就可以执行导入了。常见的方式有两种。第一种直接在 MySQL 命令行中使用 source 命令mysql -u root -p进入 mysql 的交互界面后执行USE mall; SOURCE /path/to/pms_catelog.sql;source 命令适合那种一次性导入、脚本文件较大的情况。它会读取指定路径下的 SQL 文件并逐条执行执行过程会在屏幕上打印进度。如果脚本里有错误它会继续往下执行但你要留意屏幕上输出的报错信息。第二种在系统 shell 层面直接用重定向导入mysql -u root -p mall /path/to/pms_catelog.sql这种方式不需要先登录 MySQL适合自动化部署脚本。注意参数 mall 是数据库名如果文件里没写 USE 语句这里指定库名就必须写对。在持续集成流水线或者 Docker 容器初始化脚本里这种方式是最常见的。导入完成后验证是否成功。用最简单的查询看看表结构是否完整SHOW TABLES LIKE pms%; DESC pms_category;再查一下分类数据SELECT cat_id, name, parent_cid, cat_level FROM pms_category ORDER BY cat_id LIMIT 20;SELECT 的结果如果中文显示正常就说明字符集没问题如果显示成一串问号或乱码就要回头检查连接编码和客户端显示设置。3.3 脚本执行失败时怎么看报错执行过程中最常遇到的报错大概有这么几类第一类是“Table pms_category already exists”。这说明这张表之前就建过了。如果你确认这是旧数据想清空重来可以手动先删旧表再执行脚本DROP TABLE IF EXISTS pms_category;但注意前提是这张表没有被其他表外键引用否则删了会导致关联表数据出问题。生产环境里这种操作要非常谨慎测试环境随便造。第二类是“Unknown collation”或者“Unknown character set”之类的报错。这类错误几乎都和版本有关。比如有些老版本 MySQL 5.5 不支持 utf8mb4_general_ci 某些新特性或者 4.x 版本根本没有 utf8mb4。解决办法就是升级 MySQL 版本或者把脚本中的字符集统一改为目标环境支持的字符集。第三类报错是主键冲突。比如脚本里 INSERT 语句指定的主键 ID 和现有数据冲突。这种情况在重复执行脚本的时候经常发生。你只要记住一个原则pms_catelog.sql 里的分类数据属于基础初始化数据它的执行场景一般是一次性初始化而不是频繁的增量更新。如果已经初始化过了就不要再重复导入全量脚本否则就要先清理存量数据。4. 分类树查询的实战写法与性能注意4.1 查询所有子分类的两种方式数据进去了最关键的问题来了怎么根据一个父分类 ID查出它的所有子分类第一种方式使用递归查询。MySQL 8.0 提供了 WITH RECURSIVE 语法可以直接写递归 CTEWITH RECURSIVE category_tree AS ( SELECT cat_id, name, parent_cid, cat_level FROM pms_category WHERE cat_id 1 UNION ALL SELECT c.cat_id, c.name, c.parent_cid, c.cat_level FROM pms_category c INNER JOIN category_tree t ON c.parent_cid t.cat_id ) SELECT * FROM category_tree;这段 SQL 先查询根节点 cat_id1然后不断通过 parent_cid 匹配下一层子节点直到没有匹配为止。它能够一次性拿到整棵子树适合前台导航的全量展示。在 MySQL 5.7 及其以下版本里不支持递归 CTE那么在代码中可以通过多次查询拼接子节点列表。虽然没有一条 SQL 那么方便但数据量不大的情况下性能完全可以接受。第二种方式在应用层组装树。先一次性查出分类表全量数据几千条级别不算什么压力在 Java、Python、PHP 之类的代码里通过内存循环构建父子关系组装成树形结构返回给前端。这是互联网项目里比较常见的做法因为分类表数据量稳定可控一次全量加载到内存的成本很低而应用层做树的组装逻辑也更灵活各种过滤条件都好加。很多开发团队的“分类树”接口后端返回的数据就是这么来的。这两种方式怎么选取决于你的数据规模和接口要求。如果你的商城是那种上万条分类级别的大型平台一次性全量查回内存可能不合适递归查询按需加载更好。如果只是几千条那我强烈推荐应用层组装理由很简单逻辑直观、好调试、对数据库友好。4.2 常见错误生产环境频繁执行递归查询我在实际项目中踩过一个坑这里一定要提醒你。刚开始时为了省事每次前台请求分类导航我都直接发一条递归 SQL 去数据库查全部分类树。后来数据量上来后这套接口开始频繁超时那段时间被运营吐槽了无数轮。排查下来发现分类导航接口的 QPS 很高每个用户打开首页都要请求一次而递归 CTE 在数据库层的执行路径依赖于多次内连接看不出性能有多差但实际上每一次请求都会产生一次开销不小的递归遍历。优化方案就是把分类树数据放进缓存比如 Redis 中存储组装好的树结构 json并设置合理的过期时间。运营后台一旦修改了分类就主动删掉缓存 key强制重新加载。这个经验的核心点是分类数据的特点是“读多写少”而且结构高度稳定。针对这种数据最合适的套路就是缓存。绝大多数商城项目的分类导航缓存命中率都能做到 95% 以上。5. 商品分类表在业务中的典型联表场景5.1 推演一下品牌和分类的关系商品分类不是孤零零的一张表。一个典型场景你要给某个分类关联品牌。比如“手机”分类下面关联苹果、华为、小米等品牌用户筛选的时候点“品牌”分组就能看到这些关联数据。这个场景的实现策略是复制一张关联表比如 pms_category_brand表里有 category_id 和 brand_id 两个外键。这么设计的初衷是为了实现“分类-品牌”的多对多关系。如果没有这张表直接把 brand_id 存在 pms_category 里面那一个分类就只能绑定一个品牌显然不现实。从 pms_category 这张表的设计视角看它通过主键为这些关联表提供了稳定的引用锚点。你只要保证了 cat_id 的稳定性后续加多少关联表都不会出乱子。这也是主数据表最重要的职责之一给整个系统提供稳定、可靠的引用点。5.2 属性和分类的绑定逻辑商城系统里商品属性是跟分类强绑定的。比如手机分类有“运行内存”“存储容量”“屏幕尺寸”这些属性而洗面奶分类则可能有“适用肤质”“净含量”这些属性。属性挂在分类上新增商品时后台会根据商品所属分类动态加载对应的属性模板。这张属性绑定逻辑在实现上通常在 pms_attr 表或者类似叫法的表加 category_id 字段表示该属性属于哪个分类。从这里你就能看出 pms_category 表有多核心了不仅仅商品挂在分类上规格参数、品牌、筛选属性全都挂在分类上。所以设计分类表的时候主键稳定性怎么强调都不为过。一旦上线运营了一段时间分类 ID 被大量引用这时候如果因为误操作把 cat_id 改了后果是灾难级别的。所有关联数据全部错乱商品找不到分类分类下没有商品整个前台会变得一塌糊涂。做开发的时候我经常在项目代码里看到有人直接根据分类 name 去关联查询。这背后可能是为了图省事想跳过 cat_id 的关联。但这属于极其危险的操作因为 name 很容易重复或修改。正确的做法永远是用主键 ID 做关联name 只是展示用的“装饰品”。6. 分类表设计的扩展方向与避坑清单6.1 如何扩展支持无限层级有些业务可能不止三级分类比如跨境商品有时会出现四级甚至五级分类。当前的 pms_category 表只设计了三层cat_level 字段的取值如果超出了 3系统代码里可能会部分失效。要扩展无限层级一个比较粗糙的做法是重新定义 cat_level 和 parent_cid 的取值规范让代码对层级数不做硬性限制。但这样做需要修改业务逻辑中对层级的硬编码判断。更聪明的做法是甩开 parent_cid 的复杂度另加一个 path 字段。比如一级分类的 path 是 /1/二级分类的 path 是 /1/2/三级分类的 path 是 /1/2/3/。要查某个分类节点的所有子分类只需要WHERE path LIKE /1/2/%既高效又简单。这种方案在需要规律性查询层级结构的场景下非常实用。不过它也有天生的缺点就是移动分类节点时子节点的 path 都要同步更新。如果你的业务层级确实比较深数据量又大可以把“路径枚举”和“自关联”两种方案结合着用。自关联负责维护树形逻辑path 负责查询加速。我从实际经验看大多数商城三类分类就够用了过度设计反而增加维护成本。6.2 调整分类结构时要注意的连锁反应运营调整分类是家常便饭比如把“手机配件”从“手机通讯”下面挪到“数码产品”下面。在表里操作可能就是 update 一下 parent_cid但这个问题远没这么简单。一旦这个分类下面挂了许多商品、品牌关联、属性模板所有这些数据都要跟着“搬家”。如果系统里没有做联动处理那么就会出现“分类移动了商品还挂在旧分类路径上”的状态导致搜索和筛选结果不一致。这里推荐一个做法在分类调整接口中实现事务性操作。要么整体成功要么整体回滚。如果一个分类下有商品系统应该先提醒用户必须先将该分类下的商品全部移走否则不允许修改父分类。别看这一条不起眼它能帮你省掉无数个“数据对不上”的深夜。这个严谨度是商业级系统与 demo 项目的分水岭。6.3 开发初期就该定好的三个规范结合我总结的教训在建表脚本刚开始落地时就建议团队定好三个规范。第一分类名称的唯一性校验收紧。同一层级下分类名不能重复这一条要通过后端接口保证一般不允许用户在界面上任自由输入。为缓解输入带来的脏数据可以在数据库层面为 name 和 parent_cid 建一个联合唯一索引比如ALTER TABLE pms_category ADD UNIQUE KEY uk_name_parent (name, parent_cid);第二条所有关联表的外键字段统一叫 category_id不要一会叫 categoryId一会叫 cid一会又叫 pms_cat_id。这个建议听起来像是在说废话但你真的很难想象当项目维护到第三年、代码量堆到几十万行之后光是字段名不统一就能让新人疯掉。表结构的一致性是代码可维护性的隐形基础。第三条分类坐标一旦生成不允许手工修改。所有对分类 ID 的变更必须通过后台服务接口来执行防止有人直接连数据库改数据。被改乱的分类关系调试成本远高于重新造一套数据。7. 踩坑实录执行 pms_catelog.sql 后的三个隐藏问题7.1 自增主键没有从 1 开始有些版本的脚本里AUTO_INCREMENT 的起始值是 0但 MySQL 在初始化时实际会从 1 开始分配。这本来不是问题但你如果清空表后想让 ID 重新从 1 开始用 TRUNCATE 才是干净利落的方式而 DELETE FROM 除了删除数据并不会重置自增计数器。我在项目初始化时遇到过类似的尴尬删了所有测试数据后新插入的第一条分类 ID 直接变成了 100 多搞得测试同学以为数据没删干净。所以这里给大家提个醒在执行初始化脚本前如果希望清空重来用TRUNCATE TABLE pms_category;而不是DELETE FROM pms_category;两者效果在测试数据量不大时看起来一样但 TRUNCATE 会重置 AUTO_INCREMENTDELETE 不会。关于这一点面试官也很喜欢拿出来考核属于基本功范畴。7.2 父子分类数据不一致时如何自查当你发现分类树“莫名”少了一个分支或者某个分类层级对不上优先检查父分类的完整性。由于表没有外键约束这是电商大表设计中的普遍取舍性能优先你完全可能插入一个 parent_cid 指向不存在的分类而这在数据库层面不会被拦截。要自查脏数据可以使用一条 LEFT JOIN 查出来SELECT c.cat_id, c.name, c.parent_cid FROM pms_category c LEFT JOIN pms_category p ON c.parent_cid p.cat_id WHERE c.parent_cid ! 0 AND p.cat_id IS NULL;这条 SQL 的核心逻辑是找出 parent_cid 指向了不存在节点的记录。运行之后如果查出结果说明分类树有坏链要么补上缺失的父分类要么修正子分类的 parent_cid。这个自连接的场景很典型建议收藏。7.3 从建表开始就留好审计字段写完 pms_category 表之后我还推荐你在生产环境中加两个常用字段create_time 和 update_time。原脚本里没有这两个字段但在真实项目中分类的创建和修改是运营审计的重要组成部分。尤其是“谁在什么时候把分类下线了”或者“什么时候改了分类名称”在问题反馈时非常重要。如果已经上线了可以用一条 ALTER 语句补上ALTER TABLE pms_category ADD COLUMN create_time datetime DEFAULT NULL COMMENT 创建时间, ADD COLUMN update_time datetime DEFAULT NULL COMMENT 更新时间;做后台管理系统这种时间审计字段的价值我在项目中体会得太深刻了。日报周报要数据结构变更说明运营扯皮要查操作记录开发排查 bug 要定位数据变更时间少了它们寸步难行。8. 延伸思考分类表数据能不能上缓存分类表的读多写少特性天然适合上缓存。我刚才已经提到分类导航接口扛不住频繁递归查询的一个优化手段就是用 Redis 缓存分类树 JSON。实际落地时比较稳的做法是双缓存策略。也就是说一级分类和二级分类作为“基础分类缓存”单独存一份过期时间设得长一点比如 24 小时。三级分类数量较多变更也相对频繁可以单独存在另一个 key 里过期时间设短比如 30 分钟。当后台做分类变更时同时删除这两类缓存 key确保数据最终一致。这么做的原因是前台页面往往只需要前两级分类做导航展示而进入三级分类页时才需要更深的层级。把不同层级的变更频率区分开到了真实场景会大幅减少缓存重建的代价。我当时的项目把缓存套上去之后分类导航接口的响应时间从平均 120ms 降到了 3ms 以内这个数字绝对是质的飞跃。缓存不是银弹但它对这种“读多写少、结构稳定”的数据就是最优解。9. 从一张分类表看整套系统设计观我在和团队里新人交流的时候经常反复强调一句话一张表的设计永远不会只是因为这张表本身它背后代表的是对整个业务链条的理解。你以为你是在建 pms_category 这张表实际上你是在定义整个商品体系的“挂载点”。以后商品挂在它身上属性挂在它身上品牌挂在它身上运营的活动页也通过它来组织商品。分类表设计的稳不稳直接决定了后面的业务能不能顺畅铺开。从 pms_catelog.sql 这个脚本入手复盘了这么多内容其实是想借这个入口让你明白商城系统里主数据建模的核心逻辑。真正的高手从一张建表语句里就能看出背后的业务边界、查询模式、扩展方向甚至数据生命周期管理策略。做开发不能只是“会执行 SQL”更要看得懂 SQL 背后的设计意图。如果你现在正在搭建商城的商品模块或者正在梳理自家系统的分类数据建议你把开头讲的那些字段设置对照你的现状过一遍看看有没有哪一条落下。分类表这种底层数据表起步时改成本最低等业务跑起来后动它每一次变更都像在高速公路上换轮胎。最后再分享一个我的个人体会。开发工作里那些最不起眼的“小脚本”往往藏着项目最初设计者最多的思考。我已经数不清有多少次是靠着翻看项目早期遗留的建表语句才看懂业务逻辑的来龙去脉。所以别嫌 pms_catelog.sql 小认真读它你会学到很多比 CRUD 更值钱的东西。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑