高阶MySQL索引和查询优化

MySQL引擎查看

show engines;

InnoDB default supports transaction, row-level locking, and foreign keys.(支持事务、行锁、外键)

show variables like ‘%storage_engine%’;
default_storage_engine InnoDB

索引建立

user表
id name email nickname

单值索引:create index idx_user_name on user(name)
复合索引:create index idx_user_nameEmail on user(name,email)

7种join

left join
right join
inner join

索引:排序、查找

多路搜索树,并不一定是二叉树 B-tree
数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引。

优势:
1、提高检索效率,降低数据库的IO成本;
2、对数据进行排序,降低排序成本,降低CPU的消耗;

劣势:

性能分析

explain+sql语句
能干嘛:表的读取顺序、数据读取操作的操作类型、哪些索引可以使用、哪些索引被实际使用、表之间的引用、每张表有多少行被优化器查询
执行计划包含的信息:id,select_type,table,type,possible_keys,key,key_len,ref,rows,extra

id:id相同,按顺序从上往下执行,id不同,越大优先级越搞,id有相同有不同,先执行大的,derived=衍生表,derived2的2表示被衍生表的id。

select_type:simple、primary、subquery、derived、union、union result。
type:从最好到最差依次是system>const>eq_ref>ref>range>index>all,null

system:表只有一行记录(等于系统表)
const(常量):表示通过索引一次就找到了,const用于比较primary key或者unique索引。
eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。
ref:①非唯一性索引扫描,返回匹配某个单独值的所有行;②本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,它可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。
range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引,一般就是在你的where语句出现了between、<、>、in等的查询。开始于索引的某一点,结束于另一点,不用扫描全部索引。
index:Full Index Scan,index于ALL区别为index类型只遍历索引树。all和index都是读全表,但index是从索引读取,all是从硬盘中读取。

possible_keys:显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用。
key:实际使用的索引。如果为null,则没有使用索引。查询中若使用了覆盖索引,则该索引仅出现在key列表中。
覆盖索引:建的索引和字段刚好吻合。理解方式一,就是select的数据列只用从索引中就能够取得,不必读取数据行,mysql可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖。
理解方式二,略。

key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好。key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的。
----->同样结果下,查询条件越少越好。

ref:显示索引的哪一列被使用了,如果可能的话,是一个常数。哪些列或常量被用于查找索引列上的值。

rows:根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数。

Extra:包含不适合在其他列中显示但十分重要的额外信息。
①Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。mysql中无法利用索引完成的排序操作称为“文件排序”。
②Using temporary:使用了临时表保存中间结果,
③Using index:表示相应的操作中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错。如果同时出现using where,表明索引被用来执行索引键值的查找;如果没有同时出现using where,表明索引用来读取数据而非执行查找动作。
④using where
⑤using join buffer:使用了缓存
⑥impossible where:如:where name=‘Lily’ and name=‘张三’
⑦select tables optimized away
⑧distinct

CASE
两表、三表
索引:①左连接索引建在右表上;②右连接索引建左表上;

join语句的优化

①尽可能减少join语句中的nestedloop的循环总次数,“永远用小结果集驱动大的结果集”。如:书和类别,类别驱动书表
②优先优化nestedloop的内层循环;
③保证join语句中被驱动表上join条件字段已经被索引
④当无法保证被驱动表的join条件字段被索引且内存资源充足的前提下,不吝惜joinbuffer的设置;

索引失效的原因:

①全值匹配我最爱
②最佳左前缀法则:如果索引了多列,查询从索引的最左前列开始,并且不跳过索引中的列。(带头大哥不能死,中间兄弟不能断
③不能在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描。(索引列上无计算
④存储引擎不能使用索引中范围条件右边的列(范围之后全失效)。
⑤尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select *。
⑥mysql在使用不等于(!=或者<>)的时候,无法使用索引会导致全表扫描。
⑦is null,is not null 也无法使用索引。
⑧like以通配符开头(’%abc’)mysql索引失效会变成全表扫描的操作。(like的%加右边,或者用覆盖索引解决
⑨字符串不加单引号索引失效。(字符串里有引号
⑩少用or,用它来连接时索引会失效。

定值、范围还是排序,一般order by是给个范围,group by基本上都需要进行排序,会产生临时表。

一般性建议:

①对于单键索引,尽量选择针对当前query过滤性更好的索引;
②在选择组合索引的时候,当前query中过滤性最好的字段在索引字段顺序中,位置越靠前越好;
③在选择组合索引的时候,尽量选择可以能够包含当前query中的where字句中更多字段的索引;
④尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的。

查询截取分析

①慢查询的开启并捕获
②explain+慢SQL分析
③show profile查询SQL在mysql服务器里面的执行细节和生命周期情况
④SQL数据库服务器的参数调优

查询优化

①小表驱动大表

select *from A where id in (select id from B)
等价于:
for select id from B
for select * from A where A.id = B.id
当B表的数据集必须小于A表的数据集时,用in优于exists。

select * from A where exists (select 1 from B where B.id = A.id)
等价于
for select * from A
for select * from B where B.id = A.id
当A表的数据集小于B表的数据集时,用exists优于in。

exists
select … from table where exists (subquery)

②order by关键字的排序优化

order by子句,尽量使用index方式排序,避免使用filesort方式排序(默认升序)

尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀

如果不在索引列上,filesort有两种算法:mysql就要启动双路排序和单路排序

mysql4.1之前使用双路排序

mysql4.1之后使用单路排序

提高order by的速度

order by时select * 是一个大忌,只query需要的字段。

当query的字段大小总和小于max_length_for_sort_data 而且排序字段不是TEXT|BLOB类型时,会用改进后的算法——单路排序,否则用老算法——多路排序

两种算法的数据都有可能超出sort_bufer的容量,超出之后,会创建tmp文件进行合并排序,导致多次I/O,但是用单路排序算法的风险会更大一些,所以要提高sort_buffer_size。

尝试提高sort_buffer_size

尝试提高max_length_for_sort_data

③为排序使用索引

mysql两种排序方式:文件排序或扫描有序索引排序
mysql能为排序与查询使用相同的索引

key a_b_c(a,b,c)
order by 能使用索引最左前缀
-order by a
-order by a,b
-order by a,b,c
-order by a desc,b desc, c desc
如果where使用索引的最左前缀定义为常量,则order by能使用索引
-where a = const order by b,c
-where a = const and b = const order by c
-where a = const and b>const order by b,c
不能使用索引进行排序
-order by a asc,b desc ,c desc //排序不一致
-where g = const by order by b,c //丢失a索引
-where a = const order by c //丢失b索引
-where a = const order by a,d //d 不是索引的一部分
-where a in (…) order by b,c //对于排序来说,多个相等条件也是范围查询

慢查询日志

①mysql的慢查询日志是mysql提供的一种日志记录,它用来记录在mysql中响应时间超过阈值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中;
②long_query_time的默认值为10,意思是运行10秒以上的语句;
③由他来查看哪些SQL超出了我们的最大忍耐时间值,比如一条SQL执行超过5秒钟,我们就算慢SQL,希望能收集超过5秒的SQL,结合之前explain进行全面分析。

默认情况下,mysql数据库没有开启慢查询日志,需要手动设置;如果不是调优需要的话,不建议开启,因为开启慢查询日志会或多或少带来一定的性能影响。

show variables like ‘%slow_query_log%’;
开启:set global slow_query_log=1;
如果要永久生效,必须修改配置文件my.cnf,[mysqld]下增加或修改参数slow_query_log 和slow_query_log_file 后,然后重启mysql服务器。
slow_query_log=1
slow_query_log_file = /var/lib/mysql/xx-slow.log(默认host_name-slow.log)记录默认超过多少时间的查询记录,
long_query_timeshow variables like ‘long_query_time%’;
等于10秒的不会记录,只记录大于10秒的

查询当前系统有多少条慢查询记录
show global status like ‘%Slow_queries%’;

long_query_time = 3;
log_output=FILE

日志查询分析工具mysqldumpslow
①s:表示按照何种方式排序
②c:访问次数
③l:锁定时间
④r:返回记录
⑤t:查询时间
⑥al:平均锁定时间
⑦ar:平均返回记录数
⑧at:平均查询时间
⑨t:返回前面多少条的数据
⑩后边搭配一个正则匹配模式,大小写不敏感

定义分号; 作为结束符号:delimiter ;

showProfile:是mysql提供可以用来分析当前会话中语句执行的资源消耗情况,可以用于SQL的调优的测量,默认关闭状态,保存最近15次的运行结果。
①查看是否支持:show variables like ‘profiling’;
②set profiling=on;
③show profiles;
④show profile cpu , block io for query 3;
⑤日常开发需要注意的结论:converting HEAP to MyISAM 查询结果太大,内存都不够用了往磁盘上搬了;Creating tmp table创建临时表(拷贝数据到临时表;用完再删除);Coping to tmp table on disk,把内存中临时表复制到磁盘,危险;locked

全局查询日志(生产永远不要开此功能)
set global general_log=1;
set global log_output = ‘TABLE’;

mysql锁机制

锁是计算机协调多个进程或线程并发访问某一资源的机制

锁的分类
①对数据操作的类型分读写,读锁(共享锁)、写锁(排它锁)
②对数据操作的粒度分表锁、行锁

表锁(偏读)
行锁(偏写)

lock table 表名 read(write), 表名2 read(write) ;
show open tables;
unlock tables;

读阻塞写
简而言之,就是读锁会阻塞写,但是不会阻塞读,而写锁则会把读和写都阻塞。

show status like ‘table%’;

InnoDB存储引擎,开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
InnovationDB与MyISAM的最大不同有两点:一是支持事务,二是采用了行级锁;

事务ACID,原子性(Atomicity),一致性(Consistent),隔离性(Isolation),持久性(Durable)

show variables like ‘tx_isolation’;
隔离性
未提交读
已提交读
可重复读
可序列化
mysql 是RR,不会出现脏读和可重复读,但会出现幻读

无索引行锁升级为表锁
间隙锁的危害(当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但并不存在的记录,叫做“间隙(GAP)”),InnoDB也会对这个间隙加锁,这种锁机制就是所谓的间隙锁(next-key锁)。

锁定某一行
begin;
select *from test_table where a=8 for update;
commit;

InnoDB 行锁状态
show status like ‘innodb_row_lock%’;

主从复制

①复制的基本原理
slave会从master读取binlog来进行数据同步
三步骤

②复制的基本原则
每个slave只有一个master
每个slave只能有一个唯一的服务器ID
每个master可以有多个salve

③复制的最大问题
延迟

④一主一从常见配置
mysql版本一致且后台以服务运行
主从都配置在mysqld节点下,都是小写
主机修改my.ini配置文件
1.必须主服务器唯一ID
server-id=1
2.必须启用二进制日志
log-bin=自己本地的路径/mysqlbin
3.可选启用错误日志
log-err=自己本地的路径/mysqlerr
4.可选根目录
basedir=“d:/devSoft/MysqlServer5.5/”
5.可选临时目录
tmpdir=“D:/devSoft/MysqlServer5.5/”
6.可选数据目录
datadir=“自己本地路径/Data/”
7.read-only=0,代表主机读写都可以
8.可选,设置不要复制的数据库,忽略复制的数据库
binlog-ignore-db=mysql
9.可选,设置需要复制的数据库
binlog-do-db=需要复制的主数据库名字

从机修改my.cnf配置文件
1.必须从服务器唯一ID
2.可选启用二进制日志

因修改过配置文件,请主机+从机都重启后台mysql服务
主机从机都关闭防火墙
service iptables stop

在windows主机上建立账户并授权slave
grant replication slave on . TO ‘zhangsan’@‘从机器数据库IP’ Identified by ‘123456’;
flush privileges;
查询master的状态,show master status;
记下file和position的值
执行完此步骤后不要再操作主服务器mysql,防止主服务器状态值变化

在Linux从机上配置需要复制的主机
change master to master_host=‘192.168.1.XX’,
master_user=‘zhangsan’,
master_password=‘123456’,
master_log_file=‘mysqlbin.具体数字’,master_log_pos=具体值;

启动从服务器复制功能:start slave;
show slave status;
Slave_IO_Running:Yes
Slave_SQL_Running:Yes
说明主从配置成功

如何停止从服务器复制功能:stop slave;

说明:本博文来自本人学习相关视频总结整理内容,转载请说明,有问题将追究相关责任。

你可能感兴趣的:(MySQL,主从复制)