08-高性能表结构及索引设计最佳实践-02

本文详细介绍了MySQL InnoDB存储引擎中的各种索引类型及其工作原理,包括聚集索引、辅助索引、联合索引和自适应哈希索引。通过实际表order_exp的例子,讲解了这些索引如何提高数据库查询效率。

MySQL索引辨析

范例表说明

经常使用到InnoDB表order_exp,基础表结构如下:

在这里插入图片描述
数据量大概在1万多行。
在这里插入图片描述
同时还有个几个派生表如s1,s2,order_exp_cut,表结构基本和order_exp一致,有少许差别,数据量上也比order_exp少:

在这里插入图片描述
在这里插入图片描述

InnoDB中的索引复习

聚集索引/聚簇索引

InnoDB中使用了聚集索引,就是将表的主键用来构造一棵B+树,并且将整张表的行记录数据存放在该B+树的叶子节点中。

辅助索引/二级索引

对于辅助索引(Secondary Index,也称二级索引、非聚集索引),叶子节点并不包含行记录的全部数据。叶子节点除了包含键值以外,每个叶子节点中的索引行中还包含了相应行数据的聚集索引键。
在这里插入图片描述

回表

辅助索引的存在并不影响数据在聚集索引中的组织,因此每张表上可以有多个辅助索引。当通过辅助索引来寻找数据时,InnoDB存储引擎会遍历辅助索引并通过叶级别的指针获得指向主键索引的主键,然后再通过主键索引(聚集索引)来找到一个完整的行记录。这个过程也被称为回表。也就是根据辅助索引的值查询一条完整的用户记录需要使用到2棵B+树----一次辅助索引,一次聚集索引。

联合索引/复合索引

前面我们对索引的描述,隐含了一个条件,那就是构建索引的字段只有一个,但实践工作中构建索引的完全可以是多个字段。所以,将表上的多个列组合起来进行索引我们称之为联合索引或者复合索引,比如index(a,b)就是将a,b两个列组合起来构成一个索引。

自适应哈希索引

InnoDB存储引擎除了我们前面所说的各种索引,还有一种自适应哈希索引,我们知道B+树的查找次数,取决于B+树的高度,在生产环境中,B+树的高度一般为34层,故需要34次的IO查询。

全文检索之倒排索引

什么是全文检索(Full-Text Search)?它是将存储于数据库中的整本书或整篇文章中的任意内容信息查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。我们比较熟知的Elasticsearch、Solr等就是全文检索引擎,底层都是基于Apache Lucene的。举个例子,现在我们要保存唐宋诗词,数据库中我们们会怎么设计?诗词表我们可能的设计如下:
在这里插入图片描述

<think>我们正在设计一个菜单表结构,需要遵循数据库设计最佳实践。根据引用内容,我们可以参考数据库设计的基础理论和关键技术,以及实际应用场景。菜单表通常用于存储系统中的菜单项,比如导航菜单、权限菜单等。设计菜单表时,需要考虑以下几点:1.菜单项的层级关系(父子关系)2.菜单的排序3.菜单的元数据(名称、图标、路径等)4.菜单的权限控制(可选,如果与权限关联)常见的菜单表结构设计有两种方式:方式一:邻接表(AdjacencyList)这是最简单的树形结构存储方式,每个菜单项存储其父菜单的ID。优点:结构简单,操作方便。缺点:递归查询效率较低(在MySQL8.0之前需要使用递归查询或多次查询,MySQL8.0支持CTE递归查询)。方式二:嵌套集(NestedSet)每个菜单项存储左值和右值,通过左右值来确定层级关系。优点:查询子树和祖先路径效率高。缺点:插入和删除节点时需要调整多个节点的左右值,操作复杂。在实际应用中,邻接表因为简单而被广泛采用,特别是当菜单层级不深(如3-4级)且数据量不大时。此外,还可以考虑使用闭包表(ClosureTable),它通过一个额外的表来存储节点之间的关系,从而解决邻接表递归查询效率低的问题。但是,根据最佳实践,对于菜单这种通常层级不深且变动不频繁的数据,邻接表是足够且易于维护的。因此,我们可以设计一个使用邻接表方式的菜单表:表名:`menu`字段:-`id`:主键,自增整数-`parent_id`:父菜单ID,外键引用本表的id,可为NULL(表示顶级菜单)-`name`:菜单名称,VARCHAR(50)-`path`:菜单对应的路径(或路由),VARCHAR(255),可为NULL(如果是分组菜单)-`icon`:菜单图标,VARCHAR(50),可为NULL-`sort_order`:排序权重,INT,用于同级菜单的排序-`is_enabled`:是否启用,BOOLEAN,默认为1(启用)-`created_at`:创建时间,TIMESTAMP-`updated_at`:更新时间,TIMESTAMP此外,如果需要权限控制,可以关联权限表,比如每个菜单项可以关联一个权限标识(permission_code),或者通过角色-菜单关联表来实现。示例SQL创建语句:```sqlCREATETABLEmenu(idINTAUTO_INCREMENTPRIMARYKEY,parent_idINTNULL,nameVARCHAR(50)NOTNULL,pathVARCHAR(255)NULL,iconVARCHAR(50)NULL,sort_orderINTDEFAULT0,is_enabledBOOLEANDEFAULT1,created_atTIMESTAMPDEFAULTCURRENT_TIMESTAMP,updated_atTIMESTAMPDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMP,FOREIGNKEY(parent_id)REFERENCESmenu(id)ONDELETECASCADE);```注意:-外键约束`ONDELETECASCADE`表示当父菜单被删除时,子菜单自动删除。-如果使用InnoDB引擎,外键约束才有效。查询所有菜单并按层级和排序权重展示:在MySQL8.0以上,可以使用递归CTE(CommonTableExpression)查询:```sqlWITHRECURSIVEmenu_treeAS(SELECTid,parent_id,name,path,icon,sort_order,1ASlevelFROMmenuWHEREparent_idISNULLUNIONALLSELECTm.id,m.parent_id,m.name,m.path,m.icon,m.sort_order,mt.level+1FROMmenumINNERJOINmenu_treemtONmt.id=m.parent_id)SELECT*FROMmenu_treeORDERBYlevel,sort_order;```在MySQL8.0以下,通常需要在应用层进行递归查询(多次查询,然后构建树形结构)。另外,如果菜单需要支持多语言,那么还需要设计菜单名称的多语言表,这里不展开。总结:菜单表结构设计采用邻接表模式是常见且实用的做法。同时,通过外键约束保证数据完整性,通过递归查询(或应用层构建树)来获取层级结构。参考引用:[^1]提到数据库设计的基础理论和关键技术,以及实际应用场景。[^2]提供了一个数据库设计的实例(个人博客数据管理系统),其中包含了表结构设计。[^3]介绍了使用MySQLWorkbench进行数据库设计与管理,我们可以使用该工具来设计并生成菜单表。根据以上设计,我们可以满足菜单的基本管理需求。§§相关问题§§1.菜单表如何支持无限层级?2.在菜单表设计中,如何优化递归查询的性能?3.菜单表与权限系统如何关联设计?</think>### 数据库菜单表结构设计最佳实践设计菜单表结构时,需考虑**层级关系、权限控制、灵活扩展**等核心需求。以下是经过验证的最佳实践方案: #### 基础表结构设计(邻接表模型) ```sql CREATE TABLE sys_menu ( menu_id INT AUTO_INCREMENT PRIMARY KEY COMMENT '菜单ID', parent_id INT DEFAULT 0 COMMENT '父菜单ID(0表示根节点)', menu_name VARCHAR(50) NOT NULL COMMENT '菜单名称', menu_path VARCHAR(255) COMMENT '路由路径', menu_icon VARCHAR(50) COMMENT '图标类名', sort_order INT DEFAULT 0 COMMENT '排序权重', is_visible TINYINT(1) DEFAULT 1 COMMENT '是否可见', permission_tag VARCHAR(50) COMMENT '权限标识', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_parent (parent_id), INDEX idx_sort (sort_order) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` **关键字段说明:** - `parent_id`:实现层级结构的基础字段,0表示顶级菜单 - `sort_order`:控制同级菜单的显示顺序 - `permission_tag`:关联权限系统的标识符(如`system:user:view`) - `is_visible`:动态控制菜单显示状态 #### 高级优化方案 1. **闭包表优化深层级查询** ```sql -- 路径关系表 CREATE TABLE menu_closure ( ancestor INT NOT NULL COMMENT '祖先节点', descendant INT NOT NULL COMMENT '后代节点', depth INT NOT NULL COMMENT '层级深度', PRIMARY KEY (ancestor, descendant), FOREIGN KEY (ancestor) REFERENCES sys_menu(menu_id), FOREIGN KEY (descendant) REFERENCES sys_menu(menu_id) ); ``` **优势**:解决邻接表递归查询性能问题,特别适合超过3层的深菜单树[^1] 2. **多语言支持设计** ```sql CREATE TABLE menu_i18n ( menu_id INT NOT NULL, lang_code CHAR(2) NOT NULL COMMENT '语言代码', display_name VARCHAR(100) NOT NULL COMMENT '本地化名称', PRIMARY KEY (menu_id, lang_code) ); ``` #### 设计原则 1. **层级控制**:建议不超过5级,超过3级时添加面包屑导航字段 2. **权限分离**:菜单表只存储权限标识,具体验证逻辑在业务层实现 3. **类型区分**:添加`menu_type`字段(如:0-菜单项,1-功能按钮) 4. **元数据扩展**:使用JSON字段存储动态配置(如:`extra_config JSON`) #### 查询示例 获取用户可见菜单树(MySQL 8.0+ 递归查询): ```sql WITH RECURSIVE menu_tree AS ( SELECT * FROM sys_menu WHERE parent_id = 0 AND is_visible = 1 UNION ALL SELECT m.* FROM sys_menu m INNER JOIN menu_tree mt ON m.parent_id = mt.menu_id WHERE m.is_visible = 1 ) SELECT * FROM menu_tree ORDER BY sort_order; ``` #### 性能优化建议 1. 为`parent_id`和`sort_order`创建组合索引 2. 高频访问系统添加菜单缓存层(Redis/Memcached) 3. 定期执行`OPTIMIZE TABLE`维护索引碎片 > 使用MySQL Workbench可视化设计时,可通过EER图建立表关系,并自动生成DDL脚本[^3]。实际部署前建议用工具(如pt-query-digest)进行压力测试。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值