20150324--Mysql索引优化-02
2016-05-08 21:32
519 查看
七、索引覆盖
索引覆盖是指:如果查询的列恰好是索引的一部分,那么查询只需要在索引文件上进行,不需要回行到磁盘再找数据,这种查询速度非常快,称为“索引覆盖” 案例1,如下对name字段添加了普通索引,要查询name字段信息。![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213117952-726942689.jpg)
案例2:比如对id和name字段建立符合索引,我们取出的数据是复合索引的一部分,因此用到了索引覆盖。
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213119327-1177690296.jpg)
八、前缀索引,
利用字段数据的前部分作为索引,称为前缀索引。减少索引长度,提高索引效率。 比如:统计密码的前7个字符,作为不相同匹配条件,几乎可以做到1:1 此时,就可以利用前7个字符做索引关键字即可(离散程度高)![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213120624-485435116.jpg)
语法: alter table 表名 add index (passwd(7)) 指定前7位作为索引关键字。 不使用索引前缀,索引的长度。
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213121890-760602421.jpg)
使用索引前缀后,索引的长度。
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213123077-1158840.jpg)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213124484-190765737.jpg)
九、翻页优化
翻页的sql语句: select * from table_name limit offset N 使用如上语句,在翻页时,翻到最后,越来越慢, 原因:并不是跨过offset行,取出n条, 是取出offset+N条数据,舍弃前面的offset行,只取出n条数据。![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213125796-1166891620.jpg)
如何解决? (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;语句取出的结果不一样,。
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213127390-558930078.jpg)
(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去查具体条目,这种技巧就是延迟索引。
十、碎片整理
比如建表测试:![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213128812-279500870.jpg)
数据表文件原来的容量:
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213130077-1396055198.jpg)
当delete from ceshi where id=1,应该容量减去三分之一,但是并没有被删除。 需要把里面的一些碎片给释放掉。 使用optimize table 表名;或alter table 表名 engine myisam(innodb) 执行optimize table 表名,命令后,把原来的碎片空间给释放掉
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213131046-508709278.jpg)
注意:修复表的数据及索引碎片,就会把所有的数据文件重新整理一遍,使之对齐,这个过程,如果表的行数比较大,也是比较耗费资源的操作,所以,不能频繁的修复。 如果表的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 读锁的演示:![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213131812-1732982440.png)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213132577-1209760521.png)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213137171-1740511175.jpg)
要注意:对表添加锁定后,只能操作锁定的表,如果想要操作其他表,则可以在锁定表时,一次性锁定多张表。语法:lock table 表1 read,表2 read;
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213138609-313669940.jpg)
写锁的演示 对表写锁锁定之后,自己可以进行修改和查询,另外的进程则无法查询,更不能修改。
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213140327-871693226.jpg)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213141952-64855274.jpg)
2、行锁的演示:
是innodb支持的一种锁,在使用时,要添加条件限制是要操作哪行数据。 语法: begin; //开始 执行语句;//要锁的行 commit; //解锁![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213143718-384433131.jpg)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213144905-407052043.png)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213149468-1472988518.png)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213150421-1454608517.png)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213151530-1791067891.png)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213152812-1568000240.png)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213153952-429504947.png)
文件锁,flock_file
十二、分区分表技术
基本概念,把一个表,从逻辑上分成多个区域,便于存储数据。 采用分区的前提:数据量非常大。![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213155546-2117271003.jpg)
分区的语法,在创建表时,完成分区 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) );![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213157124-905212984.jpg)
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213158999-115575823.jpg)
添加两天条语句,测试是否使用了分区存储。
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213200390-1127476496.jpg)
explain partitions select *from emp where store_id=3 测试是否用到了分区: explain partitions select * from p_list where store_id=20\G 注意:在使用分区时,where后面的字段必须是分区字段,才能使用到分区。
![](https://images2015.cnblogs.com/blog/897569/201605/897569-20160508213201921-1801209093.jpg)
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) );
相关文章推荐
- 20150324--Mysql索引优化-01
- 转发:[MySQL] 实现树形的遍历(关于多级菜单栏以及多级上下部门的查询问题)
- mysql数据库表清空后id如何从1开始自增
- mysql解压版安装教程
- Windows下MySQL安装、卸载、数据路径配置
- MySQL学习笔记-查看表,修改表,删除表
- MySQL 对于千万级的大表要怎么优化?
- Mysql 字符串 操作函数
- mysql主从复制
- Mysql数据库修复
- mysql插入时防止重复记录
- Mysql中触发器的使用
- [MySQL日记]主键唯一键重复插入解决方法
- mysql 临时表 效率问题改进
- MySQL知识
- MySQL 高级查询
- MySQL简单查询
- MySQL语句
- MySql修改数据库编码为utf8
- mysql操作语法