MySQL使用的一些小细节分享

121 阅读10分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

本次的分享是基于mysql的innoDB引擎,选取了一个常见的版本5.7,接下来将从以下的几个角度,结合一些项目中具体出现的事例,来进行具体的分析

     一.  关于mysql字符编码的问题

谈到字符编码问题,会让很多人感到头疼,这里不在深究各个字符编码的特点和理论,这里只说下Unicode和utf8字符编码的关系。

Unicode是编码字符集,而UTF-8就是字符编码,即Unicode规则字库的一种实现形式。随着互联网的发展,对同一字库集的要求越来越迫切,Unicode标准也就自然而然的出现。它几乎涵盖了各个国家语言可能出现的符号和文字,并将为他们编号。

Unicode的编号从0000开始一直到10FFFF共分为16个Plane,每个Plane中有65536个字符。而UTF-8则只实现了第一个Plane,可见UTF-8虽然是一个当今接受度最广的字符集编码,但是它并没有涵盖整个Unicode的字库,这也造成了它在某些场景下对于特殊字符的处理困难

什么是utf8mb4

苹果推广了emoji表情,而emoji表情是utf8没办法保存的。

utf8mb4是utf8的超集,理论上由utf8升级到utf8mb4字符编码没有任何兼容问题。    

utf8mb4是MySQL5.5.3版本之后支持的字符集,如果你需要使用这个字符集,前提条件是你的MySQL版本必须 >= 5.5.3 

     总结

不要在MySQL上使用utf8字符编码,推荐使用utf8mb4

这是一个外国大兄弟的原话,估计也是有故事的人:

Never use utf8 in MySQL — always use utf8mb4 instead. Updating your databases and code might take some time, but it’s definitely worth the effort. Why would you arbitrarily limit the set of symbols that can be used in your database? Why would you lose data every time a user enters an astral symbol as part of a comment or message or whatever it is you store in your database? There’s no reason not to strive for full Unicode support everywhere. Do the right thing, and use utf8mb4. 🍻

 

 

二. 关于mysql中的关键字和保留词

大家可以先看下下面的表结构:

在java中,给变量取名的时候,要求的是"见名知意",在创建数据库的时候,同样也是有这样的要求,在给变量取名的时候,尽量要还原变量本身所要表达的含义,而不是用一些比较通用的单词的表达,如上图所示,"type"和"day"是mysql之前版本的关键字和保留词,如果使用关键字和保留词作为表名或者列,会出现什么情况呢,请看下面的栗子:

首先我这里设计个简单的表:

表里面插入一条数据:

然后我们来看查这条数据以及查询结果:

那如果数据库里已经存在这种关键字,而且由于各种原因导致这些字段没办法修改,那有没有办法抢救一下呢?

答案是肯定可以的,同样的查询,我们稍微修改下mysql语句,看看会有什么不同

其实在字段上加上反引号就可以啦(~ ̄▽ ̄)~,友情提示 :位置就在"TAB"键的上面哦

想了解更多的小伙伴可以去MySQL官方网站上去看下,地址我贴在下面啦:

dev.mysql.com/doc/refman/…

三. 关于MySQL中的sql优化:

在我们日常使用Mysql中,涉及最多的基本上都是查询语句,而平时我们所见的慢sql,也基本上都是出现在查询语句中,接下来,我们来探讨下慢sql的查询优化问题吧ψ(`∇´)ψ

在mysql中有一个叫做查询优化器的模块,一条查询sql进行预发解析后会被交给查询优化器来进行优化,优化的结果就是生成我们熟悉的执行计划,执行计划中表明了会使用哪些索引,表之间的连接顺序等等,最后会按照执行计划中的步骤来调用存储引擎提供的方法来真正的执行查询。

PS:MySQL 5.7 支持的存储引擎有 InnoDB、MyISAM、Memory、Merge、Archive、Federated、CSV、BLACKHOLE 等 

Mysql的设计者Monty Widenius(有兴趣的同学可以去了解一下这个白头发大叔)把Mysql执行查询语句的方式称之为访问方法或者访问类型,相同的查询语句可以使用不同的执行方法来执行,结果一样,但是效率确有很多的偏差,俗话说,条条大路通罗马,我们要做的,就是找到效率最高的一条路

Mysql的查询大致可以分为使用全表扫描进行查询和使用索引进行查询,本次我们关注的重要主要就是,使用索引进行查询,使用索引来执行查询,又可以大致分为以下几类:

a)        针对主键或唯一二级索引的等值查询

b)        针对普通二级索引的等值查询

c)        针对索引列的范围查询

d)        直接扫描整个索引

废话不多说,我们来看下具体的栗子(这里就以单表查询为例):

首先建一张用户表,并且加上几个不同类型的索引

B+树本身就像是一个矮矮的大胖子(原谅我词穷,只能找到这种形容方式了😂😂),接下来,我就根据B+树的结构,结合不同类型的索引,来说说索引的工作方式:

ps:以下所有的查询语句使用的select * 是为了书写方便,实际应用中,请写具体的列名称

a) 针对主键或唯一二级索引的等值查询(const【常数级别】)

1.对于主键的等值查询,我找了个极度精简版的图,这个相信大家都懂,不需要多说啥。。

2.对于唯一二级索引的等值查询

可以看到,对于唯一二级索引的等值查询,第一步先从 idx_key2(对应上面那张表中的索引index_id_card)对应的B+树索引中根据 key2(id_card)列与常数的等值比较条件定位到一条二级索引记录,然后再根据该记录的id值到聚簇索引中获取到完整的用户记录,需要注意的是,这种const访问方法只能在主键列或者唯一二级索引列和一个常数进行等值比较时才有效,如果主键或者唯一二级索引是由多个列构成的话,索引中的每一个列都需要与常数进行等值比较,这个const访问方法才有效(这是因为只有该索引中全部列都采用等值比较才可以定位唯一的一条记录)

ps:思考一下唯一二级索引可以插入多个null值吗?如果可以插入,那么select * from test where id_card is null;这种查询语句能达到const要求吗? 

b)针对普通二级索引的等值查询(ref)

如:select * from test where name = '张三';

由于普通二级索引并不限制索引列值的唯一性,所以很多时候查出来的是多条数据,使用二级索引来执行查询的代价取决于等值匹配到的二级索引记录条数,回表的代价取决于匹配的条数

这种查询的访问方法被称之为:ref,二级索引列值为 null的情况,不论是普通的二级索引,还是唯一二级索引,它们的索引列对包含 null 值的数量并不限制,所以我们采用 key is null 这种形式的搜索条件最多只能使用 ref 的访问方法,而不是 const 的访问方法

c) 针对索引列的范围查询(range)

select * from test where age in (6,18) or (age > 20 and age < 60)

对于上面的查询语句,我们当然还可以使用全表扫描的方式来执行这个查询,不过也可以使用二级索引+回表的方式执行,如果采用二级索引+回表的方式来执行的话,那么此时的搜索条件就不只是要求索引列与常数的等值匹配了,而是索引列需要匹配某个或某些范围的值,在本查询中 列的值只要匹配下列3个范围中的任何一个就算是匹配成功了

这种利用索引进行范围匹配的访问方法称之为:range

此处所说的使用索引进行范围匹配中的索引可以是聚簇索引,也可以是二级索引。

d) 直接扫描整个索引(all)

这个其实就是全表扫描,对于innodb表来说也就是直接扫描聚簇索引

下面是我找到的建立索引的条件,大家可以做个参考:

1、表的主键、外键必须有索引;

2、数据量超过300的表应该有索引(这个需要视具体情况而定,若为关联表,可能数据量低的时候也需要建索引);

3、经常与其他表进行连接的表,在连接字段上应该建立索引(例如一些公共配置表);  

4、经常出现在Where子句中的字段,特别是大表的字段,应该建立索引;

5、索引应该建在选择性高的字段上,这个可以参照查询的时间复杂度;

6、索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;

7、复合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替: A、正确选择复合索引中的主列字段,一般是选择性较好的字段; B、复合索引的几个字段是否经常同时以AND方式出现在Where子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引; C、如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引; D、如果复合索引所包含的字段超过3个,那么仔细考虑其必要性,考虑减少复合的字段; E、如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引;

8、频繁进行数据操作的表,不要建立太多的索引,建立索引的字段,频繁的数据操作会导致索引不断的重构。

9、删除无用的索引,避免对执行计划造成负面影响; 索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。因为太多的索引与不充分、不正确的索引对性能都毫无益处:在表上建立的每个索引都会增加存储开销,索引对于插入、删除、更新操作也会增加处理上的开销。另外,过多的复合索引,在有单字段索引的情况下,一般都是没有存在价值的;相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负面影响更大

·