Class 1:(表达优化与列类型选择)
1.定长与变长分离
核心且常用字段,宜建成定长,放在一张表。
而varchar,test这种变长字段,适合单一放一张表,用主键与核心表关联起来。
2.常用字段和不常用字段分离
3.在一对多需要关联统计的字段上添加冗余字段
Class 2:(列选择原则)
1.字段类型优先级:
整型>date,time>enum,char>varchar>blob(无法使用内存零时表),text (整形>char 不需要考虑字符集,和校对集 例:a B c D 比较大小)
以性别utf8为例:
enum('男‘,‘女’);内部转成数字来存,多了一个转换过程
char(1);,3个字节长度
tinyint();定长一个字节
2.够用就行,不要慷慨
大的字段浪费内存影响速度(Varchar(10)比Varchar(300)查询内容占用内存更小)
3.尽量避免使用null
NULL不利于索引,要用特殊的字节来标注
在磁盘上占的空间其实更大
where 列名=null
where 列名!=null 都查不到值
where 列名 is null 或 is not null才可以查询
Enum列的说明:
1.在内部用整型储存(多一个转化的过程)
2.enum列与enum列相关联速度最快
3.比(var)char弱在碰到与char关联时要花时间
4.优势在于当char非常长时,enum仍然是整型固定长度。当查询的数据量越大,enum的优势越明显
Class 3:
索引优化策略
btree索引:(innodb)将索引值按一定的算法,存入一个树形的数据结构中(二叉树),每次查询都是从树的入口root开始,依次遍历node,获取leaf。这是MySQL里默认和最常用的索引类型。(btree就是二叉树在磁盘的数据结构上的优化,根据磁盘块大小才有多叉而不是用二叉)
hash索引:
在memory表(内存引擎)里使用。理论查询时间复杂度为O(1)
缺点:
1.hash函数计算后的结果是随机的,如果是在磁盘上放置数据(磁盘上会有很多空洞)。
2.无法对范围查询进行优化。
3.无法利用前缀索引(hello 和 hello world)。
4.排序无法优化。
5.必须回行(索引和数据不在同一个文件内)。通过索引拿到数据位置必须回到表中取数据。
总结:(memory表)HASH索引可以一次定位,不需要像树形索引那样逐层查找,因此具有极高的效率。但是,这种高效是有条件的,即只在“=”和“in”条件下高效,对于范围查询、排序及组合索引仍然效率不高。
Class 4:
Btree索引的常见误区:
-
索引是相互独立的(where cat_id=3 and price > 100 的情况下只能使用一个索引,原理根据Btree数据结构可知。)
-
在实际应用中,使用的是联合索引(注意:和顺序有关或左前缀索引)
例:index(a,b,c)
Where a=3 and b>4 (a,b同时起作用)
Where a=3 and c>4 (a起作用 ,c不起作用)
Where b=3 and c>4 (b,c同时不起作用)
Where a>3 and b=4 (a起作用,b不起作用)
原理:根据Btree数据结构,另外排序顺序形似字符串排序。
-
Btree索引同时能提高排序速度。
例:where c1=x and c4=x group by c3,c2
where c1=x and c4=x order by c3,c2
Class 5:
验证索引是否被使用:
Explain命令
例:explain select * from t4 where c1=3 and c2=4 and c4>5 and c3=2 \G
打印结果中的key_len =4 表示使用了4个 索引(是索引的长度不是数量,c1 长度为1) 如果值为null,代表该条指令没使用相关索引。
Class 6:(聚簇索引与非聚簇索引)
Myisam:数据和索引为两个单独的文件,索引指向数据在磁盘上的位置,为非聚簇索引。
Innodb:在主键索引文件上,直接存放该行数据,次索引指向主键引用,再使用主键找数据,为聚簇索引。(在某些情况下(表中有特长的数据列),使用次索引索引数据更快)
优势:数据少,不用回行。
劣势:当主键没有规律的时候,乱序插入会造成多次页分裂。
(形似于链表插入,和树插入)
Class 7:(索引覆盖)
在非聚簇索引中,所查询的数据就在索引文件中,即可不用回行。
例:create table t99(
Id int,
Name char(10),
Intro varchar(20),
Index inm(id,name)
)中
语句一:Select name from t99 where....
语句二:Select name,intro from t99 where....
在这两个语句中,语句一使用了索引覆盖。Explain命令中的Extra行显示
Using index
Class 8:(索引的合理设计)
-
查询频繁
-
区分度高:
例:男/女 不需要加。(一般情况下,达到0.1以上即可)
-
长度小的字段:
字段比较长,可以使用前几个字节建立索引
例:所有词组表,用第一个汉子做索引。
域名表,可以采用倒序之后的,前几个字节。
或者采用伪哈希技巧,CRC(域名)做索引。
-
尽量能覆盖常查询字段
-
列的查询顺序
根据不同的业务情况,使用冗余索引。(注意,有的索引有包含关系)
-
Optimize table 清除索引碎片,表碎片。、
Class 9:(sql语句优化)
-
sql语句时间花费
-
等待时间
-
执行时间(两个时间相关系)
-
取出数据
-
查找(按照索引)
-
查询的快:联合索引的顺序,区分度,长度
-
取得快:索引覆盖
-
传输的少:更少的行列
方法:切分查询
例:插入一万行数据,改成1000行插十次。
例:三表联查,改成两个两表联查(左连接多次,会有很多冗余数据)
Class 10:(explain详解)
1.id(查询执行的顺序)
2. select_type(查询中每个select子句的类型(简单OR复杂))
a. SIMPLE:查询中不包含子查询或者UNION
b. 查询中若包含任何复杂的子部分,最外层查询则被标记为:PRIMARY
c. 在SELECT或WHERE列表中包含了子查询,该子查询被标记为:SUBQUERY
d. 在FROM列表中包含的子查询被标记为:DERIVED(衍生)用来表示包含在from子句中的子查询的select,mysql会递归执行并将结果放到一个临时表中。服务器内部称 为"派生表",因为该临时表是从子查询中派生出来的
e. 若第二个SELECT出现在UNION之后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
f. 从UNION表获取结果的SELECT被标记为:UNION RESULT
3.Type
ALL, index, range, ref, eq_ref, const, system, NULL
从左到右,性能从最差到最好
a.ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
b. index:Full Index Scan,index与ALL区别为index类型只遍历索引树
c.range:索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行。显而易见的索引范围扫描是带有between或者where子句里带有<, >查询。当mysql使用索引去查找一系列值时,例如IN()和OR列表,也会显示range(范围扫描),当然性能上面是有差异的。
d. ref:使用非唯一索引扫描或者唯一索引的前缀扫描,返回匹配某个单独值的记录行
e. eq_ref:类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
f. const、system:当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量
g. NULL:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。
4. possible_keys
指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用
5. key
显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL
6. key_len
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)
7. ref
表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
8. rows
表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
9. Extra
包含不适合在其他列中显示但十分重要的额外信息
a. Using index
该值表示相应的select操作中使用了覆盖索引(Covering Index)
b. Using where
表示mysql服务器将在存储引擎检索行后再进行过滤。许多where条件里涉及索引中的列,当(并且如果)它读取索引时,就能被存储引擎检验,因此不是所有带where字句的查询都会显示"Using where"。有时"Using where"的出现就是一个暗示:查询可受益与不同的索引。
c. Using temporary
表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询
d. Using filesort
MySQL中无法利用索引完成的排序操作称为“文件排序”
e. Using join buffer
改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。
f. Impossible where
这个值强调了where语句会导致没有符合条件的行。
g. Select tables optimized away
这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行.
h. Index merges
当MySQL 决定要在一个给定的表上使用超过一个索引的时候,就会出现以下格式中的一个,详细说明使用的索引以及合并的类型。
Using sort_union(...)
Using union(...)
Using intersect(...)
EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。
Class 11:
1.in exist陷阱
Select * from table_a where id_a in(Select id_a from table_b where id_b = 6)
等效于exist 也就是 Select * from table_b where id_b = 6 and id_a=?
(id_a,id_b有索引)
所以反而是外面 用不上key,内层可以用上key。
2.union
MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合中。多个 SELECT 语句会删除重复的数据。
1.会产生临时表。
2.尽量字表where条件精确,临时表变小。
3.尽量使用union all,可以避免查重,查重就要排序。
3.Limit
Limit offset,N 实际将会取offset+N条记录。Offset越大,实用效率越低。
1.业务解决(百度):回避大offset,只能70页左右。
2.使用条件查询,比如limit 500000,N 改成where id>500000 limit N。改用逻辑删除。
3.索引覆盖+加延迟索引:
Select * from table
Inner join
(select id from table limit 500000,N)as tmp;
On table.id=tmp.id
感谢:
本学习笔记来自于网易云课堂
高性能Mysql :https://study.163.com/course/courseMain.htm?courseId=1003746011
部分内容引用自 https://www.cnblogs.com/gomysql/p/3720123.html