WinddSnow

MySQL优化

字数统计: 7.6k阅读时长: 27 min
2022/10/19

先言

  • 不要听信你看到的关于优化的“绝对真理”,而应该是在实际的业务场景下通过测试来验证你关于执行计划以及响应时间的假设。
  • 具体业务场景的不同,使用的MySQL服务版本不同,都会使得优化方案的制定也不同。
  • 数据库任何操作都需要慎之又慎,即使所谓优化,也需要尽可能组织涉及到的所有业务部门具体商议,非常有可能,对你的业务来说是优化,却会影响他人业务!
  • 切记,你需要清楚的知道,你的操作所带来的一切结果,测试环境不等于生产环境,风险操作,备份先行。
  • 优化有风险,涉足需谨慎!

优化可能带来的问题

  • 优化不总是对一个单纯的环境进行,还很可能是一个复杂的已投产的系统!
  • 优化手段有很大的风险,一定要意识到和预见到!
  • 任何的技术可以解决一个问题,但必然存在带来一个问题的风险!
  • 对于优化来说调优而带来的问题, 控制在可接受的范围内才是有成果。
  • 保持现状或出现更差的情况都是失败!

优化的需求

  • 稳定性和业务可持续性,通常比性能更重要!
  • 优化不可避免涉及到变更,变更就有风险!
  • 优化使性能变好,维持和变差是等概率事件!
  • 优化应该是各部门协同,共同参与的工作,任何单一部门都不能对数据库进行优化!
  • 所以优化工作,是由业务需要驱使的!!!

优化由谁参与

  • 在进行数据库优化时,应由数据库管理员、业务部门代表、应用程序架构师、应用程序设计人员、应用程序开发人员、硬件及系统管理员、存储管理员等,业务相关人员共同参与。

优化的思路

应急调优

针对突然的业务办理卡顿,无法进行正常的业务处理!需要立马解决的场景!

  1. show processlist(查看连接session状态)
  2. explain(分析查询计划),show index from tableName(分析索引)
  3. 通过执行计划判断,索引问题(有没有、合不合理)或者语句本身问题
  4. show status like ‘%lock%’; # 查询锁状态
  5. kill sessionId; # 杀掉有问题的session

常规调优

针对业务周期性的卡顿,例如在每天10-11点业务特别慢,但是还能够使用,过了这段时间就好了。

  1. 查看slowlog,分析slowlog,分析出查询慢的语句。
  2. 按照一定优先级,进行一个一个的排查所有慢语句。
  3. 分析top sql,进行explain调试,查看语句执行时间。
  4. 调整索引或语句本身。

具体优化

mysql查询流程

  1. 客户端将查询发送到服务器;
  2. 服务器检查查询缓存,如果找到了,就从缓存中返回结果,否则进行下一步。—
  3. 服务器解析,预处理。
  4. 查询优化器优化查询
  5. 生成执行计划,执行引擎调用存储引擎API执行查询
  6. 服务器将结果发送回客户端。

查询缓存
在解析一个查询语句之前,如果查询缓存是打开的,那么MySQL会优先检查这个查询是否命中查询缓存中的数据,如果命中缓存直接从缓存中拿到结果并返回给客户端。这种情况下,查询不会被解析,不用生成执行计划,不会被执行。
语法解析和预处理器
MySQL通过关键字将SQL语句进行解析,并生成一棵对应的“解析树”。MySQL解析器将使用MySQL语法规则验证和解析查询。
查询优化器
语法书被校验合法后由优化器转成查询计划,一条语句可以有很多种执行方式,最后返回相同的结果。优化器的作用就是找到这其中最好的执行计划。
查询执行引擎
在解析和优化阶段,MySQL将生成查询对应的执行计划,MySQL的查询执行引擎则根据这个执行计划来完成整个查询。最常使用的也是比较最多的引擎是MyISAM引擎和InnoDB引擎。mysql5.5开始的默认存储引擎已经变更为innodb了。

查询SQL分析

1. 慢查询日志

在配置文件my.cnf[linux]或my.ini[windows Server2008]中在[mysqld]一行下面加入两个配置参数

1
2
3
4
log-slow-queries=C:/ProgramData/MySQL/MySQL Server 5.5/Data/mysqldata/slow-query.log

超过多少秒就是慢查询
long_query_time=5
1
2
SHOW VARIABLES LIKE 'long_query_time%';   -- 查看当前多少秒算慢
show global status like '%Slow_queries%'; --查询当前系统中有多少条慢查询记录

进入log的存放目录,运行:

1
2
3
4
[root@mysql_data]# mysqldumpslow slow-query.log
Reading mysql slow query log fromslow-query.log
Count: 2 Time=11.00s (22s) Lock=0.00s (0s)Rows=1.0 (2), root[root]@mysql
select count(N) from t_user;

mysqldumpslow命令
/path/mysqldumpslow -s c -t 10/database/mysql/slow-query.log
这会输出记录次数最多的10条SQL语句,其中:
-s, 是表示按照何种方式排序,c、t、l、r分别是按照记录次数、时间、查询时间、返回的记录数来排序,ac、at、al、ar,表示相应的倒叙
-t, 是top n的意思,即为返回前面多少条的数据;
-g, 后边可以写一个正则匹配模式,大小写不敏感的;

例如:

/path/mysqldumpslow -s r -t 10/database/mysql/slow-log

得到返回记录集最多的10个查询。

/path/mysqldumpslow -s t -t 10 -g “leftjoin” /database/mysql/slow-log

得到按照时间排序的前10条里面含有左连接的查询语句。

使用mysqldumpslow命令可以非常明确的得到各种我们需要的查询语句,对MySQL查询语句的监控、分析、优化是MySQL优化非常重要的一步。开启慢查询日志后,由于日志记录操作,在一定程度上会占用CPU资源影响mysql的性能,但是可以阶段性开启来定位性能瓶颈。

2. EXPLAIN 分析查询

EXPLAIN可以帮助开发人员分析SQL问题,EXPLAIN显示了MySQL如何使用使用SQL执行计划,可以帮助开发人员写出更优化的查询语句。使用方法,在select语句前加上Explain就可以了:
EXPLAIN SELECT * FROM products

exolan结果的列的说明

1. id

SELECT识别符。这是SELECT查询序列号。这个不重要。它只是标识执行的sql语句中有多个查询而已

2. select_type

表示SELECT语句的类型。

  1. simple:简单select(不使用union或子查询)。
  2. primary:最外面的select。
  3. union:union中的第二个或后面的select语句。
  4. dependent union:union中的第二个或后面的select语句,取决于外面的查询。
  5. union result:union的结果。
  6. subquery:子查询中的第一个select。
  7. dependent subquery:子查询中的第一个select,取决于外面的查询。
  8. derived:导出表的select(from子句的子查询)。
3. table

显示这查询的数据是关于哪张表的。

4. type【重要

区分索引,这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为:
system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref,到index就可以。

  1. system:表仅有一行,这是const类型的特列,平时不会出现,这个也可以忽略不计。
  2. const:数据表最多只有一个匹配行,因为只匹配一行数据,所以很快
  3. eq_ref:mysql手册是这样说的:”对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY”。eq_ref可以用于使用=做条件比较,且该列是索引的列。
  4. ref:查询条件索引既不是UNIQUE也不是PRIMARY KEY的情况。ref可用于=或<或>操作符的带索引的列。
  5. ref_or_null:该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。
  6. index_merge:该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。
  7. unique_subquery:该类型替换了下面形式的IN子查询的ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。
  8. index_subquery:该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)
  9. range:只检索给定范围的行,使用一个索引来选择行。
  10. index:该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。
  11. ALL:对于每个来自于先前的表的行组合,进行完整的表扫描。(性能最差,去除all,最少要有index)
5. possible_keys

指出MySQL能使用哪个索引在该表中找到行。如果是空的,没有相关的索引。这时要提高性能,可通过检验WHERE子句,看是否引用某些字段,或者检索字段不是适合索引。

6. key

实际使用到的索引。如果为NULL,则没有使用索引。如果为primary的话,表示使用了主键。

7. key_len

最长的索引宽度。如果键是NULL,长度就是NULL。在不损失精确性的情况下,长度越短越好。

8. ref

显示使用哪个列或常数与key一起从表中选择行。

9. rows

显示MySQL认为它执行查询时必须检查的行数。行数越少效率越高(是否有索引)

10. Extra

执行状态说明,该列包含MySQL解决查询的详细信息,这个列的值有可能多个以下的情况

  • Distinct: MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。
  • Not exists: MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
  • range checked for each record (index map: #): MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。
  • 【Using filesort】: MySQL需要额外的一次传递,以找出如何按排序顺序检索行。排序上,出现这个意为着排序时需要读取真实数据记录【读取数据文件IO】
  • Using index: 从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。
  • 【Using temporary】:为了解决复杂查询,MySQL需要创建一个临时表来容纳结果,效率较低。
  • Using where:WHERE 子句用于限制哪一个行匹配下一个表或发送到客户。
  • Using sort_union(…), Using union(…), Using intersect(…):这些函数说明如何为index_merge联接类型合并索引扫描。
  • Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查 询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际表中的数据。

索引优化

什么是索引

  • 索引(Index)是帮助MySQL高效获取数据的数据结构。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构上实现高效的查找算法.这种数据结构,就是索引.
  • 一般来说索引本身也很大,不可能全部存储在内存中,因此往往以索引文件的形式存放在磁盘中. 我们平常所说的索引,如果没有特别说明都是指BTree索引(平衡多路搜索树). 其中聚集索引,次要索引,覆盖索引 复合索引,前缀索引,唯一索引默认都是使用的BTree索引,统称索引. 除了BTree索引之后,还有哈希索引
  • 索引的优点:大大的提高查询效率
  • 缺点:占用内存(是一种数据结构需要存储),影响写操作的效率(调整索引结构)

索引的类别

  1. 普通索引–是最基本的索引,它没有任何限制.
  2. 唯一索引–与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合(索引的列有多个)索引,则列值的组合必须唯一。
  3. 主键索引–是一种特殊的唯一索引,这个时候需要一个表只能有一个主键,不允许有空值。一般是在建表的时候同时创建主键索引.也就是说主键约束默认索引
  4. 复合索引 【使用时推荐】–指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合(使用复合索引,必须使用索引列中的第一列做为条件,复合索引中的第一个列为最左列,优先列。最左匹配优先)
  5. 全文索引–类似ES倒排索引,不常用,主要用来查找文本中的关键字,而不是直接与索引中的值相比较。

索引的存储结构

BTree索引

  • BTREE索引以B+树的结构存储数据
  • BTREE索引能够加快数据的查询速度
  • BTREE索引更适合进行行范围查找

哈希索引(主要是Memory存储引擎使用)

特点: map.get(key)

  • Hash索引仅仅只能满足“=”,“IN”,不能使用范围查询;
  • Hash索引无法被利用来避免数据的排序操作;
  • Hash索引不能利用部分索引键查询;
  • Hash索引在任何时候都不能避免表扫描;
  • Hash索引遇到大量Hash值相等的情况后性能并不一定就会比B-Tree索引高;

优化建议

  • 保证被驱动表(left join右边的表(临时结果集要放到左边))的join字段已经被索引 (被驱动表 join 后的表为被驱动表 (需要被查询))
  • left join 时,选择小表作为驱动主表(left左边的表),大表作为被驱动表。left join 右边的表要建立索引 索引的列就是on中右边表的列
  • inner join 时,mysql会自己帮你把小结果集的表选为驱动表

子查询优化

子查询类型:

  1. 返回单行单列:使用逻辑运行符 =, !=, > <=…
  2. 返回单列多行: 使用in
  3. 返回单行多列: from后做为子查询 临时表
  4. 返回多行多列:from后做为子查询 临时表
  • 子查询尽量不要放在被驱动表 关联查询的右边,有可能使用不到索引。
  • 子查询的语句不能放在select的后面(如果子查询放在select后,则会每提取一条记录执行一次子查询),改为放到from后
  • 子查询应该优先过滤大量的数据先,再进行关联查询. 能够过滤大量数据的子查询放最里边

order by优化

  • ORDER BY 语句使用索引最左前列
  • 使用Where子句与Order BY子句条件列组合满足索引最左前列
  • where子句中如果出现索引的范围查询(即explain中出现range)会==导致order by 索引失效==
  • Order by 复合条件排序, 按照索引顺序, 前后的排序类别不一致,会导致order by 索引失效
  • 如果使用了复合索引:条件列为最左优先列,排序的第一个列必须为最左优先列右边的第一个列。排序的顺序与创建索引时的顺序一致,与最左优先列一致

GROUP BY优化

  • group by实质是先排序后进行分组,遵照索引建的最佳左前缀(优先列-复合索引中的第一列)
  • where高于having,能写在where限定的条件就不要去having限定了

limit优化

  • 分页时传递排序列的最后一个值
  • 最多显示100页
  • 步骤一: 使用有索引的列或者主键进行Order By操作
  • 步骤二: 记录上次返回的主键,在下次查询的时候使用条件过滤(如果主键不是连续的,是字符串类型,可以创建一个列记录) 依据不一定是id, 可以是条件列或排序列

索引的使用场景分析

适合使用索引场景

  1. 频繁作为查询条件的字段应该创建索引(复合索引时,查询条件要用到优先列,排序时最少要用到优先列相邻列,不能跳过列)
  2. 多表查询中与其它表进行关联的字段,外键关系建立索引(不要创建主外健)
  3. 单列索引/复合索引的选择,高并发下倾向于创建复合索引(是单列还是多列取决于查询的条件排序、查询的列)
  4. 查询中经常用来排序的字段(索引排序不需要读取数据 不会有filesort)
  5. 查询中经常用来统计或者分组字段
  6. 数据库中表数据量一定要大,数据多

不适合使用索引场景

  1. 频繁更新的字段: 每次更新都会影响索引树
  2. where条件查询中用不到的字段, 不做为查询条件的
  3. 表记录太少
  4. 经常增删改的表: 更新了表,索引也得更新才行
  5. 注意: 如果一张表中,列中重复的值过多,为它建立索引就没有太大意义
  6. 列中的null值过多,也不适合创建索引

索引失效情况

  • 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
    如果是数值类型的列,运算时使用了字符串 id(bigint) ‘10’
  • 存储引擎不能使用索引中范围条件右边的列(没有使用优先列)
  • mysql 在使用不等于(!= 或者<>)的时候无法使用索引会导致全表扫描【验证一把,5.5 - 5.7的是可以使用索引】
  • is not null 也无法使用索引(待验证),但是is null是可以使用索引的
  • like以通配符开头(‘%abc…’)mysql索引失效会变成全表扫描的操作
  • 字符串不加单引号索引失效
  • 少用or,用它来连接时会索引失效(只针对mysql)
  • not in操作也会使索引失效 有可能失败 验证mysql8

索引失效情况个人总结

  1. SQL语法,数据库版本问题,如字符串不加单引号, like以通配符开头等,根据不同数据库有所不同,总结就是sql语法问题,会导致索引失效
  2. 不遵循最左匹配原则导致索引失效
  3. sql分析器分析后,发现扫描全表比使用索引快,会导致索引失效
  4. 使用索引时,查询出的结果太大,官方文档说大概全表的30%左右(有争议,大概数,MySQL有优化),总之就是结果太大,会放弃索引,执行全表扫描
  5. 在索引列上做聚合操作,会导致索引失效

InnoDB存储引擎介绍

  1. InnoDB存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。相比较MyISAM存储引擎,InnoDB写的处理效率差一点并且会占用更多的磁盘空间保留数据和索引。
  2. 提供了对数据库事务ACID(原子性Atomicity、一致性Consistency、隔离性Isolation、持久性Durability)的支持,实现了SQL标准的四种隔离级别。设计目标就是处理大容量的数据库系统,MySQL运行时InnoDB会在内存中建立缓冲池,用于缓冲数据和索引。
  3. 执行select count(*) from table使用innodb引擎的表不会保存表的具体行数,扫描索引即可。MyIsAm有专门存储行数的地方,无需提交无需计算,直接读取
  4. InnoDB引擎是行锁(锁的是索引),粒度更小。插入与删除时不会锁定全表,更新时,如果where条件没有使用索引时,锁的表锁。MyIsAm锁级别要表锁。
  5. InnoDB清空数据量大的表时,是非常缓慢,这是因为InnoDB必须处理表中的每一行,根据InnoDB的事务设计原则,首先需要把“删除动作”写入“事务日志”,然后写入实际的表。所以,清空大表的时候,最好直接truncate table然后重建。即InnoDB一行一行删除(产生磁盘碎片),不会重建表。
  6. 使用truncate table时要注意:如果有视图使用了这个表,则会导致视图或失效,对视图重新编译 (视图的作用:屏蔽敏感字段、权限控制)

InnoDB存储引擎支持事务的底层原理

MVVC

全称 Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,快照读为MySQL实现MVCC提供了一个非阻塞读功能。MVCC的具体实现,还需要依赖于数据库记录中的三个隐式字段、undo log日志、readView。

隐藏字段
隐藏字段 含义
DB_TRX_ID 最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID。
DB_ROLL_PTR 回滚指针,指向这条记录的上一个版本,用于配合undo log,指向上一个版本。
DB_ROW_ID 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。
undo log日志

回滚日志,在insert、update、delete的时候产生的便于数据回滚的日志。
当insert的时候,产生的undo log日志只在回滚时需要,在事务提交后,可被立即删除。
而update、delete的时候,产生的undo log日志不仅在回滚时需要,在快照读时也需要,不会立即被删除。

版本链
  • 不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
readView

ReadView(读视图)是 快照读 SQL执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。

ReadView中包含了四个核心字段:
字段 含义
m_ids 当前活跃的事务ID集合
min_trx_id 最小活跃事务ID
max_trx_id 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的)
creator_trx_id ReadView创建者的事务ID
而在readview中就规定了版本链数据的访问规则:

trx_id 代表当前undolog版本链对应事务ID。

条件 是否可以访问 说明
trx_id == creator_trx_id 可以访问该版本 成立,说明数据是当前这个事务更改的。
trx_id < min_trx_id 可以访问该版本 成立,说明数据已经提交了。
trx_id > max_trx_id 不可以访问该版本 成立,说明该事务是在ReadView生成后才开启。
min_trx_id <= trx_id <= max_trx_id 如果trx_id不在m_ids中,是可以访问该版本的 成立,说明数据已经提交。
不同的隔离级别,生成ReadView的时机不同:
  • READ COMMITTED :在事务中每一次执行快照读时生成ReadView。
  • REPEATABLE READ:仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView。

存储优化

禁用索引

对于使用索引的表,插入记录时,MySQL会对插入的记录建立索引。如果插入大量数据,建立索引会降低插入数据速度。为了解决这个问题,可以在批量插入数据之前禁用索引,数据插入完成后再开启索引。

禁用索引的语句:
ALTER TABLE table_name DISABLE KEYS
开启索引语句:
ALTER TABLE table_name ENABLE KEYS

MyISAM对于空表批量插入数据,则不需要进行操作,因为MyISAM引擎的表是在导入数据后才建立索引。

禁用唯一性检查

唯一性校验会降低插入记录的速度,可以在插入记录之前禁用唯一性检查,插入数据完成后再开启。
禁用唯一性检查的语句:SET UNIQUE_CHECKS = 0;
开启唯一性检查的语句:SET UNIQUE_CHECKS = 1;

禁用外键检查

插入数据之前执行禁止对外键的检查,数据插入完成后再恢复,可以提供插入速度。

禁用:SET foreign_key_checks = 0;
开启:SET foreign_key_checks = 1;

批量插入数据

插入数据时,可以使用一条INSERT语句插入一条数据,也可以插入多条数据。

1
2
3
4
# 通过查询语句的返回列的结构创建表,表复制
create table tb_table2 as select * from tb_table where 1=2;
# 批量插入
insert into tb_table2 select * From tb_table

禁止自动提交

插入数据之前执行禁止事务的自动提交,数据插入完成后再恢复,可以提高插入速度。

禁用:SET autocommit = 0;
开启:SET autocommit = 1;

MyISAM和Innodb区别

  • InnoDB和MyISAM是许多人在使用MySQL时最常用的两个存储引擎,这两个存储引擎各有优劣,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理,而InnoDB类型支持。MyISAM类型强调的是性能,其执行速度比InnoDB类型更快,而InnoDB提供事务支持已经外部键等高级数据库功能。

具体实现的差别

  • MyISAM是非事务安全型的,而InnoDB是事务安全型的。
  • MyISAM锁的粒度是表级,而InnoDB支持行级锁定。
  • MyISAM不支持外键,而InnoDB支持外键
  • MyISAM相对简单,所以在查询效率上要优于InnoDB,小型应用可以考虑使用MyISAM。
  • InnoDB表比MyISAM表更安全(数据)。

数据库结构优化

优化表结构

  • 尽量将表字段定义为NOT NULL(即使可以为空,补空字符串),这是由于在MySQL中含有空值的列很难进行查询优化,NULL值会使索引以及索引的统计信息变得很复杂。
  • 对于只包含特定类型的字段,可以使用tinyint(1)。 0-9
  • 数值型字段的比较运算,比字符串的比较运算效率高得多,字段类型尽量使用最小粒度的类型、最简单的数据类型。例如IP地址可以使用int类型。
  • 尽量使用TINYINT、SMALLINT、MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNED。但对整数类型指定宽度,比如INT(11),没有任何用,因为指定的类型标识范围已经确定。
  • VARCHAR的长度只分配真正需要的空间
  • 尽量使用TIMESTAMP而非DATETIME,比DATETIME表示的范围小得多,而且TIMESTAMP的值因时区不同而不同。(跨国的数据库,纬度差较大的,使用0时区存储)
  • 单表不要有太多字段,建议在20个字段以内
  • 合理的加入冗余字段可以提高查询速度。三大范式
  • 列名不要过长,控制20个字符以内,不要中文字段名
  • 列的类型尽量不要使用大数据类型(blob,clob…) 字节数组, 存相对路径
  • 尽量不要创建外键

表拆分

垂直拆分

  • 垂直拆分按照字段进行拆分,其实就是把组成一行的多个列分开放到不同的表中,这些表具有不同的结构,拆分后的表具有更少的列。例如用户表中的一些字段可能经常访问,可以把这些字段放进一张表里。另外一些不经常使用的信息就可以放进另外一张表里。
  • 插入的时候使用事务,也可以保证两表的数据一致。缺点也很明显,由于拆分出来的两张表存在一对一的关系,需要使用冗余字段,而且需要join操作。但是我们可以在使用的时候可以分别取两次,这样的来说既可以避免join操作,又可以提高效率。
  • 查询单表时,效率大大提升

水平拆分 (查询条件,取hash, 如果是日期 每月/周/季/年)

  • 水平拆分按照行进行拆分,常见的就是分库分表。以用户表为例,可以取用户ID,然后对ID取10的余数,将用户均匀的分配进这 0-9这10个表中。查找的时候也按照这种规则,又快又方便。
  • 有些表业务关联比较强,那么可以使用按时间划分的。例如每天的数据量很大,需要每天新建一张表。这种业务类型就是需要高速插入,但是对于查询的效率不太关心。表越大,插入数据所需要索引维护的时间也就越长。
  • 取(哈希(列))/总表数 求余 tb_user_01, tb_user_02…
  • 如果分表时需要用多个列,创建额外的表维护多个列的关系 userid,friendName,tablename

表分区

  • 分区适用于例如日志记录,查询少。一般用于后台的数据报表分析。对于这些数据汇总需求,需要很多日志表去做数据聚合,我们能够容忍1s到2s的延迟,只要数据准确能够满足需求就可以。
  • MySQL主要支持4种模式的分区:range分区、list预定义列表分区,hash 分区,key键值分区。

存储过程

视图

同义词

CATALOG
  1. 1. 先言
    1. 1.1. 优化可能带来的问题
    2. 1.2. 优化的需求
    3. 1.3. 优化由谁参与
  2. 2. 优化的思路
    1. 2.1. 应急调优
    2. 2.2. 常规调优
  3. 3. 具体优化
    1. 3.1. mysql查询流程
    2. 3.2. 查询SQL分析
      1. 3.2.1. 1. 慢查询日志
      2. 3.2.2. 2. EXPLAIN 分析查询
      3. 3.2.3. exolan结果的列的说明
        1. 3.2.3.1. 1. id
        2. 3.2.3.2. 2. select_type
        3. 3.2.3.3. 3. table
        4. 3.2.3.4. 4. type【重要】
        5. 3.2.3.5. 5. possible_keys
        6. 3.2.3.6. 6. key
        7. 3.2.3.7. 7. key_len
        8. 3.2.3.8. 8. ref
        9. 3.2.3.9. 9. rows
        10. 3.2.3.10. 10. Extra
  4. 4. 索引优化
    1. 4.1. 什么是索引
    2. 4.2. 索引的类别
    3. 4.3. 索引的存储结构
      1. 4.3.1. BTree索引
      2. 4.3.2. 哈希索引(主要是Memory存储引擎使用)
    4. 4.4. 优化建议
    5. 4.5. 子查询优化
    6. 4.6. order by优化
    7. 4.7. GROUP BY优化
    8. 4.8. limit优化
    9. 4.9. 索引的使用场景分析
      1. 4.9.1. 适合使用索引场景
      2. 4.9.2. 不适合使用索引场景
    10. 4.10. 索引失效情况
      1. 4.10.1. 索引失效情况个人总结
    11. 4.11. InnoDB存储引擎介绍
      1. 4.11.1. InnoDB存储引擎支持事务的底层原理
        1. 4.11.1.1. MVVC
        2. 4.11.1.2. 隐藏字段
        3. 4.11.1.3. undo log日志
          1. 4.11.1.3.1. 版本链
        4. 4.11.1.4. readView
          1. 4.11.1.4.1. ReadView中包含了四个核心字段:
          2. 4.11.1.4.2. 而在readview中就规定了版本链数据的访问规则:
          3. 4.11.1.4.3. 不同的隔离级别,生成ReadView的时机不同:
    12. 4.12. 存储优化
      1. 4.12.1. 禁用索引
      2. 4.12.2. 禁用唯一性检查
      3. 4.12.3. 禁用外键检查
      4. 4.12.4. 批量插入数据
      5. 4.12.5. 禁止自动提交
    13. 4.13. MyISAM和Innodb区别
      1. 4.13.1. 具体实现的差别
  5. 5. 数据库结构优化
    1. 5.1. 优化表结构
    2. 5.2. 表拆分
      1. 5.2.1. 垂直拆分
      2. 5.2.2. 水平拆分 (查询条件,取hash, 如果是日期 每月/周/季/年)
      3. 5.2.3. 表分区
  6. 6. 存储过程
  7. 7. 视图
  8. 8. 同义词