96SEO 2026-02-20 05:13 37
noDB逻辑存储结构MyISAMMemory存储引擎选择索引索引结构二叉树B-TreeBTreeHash索引分类索引语法SQL性能分析工具SQL执行频率慢查询日志profile详情explain索引使用联合索引索引失效情况SQL提示覆盖索引前缀索引单列索引与联合索引索引设计原则SQL优化插入数据大批量数据插入主键优化order

by优化limit优化count优化update优化MySQL体系结构
最上层是一些客户端和链接服务主要完成一些类似于连接处理授权认证及相关的安全方案。
服务器也会为安全接入的每个客户验证它所具有的操作权限。
服务层
第二层架构主要完成大多数的核心服务功能如SQL接口并完成缓存的查询SQL的分析和优化部分内置函数的执行所有跨存储引擎的功能也在这层实现如过程函数等。
引擎层
存储引擎真正的负责了MySQL中数据的存储和提取服务器通过API和存储引擎进行通信。
不同的存储引擎具有不同的功能这样可以根据自己的需要来选取合适的存储引擎。
存储层
存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式
。
存储引擎是基于表的而不是基于库的所以存储引擎也可被称为表类型。
所以可以在创建表的时候来指定选择的存储引擎如果没有指定将自动选择默认的存储引擎。
xxx.ibdxxx代表的是表名innoDB引擎的每张表都会对应这样一个表空间文件存储该表的表结构frm-早期的
innodb_file_per_table;如果该参数开启代表对于InnoDB引擎的表每一张表都对应一个ibd文件。
直接打开MySQL的数据存放下有很多文件夹不同的文件夹代表不同的数据库直接打开itcast文件夹如下
account就有这样的一个account.ibd文件而在这个ibd文件中不仅存放表结构、数据还会存放该表对应的索引信息。
而该文件是基于二进制存储的不能直接基于记事本打开可以使用mysql提供的一个指令
通过该指令就可以从ibd文件中提取sdi信息而sdi数据字典信息中就包含该表的表结构。
InnoDB存储引擎逻辑结构的最高层ibd文件其实就是表空间文件在表空间中可以包含多个Segment段。
段
常见的段有数据段、索引段、回滚段等。
InnoDB中对于段的管理都是引擎自身完成不需要人为对其控制一个段中包含多个区。
区
存储引擎是面向行的也就是说数据是按行进行存放的在每一行中除了定义表时所指定的字段以外还包含两个隐藏字段(后面会详细介绍)。
Memory引擎的表数据时存储在内存中的由于受到硬件问题、或断电问题的影响只能将这些表作为临时表或缓存使用。
在选择存储引擎时应该根据应用系统的特点选择合适的存储引擎。
对于复杂的应用系统还可以根据实际情况选择多种存储引擎进行组合。
是Mysql的默认存储引擎支持事务、外键。
如果应用对事务的完整性有比较高的要求在并发条件下要求数据的一致性数据操作除了插入和查询之外还包含很多的更新、删除操作那么InnoDB存储引擎是比较合适的选择。
MyISAM
如果应用是以读操作和插入操作为主只有很少的更新和删除操作并且对事务的完整性、并发性要求不是很高那么选择这个存储引擎是非常合适的。
MEMORY
将所有数据保存在内存中访问速度快通常用于临时表及缓存。
MEMORY的缺陷就是对表的大小有限制太大的表无法缓存在内存中而且无法保障数据的安全性。
高效获取数据的有序数据结构。
在数据之外数据库系统还维护着满足特定查找算法的数据结构这些数据结构以某种方式引用指向原始数据
45;无索引情况就需要从第一行开始扫描一直扫描到最后一行我们称之为
有索引情况如果针对于这张表建立了索引假设索引结构就是二叉树那么也就意味着会对age这个字段建立一个二叉树的索引结构。
此时我们在进行查询时只需要扫描三次就可以找到数据了极大的提高的查询的效率。
提高数据检索的效率降低数据库的IO成本通过索引对数据进行排序降低数据排序的成本降低CPU的消耗
索引也要占用空间索引大大提高了查询效率同时也降低了更新表的速度如对表进行INSERT,UPDATE,DELETE时效率降低
MySQL的索引是在存储引擎层实现的不同的存储引擎有不同的索引结构主要包含以下几种
假如说MySQL的索引结构采用二叉树(一个节点下面最多包含两个节点)的数据结构比较理想的结构如下
如果主键是顺序插入的则会形成一个单向链表结构如下查找17时相当于把整张链表遍历一次
顺序插入时会形成一个链表查询性能大大降低。
因为一个节点下最多只能包含两个子节点大数据量情况下层级较深检索速度慢。
如果选择红黑树红黑树是一颗自平衡二叉树即使顺序插入数据最终形成的数据结构也是一颗平衡的二叉树,结构如下:
B-Tree是一种多路平衡查找树相对于二叉树B树每个节点可以有多个分支即多叉。
以一颗最大度数max-degree为5(5阶)的b-tree为例(即B树每个节点最多存储4个key5个指针)
https://www.cs.usfca.edu/~galles/visualization/BTree.html
5阶的B树每一个节点最多存储4个key对应5个指针。
一旦节点存储的key数量到达5就会裂变中间元素向上分裂。
在B树中非叶子节点和叶子节点都会存放数据。
BTree是B-Tree的变种以一颗最大度数max-degree为44阶3个key4个指针的btree为例其结构示意图
绿色框框起来的部分是索引部分仅仅起到索引数据的作用不存储数据。
红色框框起来的部分是数据存储部分在其叶子节点中要存储具体的数据。
所有的数据都会出现在叶子节点。
叶子节点形成一个单向链表。
非叶子节点仅仅起到索引数据作用具体的数据都是在叶子节点存放的。
通过数据结构可视化的网站来简单演示一下https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html
MySQL索引数据结构对经典的BTree进行了优化。
在原BTree的基础上增加一个指向相邻叶子节点的链表指针就形成了带有顺序指针的BTree提高区间访问的性能利于排序。
哈希索引就是采用一定的hash算法将键值换算成新的hash值映射到对应的槽位上然后存储在hash表中。
如果两个(或多个)键值映射到一个相同的槽位上他们就产生了hash冲突也称为hash碰撞可以通过链表来解决。
Hash索引只能用于对等比较(in)不支持范围查询between
…无法利用索引完成排序操作查询效率高通常(不存在hash冲突的情况)只需要一次检索就可以了效率通常要高于Btree索引
而InnoDB中具有自适应hash功能hash索引是InnoDB存储引擎根据BTree索引在指定条件下自动构建的。
相对于二叉树层级更少搜索效率高对于B-tree无论是叶子节点还是非叶子节点都会保存数据这样导致一页中存储的键值减少指针跟着减少要同样保存大量数据只能增加树的高度导致性能降低相对Hash索引Btree支持范围匹配及排序操作
在MySQL数据库将索引的具体类型主要分为以下几类主键索引、唯一索引、常规索引、全文索引。
如果存在主键主键索引就是聚集索引如果不存在主键将使用第一个唯一UNIQUE索引作为聚集索引。
如果表没有主键或没有合适的唯一索引则InnoDB会自动生成一个rowid作为隐藏的聚集索引。
由于是根据name字段进行查询所以先根据name字段的二级索引中进行匹配查找。
Lee—Geek—Arm在二级索引中只能查找到
10。
由于查询返回的数据是*(所有返回字段)所以还需要根据主键值10到聚集索引中查找10对应的记录15—10最终找到10对应的行row。
最终拿到这一行的数据直接返回即可。
先到二级索引中查找数据找到主键值再到聚集索引中根据主键值这种获取数据的方式就称之为回表查询。
而B语句需要先查询name字段的二级索引然后再查询聚集索引也就是需要进行回表查询。
假设:一行数据大小为1k一页中可以存储16行这样的数据。
InnoDB的指针占用6个字节的空间主键即使为bigint占用字节数为8。
InnoDB存储引擎最小储存单元是页一页大小就是16k。
B树叶子存的是数据内部节点存的是键值指针。
索引组织表通过非叶子节点的二分查找法以及指针确定数据在哪个页中进而再去数据页中找到需要的数据
如果B树的高度为2的话即有一个根结点和若干个叶子结点。
这棵B树的存放总记录数为根结点指针数*单个叶子节点记录行数
非叶子节点内存放多少指针呢假设主键ID为bigint类型长度为8字节(int类型的话一个int就是32位4字节)而指针大小是固定的在InnoDB源码中设置为6字节假设n指主键个数即key的个数n*8
1170,意味着根节点会有1170个key与1171个指针、因此一棵高度为2的B树能存放1171*
18736条这样的数据记录。
同理一棵高度为3的B树能存放1171
21939856也就是说可以存放两千万左右的记录。
B树高度一般为1-3层已经满足千万级别的数据存储。
索引语法
00:00:00);name字段为姓名字段该字段的值可能会重复(不能创建唯一索引只能创建常规索引)为该字段创建索引。
tb_user(name);phone手机号字段的值是非空且唯一的为该字段创建唯一索引。
tb_user(phone);为profession、age、status创建联合索引。
tb_user(profession,age,status);为email建立合适的索引来提升查询效率。
tb_user(email);查看tb_user表的所有的索引数据
命令可以提供服务器状态信息。
通过如下指令可以查看当前数据库的INSERT、UPDATE、DELETE、SELECT的访问频次
慢查询日志记录了所有执行时间超过指定参数long_query_time单位秒默认10秒的所有SQL语句的日志。
要开启慢查询日志需要在MySQL的配置文件/etc/my.cnf中配置如下信息
设置慢日志的时间为2秒SQL语句执行时间超过2秒就会视为慢查询记录慢查询日志
long_query_time2配置完毕之后重新启动MySQL服务器进行测试查看慢日志文件中记录的信息/var/lib/mysql/localhost-slow.log。
count一次,耗时13.35sec在慢查询日志中只会记录执行时间超多我们预设时间2s的SQL执行较快的SQL是不会记录的。
通过慢查询日志就可以定位出执行效率比较低的SQL从而有针对性的进行优化。
通过have_profiling参数查看当前MySQL是否支持profile操作。
profile操作的默认开关0是关闭的。
可以通过set语句在session/global级别开启profiling
1;开关打开之后所执行的SQL语句都会被MySQL记录并记录执行时间消耗到哪儿去了执行如下的SQL语句
tb_sku;执行一系列的业务SQL的操作然后通过如下指令查看指令的执行耗时
c.idsc.courseid;表执行顺序studentcoursestudent_course
如果索引了多列联合索引要遵守最左前缀法则。
最左前缀法则指的是查询从索引的最左列开始并且不跳过索引中的列。
如果跳跃某一列索引将会部分失效(后面的字段索引失效)。
联合索引涉及到三个字段顺序分别为professionagestatus
最左前缀法则指的是查询时最左变的列即profession必须存在否则索引全部失效。
而且中间不能跳过某一列否则该列后面的字段索引将失效。
如果字符串不加单引号对于查询结果没什么影响但是数据库存在隐式类型转换索引将失效。
0;模糊查询在like模糊查询中在关键字后面加%索引可以生效。
而如果在关键字前面加了%索引将会失效。
%工%;or连接条件如果or条件一侧有索引一侧没有索引涉及到的索引都不会被用到。
由于age没有索引所以即使id、phone有索引索引也会失效。
所以需要针对于age也要建立索引。
23;对age字段建立索引当or连接的条件左右两侧字段都有索引时索引才会生效。
tb_user(age);数据分布影响如果MySQL评估使用索引比全表更慢则不使用索引。
17799990020;MySQL在查询时会评估使用索引的效率与走全表扫描的效率如果走全表扫描更快则放弃索引走全表扫描。
因为索引是用来索引少量数据的如果通过索引查询返回大批量的数据则还不如走全表扫描来的快此时索引就会失效。
一模一样的SQL语句先后执行了两次结果查询计划是不一样的为什么会出现这种现象这是和数据库的数据分布有关系。
查询时MySQL会评估走索引快还是全表扫描快如果全表扫描更快则放弃索引走全表扫描。
SQL提示是优化数据库的一个重要手段简单来说就是在SQL语句中加入一些人为的提示来达到优化操作的目的。
前提字段profession有一个单例索引idx_user_pro一个联合索引idx_user_pro_age_sta
建议MySQL使用哪一个索引完成此次查询仅仅是建议mysql内部还会再次进行评估。
覆盖索引是指查询使用了索引并且需要返回的列在该索引中已经全部能够找到
idx_user_pro_age_sta该索引关联了三个字段profession、age、status而这个索引也是一个二级索引所以叶子节点下面挂的是这一行的主键id。
如果超出这个范围就需要拿到主键id再去扫描聚集索引再获取额外的数据了这个过程就是回表。
查询返回所有字段值很容易就会造成回表查询除非是根据主键查询此时只会扫描聚集索引。
tb_user(username,password);可以避免上述SQL语句在查询的过程中出现回表查询。
当字段类型为字符串varchartextlongtext等时有时候需要索引很长的字符串这会让索引变得很大查询时浪费大量的磁盘IO
影响查询效率。
此时可以只将字符串的一部分前缀建立索引这样可以大大节约索引空间从而提高索引效率。
可以根据索引的选择性来决定选择性是指不重复的索引值基数和数据表的记录总数的比值索引选择性越高则查询效率越高
;示例为tb_user表的email字段建立长度为5的前缀索引。
由于是根据email字段进行查询所以先根据email字段的二级索引中进行匹配查找。
daqia—lvbu6,在二级索引中只能查找到
1。
由于查询返回的数据是*(所有返回字段)所以还需要根据主键值1到聚集索引中查找1对应的记录7—3—1最终找到1对应的行row。
最终拿到这一行的数据对比email的值是不是传递的值是查询并返回之后再查询当前下一个节点的元素。
phone、name上都是有单列索引的但是最终mysql只会选择一个索引也就是说只能走一个字段的索引此时是会回表查询的。
tb_user(phone,name);在业务场景中如果存在多个查询条件考虑针对于查询字段建立索引时建议建立联合索引而非单列索引。
多条件联合查询时MySQL优化器会评估哪个字段的索引效率更高会选择该索引完成本次查询。
针对于数据量较大且查询比较频繁的表建立索引。
针对于常作为查询条件where、排序order
by操作的字段建立索引。
尽量选择区分度高的列作为索引尽量建立唯一索引区分度越高使用索引的效率越高。
(性别区分度不大)如果是字符串类型的字段字段的长度较长可以针对于字段的特点建立前缀索引。
尽量使用联合索引减少单列索引查询时联合索引很多时候可以覆盖索引节省存储空间避免回表提高查询效率。
要控制索引的数量索引并不是多多益善索引越多维护索引结构的代价也就越大会影响增删改的效率。
values(1,Tom),(2,Cat),(3,Jerry);优化方案二手动控制事务(默认一条insert语句自动提交数据)
values(1,Tom),(2,Cat),(3,Jerry);
values(4,Tom),(5,Cat),(6,Jerry);
values(7,Tom),(8,Cat),(9,Jerry);
几百万的记录)使用insert语句插入性能较低可以使用MySQL数据库提供的load指令进行插入。
操作如下
设置全局参数local_infile为1开启从本地加载文件导入数据的开关
执行load指令将准备好的数据加载到表结构中每个数据用,分割每一行数据用/n分割
数据组织方式在InnoDB存储引擎中表数据都是根据主键顺序组织存放的这种存储方式的表称为索引组织表(index
行数据都是存储在聚集索引的叶子节点上的。
在InnoDB引擎中数据行是记录在逻辑结构
一个页中所存储的行也是有限的如果插入的数据行row在该页存储不小将会存储到下一个页中页与页之间会通过指针连接。
页可以为空也可以填充一半也可以填充100%。
每个页包含了2-N行数据(如果一行数据过大会行溢出)根据主键排列。
第一个页没有满继续往第一页插入当第一个也写满之后再写入第二个页页与页之间会通过指针连接当第二页写满了再往第三页写入。
加入1#,2#页都已经写满了存放了如图所示的数据此时再插入id为50的记录因为索引结构的叶子节点是有顺序的。
按照顺序应该存储在47之后。
3#。
将1#页后一半的数据移动到3#页然后在3#页插入50。
此时这三个页之间的数据顺序是有问题的
当删除一行记录时实际上记录并没有被物理删除只是记录被标记flaged为删除并且它的空间变得允许被其他记录声明使用。
MERGE_THRESHOLD默认为页的50%InnoDB会开始寻找最靠近的页前
MERGE_THRESHOLD合并页的阈值可以自己设置在创建表或者创建索引时指定。
满足业务需求的情况下尽量降低主键的长度。
(二级索引占用空间大)插入数据时尽量选择顺序插入选择使用AUTO_INCREMENT自增主键尽量不要使用UUID做主键或者是其他自然主键如身份证号。
业务操作时避免对主键的修改。
通过表的索引或全表扫描读取满足条件的数据行然后在排序缓冲区sort
buffer中完成排序操作所有不是通过索引直接返回排序结果的排序都叫
scan这个代表反向扫描索引因为在MySQL中我们创建的索引默认索引的叶子节点是从小到大排序的而此时我们查询排序时是从大到小所以在扫描时就是反向扫描就会出现
在索引之外需要额外进行外部的排序动作根据phoneage进行升序排序phone在前age在后违背了最左匹配法则索引失效
在索引之外需要额外进行外部的排序动作因为创建索引时如果未指定顺序默认都是按照升序排序的而查询时一个升序一个降序此时就会出现Using
使用了索引如果根据age和phone创建了联合索引默认都是升序当age和phone升序排序age单字段升序age和phone降序排序都会走联合索引。
其他情况会索引失效。
一个升序一个降序的情况需要重新建立索引。
根据排序字段建立合适的索引多字段排序时也遵循最左前缀法则。
尽量使用覆盖索引不用再回表查询避免索引排序失效。
多字段排序,
一个升序一个降序此时需要注意联合索引在创建时的规则ASC/DESC。
如果不可避免的出现filesort大数据量排序时可以适当增大排序缓冲区大小sort_buffer_size(默认256k)超过磁盘缓冲区大小会在磁盘排序性能低。
表的索引全部删除掉在没有索引的情况下执行如下SQL查询执行计划
在分组操作时可以通过索引来提高效率。
分组操作时索引的使用也是满足最左前缀法则的。
在数据量比较大时如果进行limit分页查询在查询时越往后分页查询效率越低。
如果要大幅度提升InnoDB表的count效率主要的优化思路自己计数(可以借助于redis这样的数据库进行,但是如果是带条件的count又比较麻烦)。
count主键InnoDB引擎会遍历整张表把每一行的主键id值都取出来返回给服务层。
服务层拿到主键后直接按行进行累加(主键不可能为null)。
count字段
null约束InnoDB引擎会遍历整张表把每一行的字段值都取出来返回给服务层判断是否为null不为null计数累加。
有not
null约束InnoDB引擎会遍历整张表把每一行的字段值都取出来返回给服务层直接按行进行累加。
count数字InnoDB引擎遍历整张表但不取值服务层对于返回的每一行放一个数字“1”进去直接按行进行累加count*InnoDB引擎并不会把全部字段取出来而是专门做了优化不取值服务层直接按行进行累加。
;在执行更新的SQL语句时会锁定id为1这一行的数据然后事务提交之后行锁释放
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback