MySQL 优化,索引

一、MyISAM 和 InnoDB

Mysql逻辑架构:

1.连接层 2.服务层(sql优化)3.引擎层(存储和提取)4.存储层(数据存储再文件系统,完成与存储引擎的交互)

1. 对比:

2. MyISAM

适用于读操作多于写操作,写锁后其他线程不能做任何操作,会造成阻塞。不支持事务。适合小并发,小数据。

支持Btree索引

MyISAM 使用表锁:执行select语句前,会自动给涉及的表加读锁,执行增删改前给涉及的表自动加写锁。

3. InnoDB

Mysql 默认InnoDB 存储引擎,支持事务,适合插入和更新操作较多的场景,支持Btree和自适应Hash索引,使用行锁。适合高并发,大数据。

行锁变表锁:varchar 类型字段没写引号,发生类型转换,索引失效导致行锁变表锁。

间隙锁:当我们用范围条件检索数据,并请求共享或排他锁时,InnoDB会给已有的数据记录的索引项加锁;
对于键值在范围内但不存在的记录,就叫间隙。

间隙锁的危害:InnoDB会对这个间隙加锁。导致这个间隙无法进行操作,产生阻塞。

锁定一行的方式:

begin;
select * from A where a=8 for update; 锁定一行后对该行的其他操作将被阻塞,直到锁定行commit。
commit;

InnoDB 行锁分析:

通过检查InnoDB_row_lock_xxx 分析行锁的争夺情况
show status like 'innodb_row_lock%';
InnoDB_row_lock_time_avg 等待平均时长
InnoDB_row_lock_waits 等待总次数
InnoDB_row_lock_time 等待总时长

4. 读写锁

读锁(read)共享锁
当前线程只能读当前被锁的表,不能修改任何表。 其他线程对被锁表只能读,写操作阻塞。其他表可以读写。
写锁 (write)排他锁
当前线程只能对当前表读写。其他线程对当前表读写阻塞。
总结来说:读锁会阻塞写,不会阻塞读,而写锁则把读和写都阻塞。

二、索引优化

1. sql 性能下降原因

查询语句写的不好(子查询,关联查询太多)。

没建索引,或建了索引但索引失效。

服务器调优以及各个参数设置不合理(缓冲,线程数)。

2. mysql 操作命令

rpm -ivh MySQL-client-5.6.22-1.el6.i686.rpm
rpm -ivh MySQL-server-5.6.22-1.el6.i686.rpm
cat /etc/passwd|grep mysql 查看mysql安装是否成功
cat /etc/group|grep mysql 查看有没有mysql组
rpm -qa|grep -i mysql 查询已安装
ps -ef|grep mysql

单值索引:create index idx_user_name on user(name)
复合索引:create index idx_user_nameEmail on user(name,email)
创建索引:alter table `book` add index z(`card`);
删除索引:drop index idx_class_card on book;

3. 索引简介

3.1 是什么?

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高校获取数据的数据结构。可以得到索引的本质:索引是数据结构

索引是排好序的快速查找数据结构,可以提高MySQL查询效率,索引通常以索引文件的形式存储在磁盘上。

索引分类:单值索引 唯一索引(索引列的值必须唯一) 复合索引

3.2 优劣势

优势:提高数据检索效率,降低数据库的IO成本;索引列对数据进行排序,降低数据排序的成本,降低cpu的消耗。

劣势:占用空间,表的更新速度减慢,每次更新都要保存新添数据的索引列字段,需要进行索引信息调整。需要不停优化。

3.3 mysql 索引结构

BTree索引

真实数据存储在叶子节点(磁盘中),非叶子节点存储的是搜索方向(范围区间)。

Hash索引

全文索引

R-Tree索引

3.4 哪些情况需要建立索引

1.主键自动创建唯一索引

2.频繁查询的字段

3.查询中与其他表关联的字段,外键关系建立索引

4. 频繁更新不适合建索引。

5.where条件用不到的字段不建索引

6.高并发组合索引

7.查询中统计或者分组字段

4. Explain 查看执行计划

使用EXPLAIN关键字可以模拟优化器执行SQL语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是结构的性能瓶颈。

4.1 关键字介绍

1. id select查询的序列号,表示查询中执行select子句或者表的执行顺序
1)id相同,按顺序执行
2)id不同,递增,数字大优先级高
3)id相同也不同 数字大优先级高,相同按顺序执行

2.select_type :查询类型(普通,联合,子查询)

simple 简单查询  primary 最外层查询  subquery 子查询 derived 衍生(from列表中的子查询) union select出现在UNION之后

3.table 表

4.type 访问类型,以何种方式去访问数据

好-->差 尽可能达到rang级别,最好达到ref
system > const > eq_ref > ref > range > index > All

1)all 全表扫描,数据量较大时需要优化
2)index 全索引扫描
3)rang 范围扫描
4)ref 使用了非唯一索引进行数据查找 例如部门号
5)eq_ref 使用唯一性索引进行数据查找 例如员工号
6)const 至多一个匹配行
7)system 系统只有一行记录

5.possible_keys 可能用到的索引

6.key 实际用到的索引

7.key_len 索引中使用的字节数,保证结果前提下,越短越好

8.ref 显示索引的那一列被使用了

9.rows 查找结果读取的行数

10.Extra 包含不适合在其他列中显示但十分重要的信息

1)Using filesort 无法利用索引完成的排序操作称为文件排序
2)Using temporary 建立临时表来保存中间结果,查询完成之后把临时表删除,常见order by group by
3)Using index  表示当前查询是覆盖索引的
4)Using where 使用了where 过滤

4.2 覆盖索引和最左前缀

覆盖索引:select的数据列只用从索引中就能取得,不必读取数据行,查询列要被所建的索引覆盖。

最左前缀法则:多列索引要遵循最左前缀法则,查询从索引的最左列开始并且不跳过索引中的列。

5. 索引优化

5.1 索引失效

1)不要在索引上做操作(计算,函数,自动或手动类型转换)
2)存储引擎不能使用索引中范围条件右边的列。
3)尽量使用覆盖索引(索引列和查询列一致),减少select *
4)使用 != 或<>无法使用索引会导致全表扫描。
5)is null is not null无法使用索引
6)like以通配符开头(%abc)索引失效会变成全表扫描的操作。 想使用 %abc% 就建立覆盖索引,like KK%相当于=常量     %KK和%KK% 相当于范围。
7)尽量少用or,使用or连接索引会失效
8)字符串不加单引号索引失效

5.2 优化口诀

【优化口诀】
全值匹配我最爱,最左前缀要遵循;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
like百分写最右,覆盖索引不写 * ;
不等空值还有or,索引失效要少用;
VARCHAR引号不可丢,SQL高级so easy;

三、查询优化

1. 慢sql分析

让系统跑一段时间,查看生产的慢sql情况。

开启慢查询日志,设置阙值,将慢sql语句抓取出来。 show variables like '%slow_query_log%';

使用explain 进行分析。

show profile 查询sql在服务器里的执行细节和生命周期情况。

sql 数据库服务器参数调优。

2. 小表驱动大表

select * from A where id in (select id from B)
当B表数据集小于A表,使用 in
select * from A where exists (select 1 from B where B.id = A.id)
当A的数据集小于B表,使用 exists
exists 将主查询的数据,放到子查询中做条件验证,根据验证结果决定主查询结果是否保留。

3. Order By 优化

3.1 Mysql 两种排序方式

文件排序 FileSort效率低,扫描有序索引排序 Index效率高

index 方式排序:OrderBy语句使用索引最左前列,使用Where子句与OrderBy子句条件列组合满足索引最左前列

尽可能在索引上完成排序操作,遵循最左前缀,如果不在索引列上mysql 就会启动单路排序。

3.2 单路排序

从磁盘读取查询需要的所有列,按照orderby列在buffer对它们进行排序,将排序好的列表进行输出。避免了二次读取数据,把随机IO变成顺序IO,但是会使用很大空间。

单路排序的问题:数据列超过buffer容量,导致大量IO操作。

单路排序优化:
1. 忌select *
2. 尝试提高sort_buffer_size
3.max_length_for_sort_data

常见面试题汇总

如何设计一个高并发的系统

① 数据库的优化,包括合理的事务隔离级别、SQL语句优化、索引的优化

② 使用缓存,尽量减少数据库 IO

③ 分布式数据库、分布式缓存

④ 服务器的负载均衡

锁的优化策略

① 读写分离

② 分段加锁

③ 减少锁持有的时间

④ 多个线程尽量以相同的顺序去获取资源

实践中如何优化MySQL

①sql语句及索引的优化

②数据库表结构的优化

③系统配置的优化

④硬件的优化

优化数据库的方法

①选取最适用的字段属性,尽可能减少定义字段宽度,尽量把字段设置NOTNULL,例如’省份’、’性别’最好适用ENUM

②使用连接(JOIN)来代替子查询

③适用联合(UNION)来代替手动创建的临时表

④事务处理

⑤锁定表、优化事务处理

⑥适用外键,优化锁定表

⑦建立索引

⑧优化查询语句

SQL注入漏洞产生的原因?如何防止?

SQL注入产生的原因:程序开发过程中不注意规范书写sql语句和对特殊字符进行过滤,导致客户端可以通过全局变量POST和GET提交一些sql语句正常执行。

防止SQL注入的方式:
开启配置文件中的magic_quotes_gpc 和 magic_quotes_runtime设置

执行sql语句时使用addslashes进行sql语句转换

Sql语句书写尽量不要省略双引号和单引号。

过滤掉sql语句中的一些关键词:update、insert、delete、select、 * 。

提高数据库表和字段的命名技巧,对一些重要的字段根据程序的特点命名,取不易被猜到的。

Php配置文件中设置register_globals为off,关闭全局变量注册

控制错误信息,不要在浏览器上输出错误信息,将错误信息写到日志文件中。

char和varchar的区别?

char是一种固定长度的类型,varchar则是一种可变长度的类型,它们的区别是:  

char(M)类型的数据列里,每个值都占用M个字节,如果某个长度小于M,MySQL就会在它的右边用空格字符补足.(在检索操作中那些填补出来的空格字符将被去掉)在varchar(M)类型的数据列里,每个值只占用刚好够用的字节再加上一个用来记录其长度的字节(即总长度为L+1字节).  

varchar使用场景:

1.字符串列得最大长度比平均长度大很多

2.字符串很少被更新,容易产生存储碎片

3.使用多字节字符集存储字符串

Char使用场景:

1.存储固定长度(身份证,手机号)

2.长度比较短小得字符串

3.适合经常更新的字符串,更新时不会出现页分裂得情况,避免出现存储碎片,获得更好的io性能

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章