七、索引覆盖
索引覆盖是指:如果查询的列恰好是索引的一部分,那么查询只需要在索引文件上进行,不需要回行到磁盘再找数据,这种查询速度非常快,称为“索引覆盖”
案例1,如下对name字段添加了普通索引,要查询name字段信息。
案例2:比如对id和name字段建立符合索引,我们取出的数据是复合索引的一部分,因此用到了索引覆盖。
八、前缀索引,
利用字段数据的前部分作为索引,称为前缀索引。减少索引长度,提高索引效率。
比如:统计密码的前7个字符,作为不相同匹配条件,几乎可以做到1:1
此时,就可以利用前7个字符做索引关键字即可(离散程度高)
语法:
alter table 表名 add index (passwd(7)) 指定前7位作为索引关键字。
不使用索引前缀,索引的长度。
使用索引前缀后,索引的长度。
九、翻页优化
翻页的sql语句:
select * from table_name limit offset N
使用如上语句,在翻页时,翻到最后,越来越慢,
原因:并不是跨过offset行,取出n条,
是取出offset+N条数据,舍弃前面的offset行,只取出n条数据。
如何解决?
(1)从业务上去解决:
办法:不允许翻过100页,
以百度为例,一般翻页到70页左右,谷歌40页左右
(2)不用offset,用条件查询,条件中使用id查询,使用到了索引,
select * from user limit 10000,10;
select * from user where id>10000 limit 10;
下一页:select * from user where id>10000+10 limit 10
该种方式要注意:如果有数据被删除,会导致select * from user limit 10000,10;
和select * from user where id>10000 limit 10;语句取出的结果不一样,。
(3)假如不能使用限制翻页到100页,数据有删除,还要求翻页,速度不能受影响。
思路:通过翻页,先取出id(主键),在根据id取出数据。
select name,age,email from user inner join (select id from user limit 10000,10) as tmp on tmp.id=user.id
非要物理删除,还要用offset精确查询,还不限制用户分页,怎么办
我们现在必须要查,则只查索引,不查数据,得到id
再用id去查具体条目,这种技巧就是延迟索引。
十、碎片整理
比如建表测试:
数据表文件原来的容量:
当delete from ceshi where id=1,应该容量减去三分之一,但是并没有被删除。
需要把里面的一些碎片给释放掉。
使用optimize table 表名;或alter table 表名 engine myisam(innodb)
执行optimize table 表名,命令后,把原来的碎片空间给释放掉
注意:修复表的数据及索引碎片,就会把所有的数据文件重新整理一遍,使之对齐,这个过程,如果表的行数比较大,也是比较耗费资源的操作,所以,不能频繁的修复。
如果表的update操作很频繁,可以按周月来修复
十一、锁机制讲解
场景:
下订单:
库存 为100,买一件:
(1)取出库存的数量 100
(2)库存减去1 99
(3)把剩余的库存再写入到表里面。 99
如果是两个人同时操作:
刘备:
100-1=99
99
曹操:
100-1=99
99
锁机制,
mysql 的锁有以下几种形式:
表级锁:开销小,加锁快,发生锁冲突的概率最高,并发度最低。myisam引擎属于这种类型。
行级锁:开销大,加锁慢,发生锁冲突的概率最低,并发度也最高。innodb属于这种类型。
1、表锁的演示:
对myisam表的读操作(加读锁),不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求。只有当读锁释放后,才会执行其他进程的操作。
对myisam表的写操作(加写锁),会阻塞其他进程对同一表的读和写操作,只有当写锁释放后,才会执行其他进程的读写操作。
read:所有人都只可以读,只有释放锁之后才可以写。
write:只有锁表的客户可以操作这个表,其他客户读都不能读。
语法:
lock table 表名 read|write,
解锁:
unlock table
读锁的演示:
要注意:对表添加锁定后,只能操作锁定的表,如果想要操作其他表,则可以在锁定表时,一次性锁定多张表。语法:lock table 表1 read,表2 read;
写锁的演示
对表写锁锁定之后,自己可以进行修改和查询,另外的进程则无法查询,更不能修改。
2、行锁的演示:
是innodb支持的一种锁,在使用时,要添加条件限制是要操作哪行数据。
语法:
begin; //开始
执行语句; //要锁的行
commit; //解锁
文件锁,flock_file
十二、分区分表技术
基本概念,把一个表,从逻辑上分成多个区域,便于存储数据。
采用分区的前提:数据量非常大。
分区的语法,在创建表时,完成分区
create table 表名(
字段信息
)表选项
partition by 分区的类型(分区的条件)(
//分区信息。
);vvvvvvvvvvvvvvvv
1、分区类型:
list :条件值为一个数据列表。
通过预定义的列表的值来对数据进行分割
例子:假如你创建一个如下的一个表,该表保存有全国20家分公司的职员记录,这20家分公司的编号从1到20.而这20家分公司分布在全国5个区域,如下表所示:
职员表:
id name store_id(分公司的id)
北部 1,4,5,6,17,18
南部 2,7,9,10,11,13
东部 3,12,19,20
西部 8,14,15,16
id name store_id(分公司的id)
1 李小龙 3
2 大刀王五 8
北部 1,4,5,6,17,18
南部 2,7,9,10,11,13
东部 3,12,19,20
西部 8,14,15,16
create table emp(
id int,
name varchar(32),
store_id int
)engine myisam charset utf8
partition by list (store_id)(
partition p_north values in (1,4,5,6,17,18),
partition p_east values in(2,7,9,10,11,13),
partition p_south values in(3,12,19,20),
partition p_west values in(8,14,15,16)
);
添加两天条语句,测试是否使用了分区存储。
explain partitions select *from emp where store_id=3
测试是否用到了分区:
explain partitions select * from p_list where store_id=20G
注意:在使用分区时,where后面的字段必须是分区字段,才能使用到分区。
Range(范围)
这种模式允许将数据划分不同范围。例如可以将一个表通过年份划分成若干个分区
create table p_range(
id int,
name varchar(32),
birthday date
)partition by range (month(birthday))(
partition p_1 values less than (3),
partition p_2 values less than(6),
partition p_3 values less than(9),
partition p_4 values less than MAXVALUE
);
less than 小于等于;
MAXVALUE可能的最大值
partition by range(month(birthday))(
partition p_north values in (1,4,5,6,17,18),
partition p_east values in(2,7,9,10,11,13),
partition p_south values in(3,12,19,20),
partition p_west values in(8,14,15,16)
);