mysql高级学习笔记

  1. 什么是索引?索引(index)

Mysql官方对索引的定义是:索引是帮助mysql高效获取数据的数据结构。所以,索引的本质是数据结构。

可以简单的理解为“排好序的快速查找数据结构”。

索引的目的在于提高查询效率,可以类比字典。

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

一般来说索引也很大,不可能全部存储在内存中,因此索引往往一索引文件的形式存在磁盘中。

Java中的默认索引都是B+树索引,除此之外,我们们常见的是hash索引。

索引的优势:

类似大学图书馆见书目索引,提高数据库检索效率,降低数据库的IO成本。

通过索引对数据进行排序,降低数据排序的成本,降低了CPU的消耗。

索引的劣势:

实际上索引也是一张表,该表保存了主键与索引字段,并且指向实体表的记录,所以索引也是要占用空间的。

索引虽然会提高检索效率,但是会减低更新标的速度,因为insert update、delete也会操作索引文件,会调整因为更新等操作带来的键值变化后的索引信息。

建议:一张表建立的索引最多不超过5个。(仅仅是建议)

Sql索引分类:

单值索引:一个索引只包含单个列,一个表可以有多个单列索引。

唯一索引:索引列的值必须唯一,但允许有空值。

复合索引:一个索引包含多个列

基本语法:

中括号代表可以省略,,唯一索引就加unique这个关键字,不是唯一索引就不加, columnname多个就是复合索引。
创建索引:
① Create [unique] index indexName on mytable(columnname(length));

② Alter mytable add [unique] index [indexName] on (columnName(length));

删除:drop index [indexName] on mytable;

查看: show index from table_name

四种方法添加数据库表的索引:ALTER的使用

ALTER TABLE tb_name ADD PRIMARY KEY (column_list);该语句添加一个主键,这意味着索引值必须是唯一的,且不能是空。

ALTER TABLE tb_name ADD UNIQUE index_name (column_list);这条语句创建的索引的值必须是惟一的(除了null外,null可能会出现多次)

ALTER TABLE tb_nameADD INDEX index_name(column_list); 添加普通索引。索引值可出现多次

ALTER TABLE tb_nameADD FULLTEXT index_name (column_list); 该语句指定了索引为FULLTEXT,用于全文索引。

Mysql的索引结构:(后三个了解即可)
1.BTree索引 java中mysql一般来说默认是BTree索引

  2. Hash索引

  3.full-text全文索引   

  4.R-Tree索引

一个bTree树的检索原理如下图:


mysql高级学习笔记_第1张图片
image.png

真实的数据存在于叶子结点

非叶子节点不存储真实数据,只存储指引搜索方向的数据项,例如17,35并不真实存在于数据表中。

哪些情况需要创建索引?

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

  2. 频繁作为查询条件的字段适合创建索引

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

  4. 频繁更新的字段不适合创建索引,因为在更新记录的同时还回去更新索引

  5. Where条件里用不到的字段不需要索引

  6. 单值索引和复合索引选择。。。。在高并发下倾向创建复合索引

  7. 查询中排序order by的字段,排序字段若通过索引去访问将大大提高排序速度。

  8. 查询中统计或者分组的字段groupby 分组必排序,所以跟order by相关

哪些情况不要建立索引:

  1. 表记录太少,没必要

  2. 经常增删改的表,因为索引也会随之变动

  3. 数据重复且分布平均的表字段,如果某个数据列有很多重复的内容,那没什么必要建立索引。例如性别、国籍等

Explain 是什么?查看执行计划!使用Explain关键字可以模拟优化器执行sql查询语句,从而知道mysql是如何处理你的sql语句的,分析你的查询语句或者是表结构的性能瓶颈。

Explain 怎么使用?Explain + sql 查看表的执行计划

Explain 能干嘛?可以了解到如下信息
1.表的读取顺序

2.数据读取操作的操作类型

3.哪些索引可以使用

4.哪些索引被实际使用

5.表之间的引用

6.每张表有多少行被优化器查询

执行计划包含信息:

表头信息:

| id| Select_type | table | partitions | type| Possible_keys| key| Key_len | ref | rows|filtered| Extra|

解释:

***Id:表示实际操作中加载表的顺序,可以相同或者不相同,相同从上往下依次加载执行,不相同id越大对应的表越先加载。‘’

Select_type:

常见的值有六个:

  1. SIMPLE:简单的select查询,查询中不包括子查询或者union

  2. PRIMARY:查询中若包含任何复杂的子查询,最外层的最后加载的标记为此

  3. SUBQUERY:在select或者where列表中包含了子查询

  4. DERIVED:在from列表中包含的子查询被标记为Derived(衍生),mysql会递归执行这些子查询,把结果放到临时表里。

  5. UNION:若第二个select出现在union之后,则被标记为union;若union包含在from子句的子查询中,外层select将被标记为derived

  6. UNION RESULT:从union表获取结果的select

Table:显示这行数据是关于那张表的。

***Type:访问类型排序

type可以有8种值,从最好到最坏的排序是

System>const>eq_ref>ref>range>index>all

All是全表扫描,百万级别以上必须优化,建立索引等等。

一般来说,得保证到达range和ref级别就可以了,至少range最好ref

System:表只有一行记录(等于系统表,基本不会出现)

Const:表示通过索引一次就找到了,用于比较主键索引或者唯一索引。因为只匹配一行数据,所以很快,mysql就能将该查询转换成一个常量

Eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或者唯一索引扫描。

Ref:非唯一性索引扫描。返回匹配某个单独值得所有行,本质也是一种索引访问,他返回所有匹配某个单独值得行,然而,他可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体。

Range:只检索给定范围的行,使用一个索引来选择行。Key列显示使用了那个索引,一般就是在你的where语句中出现了between、<、>、in等的查询这种范围扫描索引比全表扫描要好,因为他只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。

Index:index只遍历索引树,通常比ALL快,因为索引文件通常比数据文件小,也就是说all和index虽然都是读全表,但是index是从索引中读取的,而all是从硬盘中读取的。

Possible_keys和key

Possible_keys:显示可能应用到这张表中的索引,查询涉及到的字段上若存在索引,则列出,但不一定会实际使用。

***Key:实际运用的索引,如果是null,则是没有使用索引,如果查询中使用了覆盖索引,则该索引仅会出现在key列表中。

Key_len:表示索引中使用的字节数,计算查询中索引的长度,在不损失精度的情况下,越小越好,此值现实的是索引字段的最大可能长度,不是实际使用长度,。

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

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

***Extra:包含不适合在其他列中显示,但是又十分重要的额外信息。

Extra中可能有的值为:

  1. Using filesort:说明mysql会对数据使用一个外部索引排序,而不是按照表内的索引进行读取,mysql中无法利用索引完成的排序操作叫做“文件排序”。

**一般来说是因为建立一个col1_col2_col3的索引,查询时候没按照索引的顺序order by .mysql自己在内部重新生成一个排序,这样效率会慢,出现filesort尽快优化。

  1. Using temporary:使用了临时表保存中间结果,mysql在对查询结果排序是使用了临, 时表。

一般来说,原因是order by排序或者分组查询group by时候没有按照索引走。

使用了临时表,更加严重影响效率,出现必优化。

  1. Using index : 表示相应的select操作中使用了覆盖索引,避免访问表的数据行,效率不错!如果同时出现using where,表示索引被用来执行索引键值的查找,如果没有同事出现usingwhere 表示索引用来读取数据而非执行查找动作。

覆盖索引:select的数据列只从索引中就能获得,不必读取数据行,mysql可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说就是查询列要被所建立的索引覆盖。

Join语句的优化:

1.尽可能减少join语句中的NestedLoop的循环次数;永远用小的结果集驱动打的结果集。

2.优先优化NestedLoop的内层循环

3.保证join语句中被驱动表上的join条件字段已经被索引

4.当无法保证被驱动表的join条件字段被所以你且内存资源充足的前提下,不要太吝啬joinbuffer的设置。

**最佳左前缀法则:如果索引有多列,查询要从弄缩印的最左前列开始并且不能跳过索引中间的列。

**不要在索引列上做任何操作(计算、函数、类型转换),会导致索引失效而转向全表扫描。

** 存储引擎不能使用索引中范围条件右边的列。(范围之后索引全失效)

**尽量使用覆盖索引,脂肪纹索引的查询,索引列和查询列一致,减少select *

**mysql在使用!=或者<>不等于的时候无法使用索引导致全表扫描。

**is null和is not null也无法使用索引。

Like以通配符开头(‘%abc...’)mysql索引会失效全表扫描。百分号like加在右边不会全表扫描,或者加左边加两边使用覆盖索引。

**字符串不加单引号索引失效

**少用or用它连接的时候也会导致索引失效

分析sql慢:

  1. 观察,至少跑一天,看看生产的慢sql的情况

  2. 开启慢sql查询日志,设置阈值,超过5秒就是慢sql,抓取出来

  3. Explain+慢sql分析

  4. Show profile

  5. 运维经理或者DBA进行sql数据库服务器的参数调优。

总结;

我们应该做的:

  1. 慢查询日志的开启并捕获慢sql

  2. Explain分析

  3. Show profile查询sql在mysql服务器里面的执行细节和生命周期情况

  4. Sql数据库服务器的参数调优

永远小表驱动大表

For(int i=1;i<5;i++){

For(int j=1;j<1000;i++){

//这种就是小表驱动大表,连接5次数据库,每次查询1000次,反之则连接1000次,然后每次查询5次。

}

}

当B表的数据集必须小于A表的数据集时候用in优于exists

Select * from A where id in (select id from B)

当A表的数据集小于B表的数据集时候用Exists优于in

Select * from A where exists (select 1 from B where B.id = A.id)****注意语法。

Order by满足两种情况会使用覆盖索引。Orderby 使用最佳佐前列,或者where+order by 满足最佳佐前列原则。否则fileSort文件排序效率低。

提高order by速度

  1. 禁止使用select *

  2. 增高大sort_buffer_size

  3. 增大max_length_for_sort_data

  4. Group by和orderby 一样,但是能在where限定的不要使用having

慢查询日志,mysql数据库默认不开启慢查询日志,需要调优才开启。

查询是否开启?show variables like ‘%slow_query_log%’;

如何开启?set global slow_query_log = 1;

日志分析工具mysqldumpslow的使用。

存储过程:

Delimiter

Declare 声明变量

创建函数 create function

Repeat 循环

Create Procedure 创建存储过程

Call 存储过程名,---调用存储过程

Show profile:

是什么?是mysql提供可以用来分析当前会话中语句执行的资源消耗情况。可以用于sql调优的测量。

  1. 查看当前mysql版本是否支持show variables like ‘profiling’;

  2. 设置开启 set profiling = ‘no’;

  3. 运行sql

  4. 查看结果show profiles;

  5. 诊断sql, show profile cpu,block io for query +上一步前面的问题sql数字号码

  6. 日常开发需要注意的结论:

① Converting Heap to myisam 查询结果太大,内存都不够了,往磁盘上搬了

② Creatingtmp table 创建临时表

③ Copingto tmp table on disk 把内存中临时表复制到磁盘!!!危险

④ Locked 锁了

表锁:偏向MYISAM存储引擎,开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低。

加锁语句:lock table table_name read, table2_name write;

给tablename加读锁,给table2_name加写锁。

解锁:unlock tables;

读锁:是共享锁,当session_1加读锁当前表之后,session_1只能读当前表,不能改当前表,也不能读其他表,session_2能读当前表和其他表,但是写当前表会进入阻塞状态,等待session_1对当前表进行解锁,然后完成修改。

总而言之:读锁会阻塞写操作,不会阻塞读操作,而写锁会阻塞读写操作。

Show open tables;查看那些表被锁了。

如何分析表锁:

Show status like ‘table%’;

Table_locks_immediate:产生表级锁定的次数,表示可以立即获取锁的查询次数,每次获取锁值加1;

Table_locks_waited:出现表级锁定争用而发生等待的次数,此值高则说明存在较严重的表级锁争用的情况

此外,myisam的读写锁调度是写优先,这也是myisam不适合做写为主表的引擎,因为写锁后,其他线程不能做任何操作,大量的更新会使查询很难得到锁,从而造成永远阻塞。

行锁:偏向innoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度最小,发生所冲突的概率最低,并发度也最高。

InnoDB与myisam最大的不同,一是支持事务;二是采用了行级锁。

并发事务带来的问题:

  1. 更新丢失:两个或多个事务选择同一行,基于原始值更新该行,因为不知道其他事务的存在,会导致最后的更新覆盖其他事物的更新。

  2. 脏读:事务A读到了事务B已修改但是还未提交的数据,还在这个基础上进行了操作,这时如果B回滚,A读取的数据无效,不符合一致性要求。

  3. 不可重复读:事务A读取到了事务B已经提交的修改数据,不符合隔离性。

  4. 幻读:事务A读取到了事务B提交的新增数据,不符合隔离性。

索引失效会导致行锁变表锁,例如varchar类型sql不带引号会导致索引失效,进而导致行锁变表锁。

间隙锁:当用一个范围条件检索数据的时候,innodb会给所有符合条件的索引项加锁,对于键值存在条件范围内但是并不存在的记录,也会锁定。

怎样给某条记录加锁,行锁!!!

Begin;

Select * from table where a = 8 for update;

Update table set b=1 where a=8;

Commit;

如何分析行锁show status like ‘innodb_row_lock%’;

mysql高级学习笔记_第2张图片
image.png

尽可能让所有的数据检索都通过索引完成,避免无索引行锁升级为表锁。

合理设计索引,尽量缩小锁的范围

尽可能较少检索条件,避免间隙锁

尽量控制事务大小,减少锁定资源量和时间长度

尽可能低级别事务隔离。

Mysql主从复制:

mysql高级学习笔记_第3张图片
image.png

主从复制的规则:

  1. 每个slave只有一个master

  2. 每个slave只能有一个唯一的服务器ID

  3. 每个master可以有多个slave

一主一从常见配置:

  1. mysql版本一致并且后台以服务运行,双方能ping通。

  2. 假如win为主机,linux为从机,则win修改my.ini文件,linux修改my.cnf文件

  3. 主从配置都在【mysqld】节点下,都是小写

  4. 主机修改my.ini文件

①.Server-id = 1 【必须】主服务器唯一ID

②.【必须】启用二进制日志文件,log-bin = 本地路径/data/mysqlbin

③.【可选】启用错误日志 log-err = 本地路径/data/mysqlerr

④.【可选】根目录 ;basedir= 本地路径

⑤.【可选】临时目录; tmpdir = 本地路径

⑥.【可选】数据目录;datadir = 本地路径/Data/

⑦.Read-only = 0 代表主机读、写都可以

⑧.【可选】设置不要复制的数据库 binlog-ignore-db = mysql

⑨.【可选】设置需要复制的数据库 binlog-do-db = 需要复制的数据库名字

  1. 从机修改my.cnf文件 vim /etc/my.cnf

①.【必须】从服务器唯一ID server-id=1注释掉 server-id = 2 打开注释

②.【可选】启用二进制日志 数据库服务重启

  1. 主从都关闭防火墙 service iptables stop

  2. 在win主机上建立账户并授权slave

执行Grant replication slave on . to ‘zhangsan’@’从机数据库ip’identified by ‘123456’;

授权从机ip以zhangsan用户名123456密码访问主机

之后刷新

Flush privileges;

查看主机状态:

Show master status;

记录下前两个数据参数filename和position

  1. 在linux从机上配置需要复制的主机

①.执行CHANGE MASTER TO MASTER_HOST=’主机ip’,

MASTER_USER=’zhangsan’,MASTER_PASSWORD=’123456’,

MASTER_LOG_FILE=’FILE名字’,

MASTER_LOG_POS=Position的数字;

②.启动主从复制功能 start slave;

③.Show slave status\G; \G是竖向显示的意思 下面两个参数都是yes说明主从复制配置成功

Slave_io_running:yes

Slave_sql_running:yes

如何停止从机复制功能:stop slave;

你可能感兴趣的:(mysql高级学习笔记)