mysql

文章目录

基础篇

高级篇

第09章_性能分析工具的使用

1. 数据库服务器的优化步骤

当我们遇到数据库调优问题的时候,该如何思考呢?这里把思考的流程整理成下面这张图。
整个流程划分成了 观察(Show status) 和 行动(Action) 两个部分。字母 S 的部分代表观察(会使用相应的分析工具),字母 A 代表的部分是行动(对应分析可以采取的行动)。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2. 查看系统性能参数

在MySQL中,可以使用 SHOW STATUS 语句查询一些MySQL数据库服务器的 性能参数 、 执行频率 。
SHOW STATUS语句语法如下:
一些常用的性能参数如下:
• Connections:连接MySQL服务器的次数。
• Uptime:MySQL服务器的上线时间。
• Slow_queries:慢查询的次数。
• Innodb_rows_read:Select查询返回的行数
• Innodb_rows_inserted:执行INSERT操作插入的行数
• Innodb_rows_updated:执行UPDATE操作更新的行数
• Innodb_rows_deleted:执行DELETE操作删除的行数
• Com_select:查询操作的次数。
• Com_insert:插入操作的次数。对于批量插入的 INSERT 操作,只累加一次。
• Com_update:更新操作的次数。
• Com_delete:删除操作的次数。

3. 统计SQL的查询成本:last_query_cost

在这里插入图片描述

4. 定位执行慢的 SQL:慢查询日志

4.1 开启慢查询日志参数

在这里插入图片描述

在这里插入图片描述

4.2 查看慢查询数目

查询当前系统中有多少条慢查询记录

SHOW GLOBAL STATUS LIKE ‘%Slow_queries%’;

4.4 慢查询日志分析工具:mysqldumpslow

在生产环境中,如果要手工分析日志,查找、分析SQL,显然是个体力活,MySQL提供了日志分析工具
mysqldumpslow 。
查看mysqldumpslow的帮助信息

mysqldumpslow --help

在这里插入图片描述

在这里插入图片描述

4.5 关闭慢查询日志

在这里插入图片描述

5. 查看 SQL 执行成本:SHOW PROFILE

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



在这里插入图片描述

6. 分析查询语句:EXPLAIN

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

在这里插入图片描述

EXPLAIN小结

  • EXPLAIN不考虑各种Cache
  • EXPLAIN不能显示MySQL在执行查询时所作的优化工作
  • EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
  • 部分统计信息是估算的,并非精确值
EXPLAIN各列的作用

调优重点关注 type、key_len、rows、Extra列。

列名含义
id在一个大的查询语句(一条sql语句可能包含多个select)中每个SELECT关键字都对应一个 唯一的id。
1. id如果相同,可以认为是一组,从上往下顺序执行
2 .在所有组中,id值越大,优先级越高,越先执行。
3. 关注点:id号每个号码,表示一趟独立的查询, 一个sql的查询趟数越少越好
select_typeSELECT关键字对应的那个查询的类型。包括: simple、primary、union/dependent union/uncacheable union、subquery/dependent subquery/uncacheable subquery、union result、derived、materialized共11个值。
slelect_type的取值范围及含义如下:在这里插入图片描述
table表名。
不论我们的查询语句有多复杂,里边儿 包含了多少个表 ,到最后也是需要对每个表进行 单表访问 的,所以MySQL规定EXPLAIN语句输出的每条记录都对应着某个单表的访问方法,该条记录的table列代表着该表的表名(有时不是真实的表名字,可能是简称)。
partitions匹配的分区信息。
type针对单表的访问方法。type非常重要的性能分析列,枚举,共12个值,包括(从上到下的性能优化程度由高到低,如system性能最高、ALL最低):
1. system不需要扫描表,Mys ql内部有变量直接维护时,如对MyISAM引擎 EXPLAIN SELECT count(*) FROM t,内存中有一个变量维护着记录数计数器;
2. const当用主键或唯一二级索引列与常数进行等值匹配时。 EXPLAIN SELECT * FROM s1 WHERE id = 10005; EXPLAIN SELECT * FROM s1 WHERE key1 > ‘a’ AND key1 < ‘b’;EXPLAIN SELECT * FROM s1 WHERE key1 > ‘a’ AND key1 < ‘b’;
3. eq_ref(结合ref列一起看): 连接查询时,若被驱动表是通过主键或唯一二级索引列等值匹配时(若主键为联合索引时,需要所有列均等值匹配)时。EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id = s2.id; 从执行计划的结果中可以看出,MySQL打算将s2作为驱动表,s1作为被驱动表,重点关注s1的访问方法是 eq_ref ,表明在访问s1表的时候可以 通过主键的等值匹配 来进行访问。
4. ref普通二级索引与常量进行等值匹配时。EXPLAIN SELECT * FROM s1 WHERE key1 = ‘a’; (ref列的值为const)
5. fulltext:全文索引
6. ref_or_null普通二级索引与常量进行等值匹配,且索引列的值可能为NULL时。EXPLAIN SELECT * FROM s1 WHERE key1 = ‘a’ OR key1 IS NULL; (ref列的值为const)
7. index_merge : EXPLAIN SELECT * FROM s1 WHERE key1 = ‘a’ OR key3 = ‘a’; 从执行计划的 type 列的值是 index_merge 就可以看出,MySQL 打算使用索引合并的方式来执行对 s1 表的查询(key列的值为id_key1,id_key3)。
8. unique_subquery针对一些包含in 子查询的语句,如果查询优化器决定将in转换成exists子查询,且子查询可以使用到主键进行等值匹配时。下面语句会讲in改为exists子查询,且在子查询中通过主键进行等值匹配,故其type值为unique_subquery:EXPLAIN SELECT * FROM s1 WHERE key2 IN (SELECT id FROM s2 where s1.key1 =s2.key1) OR key3 = ‘a’;
9. index_subquery :EXPLAIN SELECT * FROM s1 WHERE common_field IN (SELECT key3 FROM s2 where s1.key1 = s2.key1) OR key3 = ‘a’;
10. range通过索引获取某些‘范围区间’的记录时。EXPLAIN SELECT * FROM s1 WHERE key1 IN (‘a’, ‘b’, ‘c’); 或者 EXPLAIN SELECT * FROM s1 WHERE key1 > ‘a’ AND key1 < ‘b’;
11. index当可以使用索引覆盖,但需要全表扫描全部的索引记录时。由于我们为key_part1、key_part2和key_part3建立了联合索引,下面的sql where部分不会使用到该索引,但select 部分的key_part2与where部分的key_part3都在索引中,此时就会使用索引覆盖(即只查索引即可得到结果,无需回表查数据),此时type的值为index。EXPLAIN SELECT key_part2 FROM s1 WHERE key_part3 = ‘a’;
12. ALL即全表扫描。EXPLAIN SELECT * FROM s1;。

小结
结果值从最好到最坏依次是: system > const > eq_ref > ref > fulltext > ref_or_null > index_merge >unique_subquery > index_subquery > range > index > ALL 其中比较重要的几个提取出来(见上图中的蓝色)。SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,最好是 consts级别。(阿里巴巴开发手册要求)。
possible_keys可能用到的索引。
key实际上使用的索引。
ken_len实际使用到的索引长度(字节数)。
key_len的长度计算公式:

1. varchar(10)变长字段且允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+1(NULL)+2(变长字段)

2. varchar(10)变长字段且不允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+2(变长字段)

3. char(10)固定字段且允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)+1(NULL)

4. char(10)固定字段且不允许NULL = 10 * ( character set:utf8=3,gbk=2,latin1=1)
ref当使用索引列等值查询时,与索引列进行等值匹配的对象信息。
rows预估的需要读取的记录条数。越小越好
filtered某个表经过搜索条件过滤后剩余记录条数的百分比。对于单表查询,filtered值没有什么参考意义。我们更关注在连接查询中驱动表对于的执行计划的filtered值,它决定了被驱动表要执行的次数(=rows*filtered)
如,对EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.id=s2.id and s1.common_field=‘a’, 输出的驱动表s1的rows为9000,filtered值=10,说明对驱动表s1通过s1.common_field='a’过滤后,得到9000*10%=900条记录,这900条记录都需要进一步从被驱动表s2中进行关联匹配,即900为被驱动表s2要执行的次数。
Extra用来说明一些额外的信息,包括不适合在其它列中显示但十分重要的额外信息,我们可以通过这些额外信息来更准确地理解mysql到底如何执行给定的查询语句。典型常见的值举例如下:
1. No tables used没有from时。 EXPLAIN SELECT 1;
2. Impossible WHEREwhere 条件不可能成立时。EXPLAIN SELECT * FROM s1 WHERE 1 != 1;
3. Using where当使用全表扫描来执行对某个表的查询,并且where条件有(只要有即可,还可能包含其他包含使用到索引的条件)针对该表的搜索条件时,。EXPLAIN SELECT * FROM s1 WHERE common_field = ‘a’;
4. No matching min/max row当select 为min、max等统计函数,但数据库中没有满足where条件的记录(key1 = 'abcdefg')时。EXPLAIN SELECT MIN(key1) FROM s1 WHERE key1 = ‘abcdefg’;
5. Using Index:·使用覆盖索引时。 EXPLAIN SELECT key1 FROM s1 WHERE key1 = ‘a’;
7. Using index condition使用索引条件下推时。 EXPLAIN SELECT * FROM s1 WHERE key1 > ‘z’ AND key1 LIKE ‘%b’;
8. Using join buffer (Block Nested Loop)在连接查询过程中,当被驱动表不能有效地利用索引时,MYSQL一般会为其分配一块名叫‘join_buffer’的内存块来加快查询速度,也就是我们所说的‘基于块的嵌套循环算法’
EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.common_field =s2.common_field; common_field没有建索引,因此该字段值为Using where, Using join buffer
9. Not exists当使用左外连接时,如果where子句中包含要求被驱动表的某个列(s2.id)等于NULL值的搜索条件(s2.id IS NULL),但那个列定义为NOT NULL时。EXPLAIN SELECT * FROM s1 LEFT JOIN s2 ON s1.key1 = s2.key1 WHERE s2.id IS NULL;
10. Using intersect(…) 、 Using union(…) 和 Using sort_union(…)对应type=index_merge,EXPLAIN SELECT * FROM s1 WHERE key1 = ‘a’ OR key3 = ‘a’; (结果显示using union(idx_key1, idx_key3); using where)
11. Zero limit: EXPLAIN SELECT * FROM s1 LIMIT 0;
11. NULL对结果集中的记录进行排序时可以利用到索引时。EXPLAIN SELECT * FROM s1 ORDER BY key1 LIMIT 10;
12. Using filesort与NULL相反,排序操作无法使用到索引(common_field 没有定义索引)时,只能在内存中(记录较少时)或磁盘中(记录较多时)进行排序,MySQL将这两情况的排序统称为文件排序(filesort), EXPLAIN SELECT * FROM s1 ORDER BY common_field LIMIT 10;
13. Using temporary使用到临时表时,一般用在 对distinct、group by、union等操作无法有效利用索引来完成时,此值需要尽量避免。EXPLAIN SELECT DISTINCT common_field FROM s1;

7. EXPLAIN的进一步使用

7.1 EXPLAIN四种输出格式

这里谈谈EXPLAIN的输出格式。EXPLAIN可以输出四种格式: 传统格式 , JSON格式 , TREE格式 以及 可
视化输出 。用户可以根据需要选择适用于自己的格式。

7.2 SHOW WARNINGS的使用

在这里插入图片描述

8. 分析优化器执行计划:trace

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

9. MySQL监控分析视图-sys schema

9.1 Sys schema视图摘要

在这里插入图片描述

9.2 Sys schema视图使用场景

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

第10章_索引优化与查询优化

1. 索引失效场景(案例)

1. 计算、函数、类型转换(自动或手动)导致索引失效

在这里插入图片描述
type为“ALL”,表示没有使用到索引,查询时间为 3.62 秒,查询效率较之前低很多。

在这里插入图片描述

2. 类型转换导致索引失效

在这里插入图片描述

3. 范围条件右边的列索引失效(范围匹配应该放到where最后)

create index idx_age_name_classid on student(age,name,classid);

在这里插入图片描述

在这里插入图片描述

4. 不等于(!= 或者<>)索引失效
5. is null可以使用索引,is not null无法使用索引
6. like以通配符%开头索引失效
7. OR 前后存在非索引的列,索引失效

在这里插入图片描述

8. 不同的 字符集 进行比较前需要进行 转换 会造成索引失效

统一使用utf8mb4( 5.5.3版本以上支持)兼容性更好,统一字符集可以避免由于字符集转换产生的乱码。不
同的 字符集 进行比较前需要进行 转换 会造成索引失效。

2. 关联查询优化

关联查询优化小结

  • 保证被驱动表的JOIN字段已经创建了索引。
  • 需要JOIN 的字段,数据类型保持绝对一致。
  • LEFT JOIN 时,选择小表作为驱动表, 大表作为被驱动表 。减少外层循环的次数。
  • INNER JOIN 时,MySQL会自动将 小结果集的表选为驱动表 。选择相信MySQL优化策略。
  • 能够直接多表关联的尽量直接关联,不用子查询。(减少查询的趟数)。
  • 不建议使用子查询,建议将子查询SQL拆开结合程序多次查询,或使用 JOIN 来代替子查询。
  • 衍生表建不了索引。
什么叫作“小表”?

在决定哪个表做驱动表的时候,应该是两个表按照各自的条件过滤,过滤完成之后,计算参与join的各个字段的总数据量,数据量小的那个表,就是“小表”,应该作为驱动表。

2.1 内连接 inner join

SELECT SQL_NO_CACHE * FROM type inner JOIN book ON type.card = book.card;

分三种情况

  1. 若两个表的连接条件字段均创建了索引,则MySQL优化器会自动选择小表作为驱动表,即小表驱动大表
  2. 若两个表的连接条件字段(type.card和book.card)均未创建索引,则两个表都用全表扫描,效率最低,此时MySQL优化器会同样选择 小表驱动大表
  3. 若两个表的连接条件字段只有其中一个创建了索引,则MySQL优化器会自动选择创建了索引的表作为被驱动表
2.2 左外连接 left [outer] join
2.2.1 左外连接 left [outer] join 不带where 条件

EXPLAIN SELECT SQL_NO_CACHE * FROM type LEFT JOIN book ON type.card = book.card;

在右表book的关联字段添加索引
ALTER TABLE book ADD INDEX Y ( card); #【被驱动表】,可以避免全表扫描,优化生效

条件用于确定如何从右表(被驱动表)搜索行,左表(驱动表)的数据一定全都有,所以 右表是我们的关键点,一定需要建立索引 。
例如,下方sql需要为book.card建立索引进行优化。

但为左表添加索引则不生效:
ALTER TABLE type ADD INDEX X (card); #【驱动表】,无法避免全表扫描,优化失效

2.2.2 左外连接 left [outer] join 带where 条件

EXPLAIN SELECT SQL_NO_CACHE * FROM type LEFT JOIN book ON type.card = book.card where type.s1=book.s1;
添加where 条件后,MySQL优化器会将其优化为内连接,因此可能会选择被连接表 book作为驱动表。

2.2 Index Nested-Loop Join (NLJ) 、Simple Nested-Loop Join 和 Block Nested-Loop Join
2.2.1 Index Nested-Loop Join (NLJ)

EXPLAIN SELECT * FROM t1 STRAIGHT_JOIN t2 ON (t1.a=t2.a);
如果直接使用join语句,MySQL优化器可能会选择表t1或t2作为驱动表,这样会影响我们分析SQL语句的执行过程。所以,为了便于分析执行过程中的性能问题,我改用 straight_join 让MySQL使用固定的连接方式执行查询,这样优化器只会按照我们指定的方式去join。在这个语句里,t1 是驱动表,t2是被驱动表。

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

两个结论:
1. 使用join语句,性能比强行拆成多个单表执行SQL语句的性能要好;
2. 如果使用join语句的话,需要让小表做驱动表。

2.2.2 Simple Nested-Loop Join
2.2.3 Block Nested-Loop Join

3. 子查询优化

MySQL从4.1版本开始支持子查询,使用子查询可以进行SELECT语句的嵌套查询,即一个SELECT查询的结果作为另一个SELECT语句的条件。 子查询可以一次性完成很多逻辑上需要多个步骤才能完成的SQL操作 。 子查询是 MySQL 的一项重要的功能,可以帮助我们通过一个 SQL 语句实现比较复杂的查询
但是,子查询的执行效率不高。原因:
① 执行子查询时,MySQL需要为内层查询语句的查询结果 建立一个临时表 ,然后外层查询语句从临时中查询记录。查询完毕后,再撤销这些临时表 。这样会消耗过多的CPU和IO资源,产生大量的慢查询。
② 子查询的结果集存储的临时表,不论是内存临时表还是磁盘临时表都 不会存在索引 ,所以查询性能会受到一定的影响。
③ 对于返回结果集比较大的子查询,其对查询性能的影响也就越大。
·在MySQL中,可以使用连接(JOIN)查询来替代子查询·。连接查询 ·不需要建立临时表 ·,其 ·速度比子查询要快· ,如果查询中使用索引的话,性能就会更好。
结论:尽量不要使用NOT IN 或者 NOT EXISTS,用LEFT JOIN xxx ON xx WHERE xx IS NULL替代

4. 排序优化

问题:在 WHERE 条件字段上加索引,但是为什么在 ORDER BY 字段上还要加索引呢?
1优化建议1:

  1. SQL 中,可以在 WHERE 子句和 ORDER BY 子句中使用索引,目的是在 WHERE 子句中 避免全表扫描 ,在 ORDER BY 子句 避免使用 FileSort 排序 。当然,某些情况下全表扫描,或者 FileSort 排序不一定比索引慢。但总的来说,我们还是要避免,以提高查询效率。
  2. 尽量使用 Index 完成 ORDER BY 排序。如果 WHERE 和 ORDER BY 后面是相同的列就使用单索引列;如果不同就使用联合索引。
  3. 无法使用 Index 时,需要对 FileSort 方式进行调优。

结论

  1. 两个索引同时存在,mysql自动选择最优的方案。(对于这个例子,mysql选择
    idx_age_stuno_name)。但是, 随着数据量的变化,选择的索引也会随之变化的 。
  2. 当【范围条件】和【group by 或者 order by】的字段出现二选一时,优先观察条件字段的过滤数量,如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上。反之亦然

5. GROUP BY优化

  • group by 使用索引的原则几乎跟order by一致 ,group by 即使没有过滤条件用到索引,也可以直接使用索引。
  • group by 先排序再分组,遵照索引建的最佳左前缀法则
  • 当无法使用索引列,增大 max_length_for_sort_data 和 sort_buffer_size 参数的设置
  • where效率高于having,能写在where限定的条件就不要写在having中了
  • 减少使用order by,和业务沟通能不排序就不排序,或将排序放到程序端去做。Order by、group by、distinct这些语句较为耗费CPU,数据库的CPU资源是极其宝贵的。
  • 包含了order by、group by、distinct这些查询的语句,where条件过滤出来的结果集请保持在1000行以内,否则SQL会很慢。

6. 优化分页查询

7. 优先考虑覆盖索引

7.1 什么是覆盖索引

简单说就是, 覆盖索引 指 索引列+主键包含 SELECT 到 FROM之间查询的列,此时通过索引即可获取所需列的数据,不需要再回表去读取行了

理解方式一:索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了。一个索引包含了满足查询结果的数据就叫做覆盖索引。
理解方式二:非聚簇复合索引的一种形式,它包括在查询里的SELECT、JOIN和WHERE子句用到的所有列(即建索引的字段正好是覆盖查询条件中所涉及的字段)。

7.2 覆盖索引的利弊
  • 好处
    • 避免Innodb表进行索引的二次查询(回表)
    • 可以把随机IO变成顺序IO加快查询效率
  • 弊端
    • 索引字段的维护 总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这是业务DBA,或者称为业务数据架构师的工作。

8. 如何给字符串添加索引

对字符串,使用前缀索引,定义好合适的(区分度90%以上)长度,就可以做到既节省空间,又不用额外增加太多的查询成本。前面已经讲过区分度,区分度越高越好。因为区分度越高,意味着重复的键值越少。

前缀索引对覆盖索引的影响
使用前缀索引就用不上覆盖索引对查询性能的优化了,这也是你在选择是否使用前缀索引时需要考虑的一个因素。

9. 索引下推 Index Condition Pushdown(ICP)

9.1 索引下推概念

将where条件的索引过滤处理,由server层下推到存储引擎层来处理,即索引下推

9.2 使用 索引下推的条件

① 只能用于二级索引(secondary index)
②explain显示的执行计划中type值(join 类型)为 range 、 ref 、 eq_ref 或者 ref_or_null 。
③ 并非全部where条件都可以用ICP筛选,如果where条件的字段不在索引列中,还是要读取整表的记录到server端做where过滤。
④ ICP可以用于MyISAM和InnnoDB存储引擎
⑤ MySQL 5.6版本的不支持分区表的ICP功能,5.7版本的开始支持。
⑥ 当SQL使用覆盖索引时,不支持ICP优化方法。

9.3 使用索引下推的加速效果

使用前,存储层多返回了需要被index filter过滤掉的整行记录
使用ICP后,直接就去掉了不满足index filter条件的记录,省去了他们回表和传递到server层的成本。
ICP的 加速效果 取决于在存储引擎内通过 ICP筛选 掉的数据的比例

10. 普通索引 vs 唯一索引

结论:建议使用普通索引

10.1 查询过程

查询过程 普通索引和唯一索引性能差别不大。

10.2 更新过程

建议 尽量选择普通索引普通索引 可以配合使用change buffer ,对于 数据量大 的表的更新优化还是很明显的。唯一索引无法使用change buffer,对数据量大的表的更新效果不佳。

什么是change buffer

为了说明普通索引和唯一索引对更新语句性能的影响这个问题,介绍一下change buffer
当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下, InooDB会将这些更新操作缓存在change buffer中,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行change buffer中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。
将change buffer中的操作应用到原数据页,得到最新结果的过程称为 merge 。除了 访问这个数据页 会触发merge外,系统有 后台线程会定期 merge。在 数据库正常关闭(shutdown) 的过程中,也会执行merge操作。
如果能够将更新操作先记录在change buffer, 减少读磁盘 ,语句的执行速度会得到明显的提升。而且,数据读入内存是需要占用 buffer pool 的,所以这种方式还能够 避免占用内存 ,提高内存利用率。
唯一索引的更新就不能使用change buffer ,实际上也只有普通索引可以使用。

change buffer的使用场景
  1. 普通索引和唯一索引应该怎么选择?其实,这两类索引在查询能力上是没差别的,主要考虑的是对 更新性能 的影响。所以,建议你 尽量选择普通索引 。
  2. 在实际使用中会发现, 普通索引 和 change buffer 的配合使用,对于 数据量大 的表的更新优化还是很明显的。
  3. 如果所有的更新后面,都马上 伴随着对这个记录的查询 ,那么你应该 关闭change buffer 。而在其他情况下,change buffer都能提升更新性能。
  4. 由于唯一索引用不上change buffer的优化机制,因此如果 业务可以接受 ,从性能角度出发建议优先考虑非唯一索引。但是如果"业务可能无法确保"的情况下,怎么处理呢?
    • 首先, 业务正确性优先 。我们的前提是“业务代码已经保证不会写入重复数据”的情况下,讨论性能问题。如果业务不能保证,或者业务就是要求数据库来做约束,那么没得选,必须创建唯一索引。
      这种情况下,本节的意义在于,如果碰上了大量插入数据慢、内存命中率低的时候,给你多提供一个排查思路。
    • 然后,在一些“ 归档库 ”的场景,你是可以考虑使用唯一索引的。比如,线上数据只需要保留半年,然后历史数据保存在归档库。这时候,归档数据已经是确保没有唯一键冲突了。要提高归档效率,可以考虑把表里面的唯一索引改成普通索引。

11. 其它查询优化策略

11.1 EXISTS 和 IN 的区分

问题:
不太理解哪种情况下应该使用 EXISTS,哪种情况应该用 IN。选择的标准是看能否使用表的索引吗?

11.2 COUNT(*)与COUNT(具体字段)效率

问:在 MySQL 中统计数据表的行数,可以使用三种方式: SELECT COUNT(*) 、 SELECT COUNT(1) 和
SELECT COUNT(具体字段) ,使用这三者之间的查询效率是怎样的?

11.3 关于SELECT(*) --不推荐

在表查询中,建议明确字段,不要使用 * 作为查询的字段列表,推荐使用SELECT <字段列表> 查询。原因:
① MySQL 在解析的过程中,会通过 查询数据字典 将"*"按序转换成所有列名,这会大大的耗费资源和时间。
② 无法使用 覆盖索引

11.4 LIMIT 1 对优化的影响

针对的是会扫描全表的 SQL 语句,如果你可以确定结果集只有一条,那么加上 LIMIT 1 的时候,当找到一条结果的时候就不会继续扫描了,这样会加快查询速度。
如果数据表已经对字段建立了唯一索引,那么可以通过索引进行查询,不会全表扫描的话,就不需要加上 LIMIT 1 了。

11.5 多使用COMMIT

只要有可能,在程序中尽量多使用 COMMIT,这样程序的性能得到提高,需求也会因为 COMMIT 所释放的资源而减少。

COMMIT 所释放的资源:

  • 回滚段上用于恢复数据的信息
  • 被程序语句获得的锁
  • redo / undo log buffer 中的空间
  • 管理上述 3 种资源中的内部花费

12. 淘宝数据库,主键如何设计的?

  1. 不建议用自增做主键
  2. 不建议业务字段做主键:作为项目设计的技术人员,我们谁也无法预测在项目的整个生命周期中,哪个业务字段会因为项目的业务需求而有重复,或者重用之类的情况出现。
  3. 主键设计至少应该是全局唯一且是单调递增。全局唯一保证在各系统之间都是唯一的,单调
    递增是希望插入时不影响数据库性能。

推荐使用有序的UUID作为业务主键。

默认的UUID是无序的,因为它将时间低位放在最前面,而这部分的数据是一直在变化的,并且是无序。
在这里插入图片描述

通过将时间高低位互换,就变成了有序的UUID。
MySQL 8.0可以更换时间低位和
时间高位的存储方式,这样UUID就是有序的UUID了。
MySQL 8.0还解决了UUID存在的空间占用的问题,除去了UUID字符串中无意义的"-"字符串,并且将字符串用二进制类型保存,这样存储空间降低为了16字节。可以通过MySQL8.0提供的uuid_to_bin函数实现上述功能,同样的,MySQL也提供了bin_to_uuid函数进行转化:

SET @uuid = UUID();
SELECT @uuid,uuid_to_bin(@uuid),uuid_to_bin(@uuid,TRUE);

以上MySQL 8.0 通过函数uuid_to_bin(@uuid,true)将UUID转化为有序UUID了。全局唯一 + 单调递增,这不就是我们想要的主键!

如果不是MySQL8.0 肿么办?手动赋值字段做主键!

  • 28
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值