您的当前位置:首页正文

MySQL算法简析_MySQL

2023-11-20 来源:爱上美食网

bitsCN.comMySQL算法简析 在MySQL 中,只有一种Join 算法,就是大名鼎鼎的Nested Loop Join,他没有其他很多数据库所提供的Hash Join,也没有Sort Merge Join。顾名思义,Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果还有第三个参与Join,则再通过前两个表的Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复。MySQL 目前可以通过两种算法来实现数据的排序操作。 1. 取出满足过滤条件的用于排序条件的字段以及可以直接定位到行数据的行指针信息,在SortBuffer 中进行实际的排序操作,然后利用排好序之后的数据根据行指针信息返回表中取得客户端请求的其他字段的数据,再返回给客户端;2. 根据过滤条件一次取出排序字段以及客户端请求的所有其他字段的数据,并将不需要排序的字段存放在一块内存区域中,然后在Sort Buffer 中将排序字段和行指针信息进行排序,最后再利用排序后的行指针与存放在内存区域中和其他字段一起的行指针信息进行匹配合并结果集,再按照顺序返回给客户端。 加大max_length_for_sort_data 参数的设置;在MySQL 中,决定使用第一种老式的排序算法还是新的改进算法的依据是通过参数max_length_for_sort_data 来决定的。当我们所有返回字段的最大长度小于这个参数值的时候,MySQL 就会选择改进后的排序算法,反之,则选择老式的算法。所以,如果我们有充足的内存让MySQL 存放需要返回的非排序字段的时候,可以加大这个参数的值来让MySQL 选择使用改进版的排序算法。 作者 bengdabitsCN.com

小编还为您整理了以下内容,可能对您也有帮助:

MySQL简单介绍——换个角度认识MySQL

1、InnoDB存储引擎

Mysql版本>=5.5 默认的存储引擎,MySQL推荐使用的存储引擎。支持事务,行级锁定,外键约束。事务安全型存储引擎。更加注重数据的完整性和安全性。

存储格式 : 数据,索引集中存储,存储于同一个表空间文件中。

InnoDB的行锁模式及其加锁方法: InnoDB中有以下两种类型的行锁:共享锁(读锁: 允许事务对一条行数据进行读取)和 互斥锁(写锁: 允许事务对一条行数据进行删除或更新), 对于update,insert,delete语句,InnoDB会自动给设计的数据集加互斥锁,对于普通的select语句,InnoDB不会加任何锁。

InnoDB行锁的实现方式: InnoDB行锁是通过给索引上的索引项加锁来实现的,如果没有索引,InnoDB将通过隐藏的聚簇索引来对记录加锁。InnoDB这种行锁实现特点意味着:如果不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,实际效果跟表锁一样。

(1)在不通过索引条件查询时,InnoDB会锁定表中的所有记录。

(2)Mysql的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果使用相同的索引键,是会出现冲突的。

(3)当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,但都是通过行锁来对数据加锁。

优点:

1、支持事务处理、ACID事务特性;

2、实现了SQL标准的四种隔离级别( 原子性( Atomicity )、一致性( Consistency )、隔离性(Isolation )和持续性(Durability ));

3、支持行级锁和外键约束;

4、可以利用事务日志进行数据恢复。

5、锁级别为行锁,行锁优点是适用于高并发的频繁表修改,高并发是性能优于 MyISAM。缺点是系统消耗较大。

6、索引不仅缓存自身,也缓存数据,相比 MyISAM 需要更大的内存。

缺点:

因为它没有保存表的行数,当使用COUNT统计时会扫描全表。

使用场景:

(1)可靠性要求比较高,或者要求事务;(2)表更新和查询都相当的频繁,并且表锁定的机会比较大的情况。

2、 MyISAM存储引擎

MySQL<= 5.5 MySQL默认的存储引擎。ISAM:Indexed Sequential Access Method(索引顺序存取方法)的缩写,是一种文件系统。擅长与处理,高速读与写。

功能:

(1)支持数据压缩存储,但压缩后的表变成了只读表,不可写;如果需要更新数据,则需要先解压后更新。

(2)支持表级锁定,不支持高并发;

(3)支持并发插入。写操作中的插入操作,不会阻塞读操作(其他操作);

优点:

1.高性能读取;

2.因为它保存了表的行数,当使用COUNT统计时不会扫描全表;

缺点:

1、锁级别为表锁,表锁优点是开销小,加锁快;缺点是锁粒度大,发生锁冲动概率较高,容纳并发能力低,这个引擎适合查询为主的业务。

2、此引擎不支持事务,也不支持外键。

3、INSERT和UPDATE操作需要锁定整个表;

使用场景:

(1)做很多count 的计算;(2)插入不频繁,查询非常频繁;(3)没有事务。

InnoDB和MyISAM一些细节上的差别:

1、InnoDB不支持FULLTEXT类型的索引,MySQL5.6之后已经支持(实验性)。

2、InnoDB中不保存表的 具体行数,也就是说,执行select count() from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含 where条件时,两种表的操作是一样的。

3、对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。

4、DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。

5、LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

6、另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表。

1.索引概述

利用关键字,就是记录的部分数据(某个字段,某些字段,某个字段的一部分),建立与记录位置的对应关系,就是索引。索引的关键字一定是排序的。索引本质上是表字段的有序子集,它是提高查询速度最有效的方法。一个没有建立任何索引的表,就相当于一本没有目录的书,在每次查询时就会进行全表扫描,这样会导致查询效率极低、速度也极慢。如果建立索引,那么就好比一本添加的目录,通过目录的指引,迅速翻阅到指定的章节,提升的查询性能,节约了查询资源。

2.索引种类

从索引的定义方式和用途中来看:主键索引,唯一索引,普通索引,全文索引。

无论任何类型,都是通过建立关键字与位置的对应关系来实现的。索引是通过关键字找对应的记录的地址。

以上类型的差异:对索引关键字的要求不同。

关键字:记录的部分数据(某个字段,某些字段,某个字段的一部分)。

普通索引,index:对关键字没有要求。

唯一索引,unique index:要求关键字不能重复。同时增加唯一约束。

主键索引,primary key:要求关键字不能重复,也不能为NULL。同时增加主键约束。

全文索引,fulltext key:关键字的来源不是所有字段的数据,而是从字段中提取的特别关键词。

PS:这里主键索引和唯一索引的区别在于:主键索引不能为空值,唯一索引允许空值;主键索引在一张表内只能创建一个,唯一索引可以创建多个。主键索引肯定是唯一索引,但唯一索引不一定是主键索引。

3.索引原则

如果索引不遵循使用原则,则可能导致索引无效。

(1)列

如果需要某个字段上使用索引,则需要在字段参与的表达中,保证字段在一侧。否则索引不会用到索引, 例如这条sql就不会用到索引:select * from A where id+1=10;

(2)左原则

Like:匹配模式必须要左边确定不能以通配符开头。例如:select * from A where name like '%小明%' ,不会用到索引,而select * from A where name like '小明%' 就可以用到索引(name字段有建立索引),如果业务上需要用到'%小明%'这种方式,有两种方法:1.可以考虑全文索引,但mysql的全文索引不支持中文;2.只查询索引列或主键列,例如:select name from A where name like '%小明%' 或 select id from A where name like '%小明%' 或 select id,name from A where name like '%小明%' 这三种情况都会用到name的索引;

复合索引:一个索引关联多个字段,仅仅针对左边字段有效果,添加复合索引时,第一个字段很重要,只有包含第一个字段作为查询条件的情况才会使用复合索引(必须用到建索引时选择的第一个字段作为查询条件,其他字段的顺序无关),而且查询条件只能出现and拼接,不能用or,否则则无法使用索引.

(3)OR的使用

必须要保证 OR 两端的条件都存在可以用的索引,该查询才可以使用索引。

(4)MySQL智能选择

即使满足了上面说原则,MySQL也能弃用索引,例如:select * from A where id > 1;这里弃用索引的主要原因:查询即使使用索引,会导致出现大量的随机IO,相对于从数据记录的第一条遍历到最后一条的顺序IO开销,还要大。

4.索引的使用场景

(1)索引检索:检索数据时使用索引。

(2)索引排序: 如果order by 排序需要的字段上存在索引,则可能使用到索引。

(3)索引覆盖: 索引拥有的关键字内容,覆盖了查询所需要的全部数据,此时,就不需要在数据区获取数据,仅仅在索引区即可。覆盖就是直接在索引区获取内容,而不需要在数据区获取。例如: select name from A where name like '小明%';

建立索引索引时,不能仅仅考虑where检索,同时考虑其他的使用场景。(在所有的where字段上增加索引,就是不合理的)

5.前缀索引

前缀索引是建立索引关键字一种方案。通常会使用字段的整体作为索引关键字。有时,即使使用字段前部分数据,也可以去识别某些记录。就比如一个班级里,我要找王xx,假如姓王的只有1个人,那么就可以建一个关键字为'王'的前缀索引。语法:Index `index_name` (`index_field`(N))使用index_name前N个字符建立的索引。

6.索引失效

(1) 应尽量避免在 where 子句中使用 != 或 > 操作符,否则将引擎放弃使用索引而进行全表扫描;

(2) 应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描;

(3) 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描;

(4)应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描;如select id from t where num/2 = 100;

(5) 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描;如:select id from t where substring(name,1,3) = ’abc’ ;

(6)应尽量避免在where子句中对字段进行类型转换,这将导致引擎放弃使用索引而进行全表扫描; 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,如select id from t where id = 1;如果id字段在表设计中是varchar类型,那么即使id列上存的是数字,在查询时也一定要用varchar去匹配,sql应改为select id from t where id = '1';

(7)应尽量避免在where子句中单独引用复合索引里非第一位置的索引;

join 的两种算法:BNL 和 NLJ

NLJ(Nested Loop Join)嵌套循环算法;以如下 SQL 为例:

select * from t1 join t2 on t1.a=t2.a

SQL 执行时内部流程是这样的:

1. 先从 t1(假设这里 t1 被选为驱动表)中取出一行数据 X;

2. 从 X 中取出关联字段 a 值,去 t2 中进行查找,满足条件的行取出;

3. 重复1、2步骤,直到表 t1 最后一行循环结束。

这就是一个嵌套循环的过程,如果在被驱动表上查找数据时可以使用索引,总的对比计算次数等于驱动表满足 where 条件的行数。假设这里 t1、t2都是1万行,则只需要 1万次计算,这里用到的是Index Nested-Loops Join(INLJ,基于索引的嵌套循环联接)。

如果 t1、t2 的 a 字段都没有索引,还按照上述的嵌套循环流程查找数据呢?每次在被驱动表上查找数据时都是一次全表扫描,要做1万次全表扫描,扫描行数等于 1万+1万*1万,这个效率很低,如果表行数更多,扫描行数动辄几百亿,所以优化器肯定不会使用这样的算法,而是选择 BNL 算法;

BNLJ(Block Nested Loop Join)块嵌套循环算法;

1. 把 t1 表(假设这里 t1 被选为驱动表)满足条件的数据全部取出放到线程的 join buffer 中;

2. 每次取 t2 表一行数据,去 joinbuffer 中进行查找,满足条件的行取出,直到表 t2 最后一行循环结束。

这个算法下,执行计划的 Extra 中会出现 Using join buffer(Block Nested Loop),t1、t2 都做了一次全表扫描,总的扫描行数等于 1万+1万。但是由于 joinbuffer 维护的是一个无序数组,每次在 joinbuffer 中查找都要遍历所有行,总的内存计算次数等于1万*1万。另外如果 joinbuffer 不够大放不下驱动表的数据,则要分多次执行上面的流程,会导致被驱动表也做多次全表扫描。

BNLJ相对于NLJ的优点在于,驱动层可以先将部分数据加载进buffer,这种方法的直接影响就是将大大减少内层循环的次数,提高join的效率。

例如:

如果内层循环有100条记录,外层循环也有100条记录,这样的话,每次外层循环先将10条记录放到buffer中,内层循环的100条记录每条与这个buffer中的10条记录进行匹配,只需要匹配内层循环总记录数次即可结束一次循环(在这里,即只需要匹配100次即可结束),然后将匹配成功的记录连接后放入结果集中,接着,外层循环继续向buffer中放入10条记录,同理进行匹配,并将成功的记录连接后放入结果集。后续循环以此类推,直到循环结束,将结果集发给client为止。

可以发现,若用NLJ,则需要100 * 100次才可结束,BNLJ则需要100 / block_size * 100 = 10 * 100次就可结束,大大减少了循环次数。

JOIN 按照功能大致分为如下三类:

JOIN、STRAIGHT_JOIN、INNER JOIN(内连接,或等值连接):取得两个表中存在连接匹配关系的记录。

LEFT JOIN(左连接):取得左表(table1)完全记录,即是右表(table2)并无对应匹配记录。

RIGHT JOIN(右连接):与 LEFT JOIN 相反,取得右表(table2)完全记录,即是左表(table1)并无匹配对应记录。

注意:mysql不支持Full join,不过可以通过UNION 关键字来合并 LEFT JOIN 与 RIGHT JOIN来模拟FULL join。

mysql 多表连接查询方式,因为mysql只支持NLJ算法,所以如果是小表驱动大表则效率更高;反之则效率下降;因此mysql对内连接或等值连接的方式做了一个优化,会去判断join表的数据行大小,然后取数据行小的表为驱动表。

INNER JOIN、JOIN、WHERE等值连接和STRAIGHT_JOIN都能表示内连接,那平时如何选择呢?一般情况下用INNER JOIN、JOIN或者WHERE等值连接,因为MySQL 会按照"小表驱动大表的策略"进行优化。当出现需要排序时,才考虑用STRAIGHT_JOIN指定某张表为驱动表。

两表JOIN优化

a.当无order by条件时,根据实际情况,使用left/right/inner join即可,根据explain优化 ;

b.当有order by条件时,如select * from a inner join b where 1=1 and other condition order by a.col;使用explain解释语句;

1)如果第一行的驱动表为a,则效率会非常高,无需优化;

2)否则,因为只能对驱动表字段直接排序的缘故,会出现using temporary,所以此时需要使用STRAIGHT_JOIN明确a为驱动表,来达到使用a.col上index的优化目的;或者使用left join且Where条件中不含b的过滤条件,此时的结果集为a的全集,而STRAIGHT_JOIN为inner join且使用a作为驱动表。注:使用STRAIGHT_JOIN虽然不会using temporary,但也不是一定就能提高效率,如果a表数据远远超过b表,那么有可能使用STRAIGHT_JOIN时比原来的sql效率更低,所以怎么使用STRAIGHT_JOIN,还是要视情况而定。

在使用left join(或right join)时,应该清楚的知道以下几点:

(1). on与 where的执行顺序

ON 条件(“A LEFT JOIN B ON 条件表达式”中的ON)用来决定如何从 B 表中检索数据行。如果 B 表中没有任何一行数据匹配 ON 的条件,将会额外生成一行所有列为 NULL 的数据,在匹配阶段 WHERE 子句的条件都不会被使用。仅在匹配阶段完成以后,WHERE 子句条件才会被使用。它将从匹配阶段产生的数据中检索过滤。

所以我们要注意:在使用Left (right) join的时候,一定要在先给出尽可能多的匹配满足条件,减少Where的执行。

(2).注意ON 子句和 WHERE 子句的不同

即使右表的数据不满足ON后面的条件,也会在结果集拼接一条为NULL的数据行,但WHERE后面的条件不一样,右表不满足WHERE的条件,左表关联的数据也会被过滤掉。

(3).尽量避免子查询,而用join

往往性能这玩意儿,更多时候体现在数据量比较大的时候,此时,我们应该避免复杂的子查询。

(1)in 和 not in 要慎用,如:select id from t where num in(1,2,3)对于连续的数值,能用 between 就不要用 in:select id from t where num between 1 and 3很多时候用 exists 代替 in 是一个好的选择:select num from a where num in(select num from b)用下面的语句替换:select num from a where exists(select 1 from b where num=a.num)

(2)Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志。

(3)join语句,MySQL里面的join是用小表去驱动大表,而由于MySQL join实现的原理就是做循环,比如left join就是对左边的数据进行循环去驱动右边的表,左边有m条记录匹配,右边有n条记录那么就是做m次循环,每次扫描n行数据,总扫面行数是m*n行数据。左边返回的结果集的大小就决定了循环的次数,故单纯的用小表去驱动大表不一定的正确的,小表的结果集可能也大于大表的结果集,所以写join的时候尽可能的先估计两张表的可能结果集,用小结果集去驱动大结果集.值得注意的是在使用left/right join的时候,从表的条件应写在on之后,主表应写在where之后.否则MySQL会当作普通的连表查询;

(4)select count(*) from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是一定要杜绝的;

(5)select * from t 这种语句要尽量避免,使用具体的字段代替*,更有实际意义,需要什么字段就返回什么字段;

(6)数据量大的情况下,limit要慎用,因为使用limit m,n方式分页时,mysql每次都是查询前m+n条,然后舍弃前m条,所以m越大,偏移量越大,性能就越差。比如:select * from A limit 1000000,20这钟,查询效率就会非常低,当分页的页数大于一定的数量之后,就可以换种方式来分页:select * from A a join (select id from A limit 1000000,20) b on a.id=b.id;

mysql 联接查询算法之Block Nested-Loop Join(BNL) 二

扫描一个表的过程其实是先把这个表从磁盘上加载到内存中,然后从内存中比较匹配条件是否满足。但内存里可能并不能完全存放的下表中所有的记录,所以在扫描表前边记录的时候后边的记录可能还在磁盘上,等扫描到后边记录的时候可能内存不足,所以需要把前边的记录从内存中释放掉。我们前边又说过,采用SNLJ 算法的两表联接过程中, 被驱动表可是要被访问好多次的 。被驱动表具体的访问次数就是由驱动表返回结果集记录数决定!如果这个被驱动表中的数据特别多而且不能使用索引进行访问,那就相当于要从磁盘上读好几次这个表,这个I/O代价就非常大了,所以我们得想办法:

当被驱动表中的数据非常多时,每次访问被驱动表,被驱动表的记录会被加载到内存中,在内存中的每一条记录只会和驱动表结果集的一条记录做匹配,之后就会被从内存中清除掉。然后再从驱动表结果集中拿出另一条记录,再一次把被驱动表的记录加载到内存中一遍,周而复始,驱动表结果集中有多少条记录,就得把被驱动表从磁盘上加载到内存中多少次。

也就是说在有索引的情况下,MySQL会尝试去使用Index Nested-Loop Join算法,在有些情况下,可能Join的列就是没有索引,那么这时MySQL的选择绝对不会是最先介绍的Simple Nested-Loop Join算法,SNLJ算法是最慢的join,毕竟是笛卡尔积!

而Block Nested-Loop Join算法较Simple Nested-Loop Join的改进就在于可以减少内表的扫描次数,甚至可以和Hash Join算法一样,仅需扫描内表一次。其使用Join Buffer(联接缓冲)来减少内部循环读取表的次数。

关于 join buffer https://www.jianshu.com/p/3c0816862cc9

可以看到相比Simple Nested-Loop Join算法,Block Nested-LoopJoin算法仅多了一个所谓的Join Buffer,为什么这样就能减少内表的扫描次数呢?下图相比更好地解释了Block Nested-Loop Join算法的运行过程:

可以看到Join Buffer用以缓存联接需要的列(所以再次提醒我们,最好不要把*作为查询列表,只需要把我们关心的列放到查询列表就好了,这样还可以在join buffer中放置更多的记录呢),然后以Join Buffer批量的形式和内表中的数据进行联接比较。就上图来看,记录r1,r2 … rT的联接仅需扫内表一次,如果join buffer可以缓存所有的外表列,那么联接仅需扫描内外表各一次,从而大幅提升Join的性能。

Block Nested-Loop Join开销

Block Nested-Loop Join极大的避免了内表的扫描次数,如果Join Buffer可以缓存外表的数据,那么内表的扫描仅需一次,这和Hash Join非常类似。但是Block Nested-Loop Join依然没有解决的是Join比较的次数,其仍然通过Join判断式进行比较。综上所述,到目前为止各Join算法的成本比较如下所示:

Block Nested-Loop Join影响

在使用 Block Nested-Loop Join(BNL) 算法时,还是可能会对被驱动表做多次扫描(尽管可能已经将驱动表中大部分关联字段数据存入join buffer)。如果这个被驱动表是一个大的冷数据表,除了会导致 IO 压力大以外,还会对 buffer pool产生严重的影响!

如果了解 InnoDB 的 LRU 算法就会知道,由于 InnoDB 对 Bufffer Pool 的 LRU 算法做了优化,即:第一次从磁盘读入内存的数据页,会先放在 old 区域。如果 1 秒之后这个数据页不再被访问了,就不会被移动到 LRU 链表头部,这样对 Buffer Pool 的命中率影响就不大。

但是,如果一个使用 BNL 算法的 join 语句,多次扫描一个冷表,而且这个语句执行时间超过 1 秒,就会在再次扫描冷表的时候,把冷表的数据页移到 LRU 链表头部。这种情况对应的,是冷表的数据量小于整个 Buffer Pool 的 3/8,能够完全放入 old 区域的情况。如果这个冷表很大,就会出现另外一种情况:业务正常访问的数据页,没有机会进入 young 区域。(导致正常业务sql查询因为没有剩余buffer pool空间进一步让磁盘IO变多而变得缓慢)

由于优化机制的存在,一个正常访问的数据页,要进入 young 区域,需要隔 1 秒后再次被访问到。但是,由于我们的 join 语句在循环读磁盘和淘汰内存页,进入 old 区域的数据页,很可能在 1 秒之内就被淘汰了。这样,就会导致这个 MySQL 实例的 Buffer Pool 在这段时间内,young 区域的数据页没有被合理地淘汰。

也就是说,这两种情况都会影响 Buffer Pool 的正常运作。 大表 join 操作虽然对 IO 有影响,但是在语句执行结束后,对 IO 的影响也就结束了。但是,对 Buffer Pool 的影响就是持续性的,需要依靠后续的查询请求慢慢恢复内存命中率。

为了减少这种影响,你可以考虑增大 join_buffer_size 的值,减少对被驱动表的扫描次数!

也就是说,BNL 算法对系统的影响主要包括三个方面: 可能会多次扫描被驱动表,占用磁盘 IO 资源; 判断 join 条件需要执行 M*N 次对比(M、N 分别是两张表的行数),如果是大表就会占用非常多的 CPU 资源; 可能会导致 Buffer Pool 的热数据被淘汰,影响内存命中率。

那么假设被驱动表全在内存中,这个时候 SNLJ 和 BNL 算法还有性能差别吗?当然是有的,由于 SNLJ 这个算法天然会对被驱动表的数据做多次访问,所以更容易将这些数据页放到 Buffer Pool 的头部,从而污染 Buffer Pool。另外,即使被驱动表数据都在内存中,但每次查找“下一个记录的操作”,都是类似指针操作。而 BNL 算法中的 join_buffer 是数组,遍历的成本更低,从被驱动表读取一条数据去 join_buffer 中遍历。

BNL的相关设置

mysql默认开启BNL

开关BNL

1、 缓存块嵌套循环连接通过一次性缓存多条数据,把参与查询的列缓存到Join Buffer 里,然后拿join buffer里的数据批量与内层表的数据进行匹配,从而减少了内层循环的次数、减少了内部表访问次数(遍历一次内层表就可以批量匹配一次Join Buffer里面的外层表数据)。

2、什么时候会使用BNL? 当内表关联字段上没有索引时,不使用Index Nested-Loop Join的时候,默认使用Block Nested-Loop Join。

3、join buffer的相关概念:

待续。。。。。

4、使用Block Nested-Loop Join算法需要开启优化器管理配置的optimizer_switch的设置block_nested_loop为on,默认为开启。

MySQL 查询优化(六): MySQL 的查询优化排序优化机制

对结果进行排序操作的代价可能很高,因此可以通过避免排序或让参与排序的数据行更少来优化查询性能。

当 MySQL 不能使用索引产生有序结果时,它必须对数据行进行排序。这有可能是在内存中进行也可能是在磁盘进行,但 MySQL 始终将这个过程称之为 filesort,即便实际上并没有使用一个文件。

如果用于排序的值可以一次性放入排序缓存中,MySQL 可以在内存中使用快排算法进行排序。如果 MySQL 不能在内存中进行排序,则会在磁盘中按块逐块排序。它对每个块使用快排算法,然后在将这些排序好的块合并到结果中。

有两个文件排序(filesort)算法:

很难说哪种算法更有效,对每个算法来说都会有最优和最坏案例。MySQL 在数据表全部列加上用于排序的列的大小不超过 max_length_for_sort_data 时会使用单次遍历算法。可以通过修改这个参数影响排序算法的选择。

需要注意的是,MySQL 的 filesort使用的临时存储空间可能会超出你的预期,这是因为它对每个排序元素都分配了固定大小的存储空间。这些存储空间要足够大以便容下存储最大的元素,而且 VARCHAR这类字段使用的是对应的最大长度。而且,如果使用的是 UTF-8字符集,MuSQL 会对每个字符分配3个字节。结果是,我们会发现那些没怎么优化的查询会导致磁盘上的临时存储空间是数据表自身存储空间的好几倍。

而在对联合查询进行排序时,MySQL 可能会在查询执行过程中执行两次文件排序。如果 ORDER BY 子句只是引用联合查询的第一张表,MySQL 可以先对这个表进行文件排序,然后再处理联合查询。如果是这种情况,在 EXPLAIN 时会在 Extra 字段显示“Using filesort”。而对于其他的排序情况——例如排序不是针对第一张表,或者是 ORDER BY 使用的列对应了不止一个数据表,MySQL 必须使用临时表缓存查询结果,然而在联合查询完成后,再对临时表进行文件排序。在这种情况下,EXPLAIN 会在 Extra 字段显示“Using temorary; Using filesort”。如果包含 LIMIT 约束的话,会发生在文件排序后,因此临时表和文件排序的存储空间可能非常大。

MySQL 5.6在只需要对数据行的子集(例如 LIMIT)进行排序时,引入了一个重大改进。相对于对整个结果集进行排序再返回部分数据,MySQL 有时候会在排序的时候直接丢弃掉不需要的数据行来提高效率。不管怎么样,排序也需要小心使用,很可能会导致存储占用的飙升最终导致系统负荷过大。

mysql关系型标准查询算法有哪些

技术分享图片

 

技术分享图片

连接查询:select table_b.type,table_b.title,table_b.content,table_b.author from table_a left join table_b on table_a.type = table_b.type where table_a.id = 1;

子查询:   select type,title,content,author from table_b WHERE type = (SELECT type from table_a WHERE id = 1);

如果一个id对应多个type,则用 select type,title,content,author from table_b WHERE type in (SELECT type from table_a WHERE id = 1);

结果如下:

技术分享图片

采用最普通的查询(不采用关系表或中间表的形式),也可以得到相同的效果,如下:

SELECT * from table_b WHERE type = ‘a‘;

那为什么还要花费如此大的力气去建立一个关系表呢?

这两种方式的不同点在于,第二种直接在详情表中查询所有为a类的记录;而第一种则是通过参数id获取到a类别,再到详情表获取所有a类的记录

我个人认为原因可能有:1、加入关系表或中间表,能让数据间的关系更加明确;2、前端传递过来的是一个id参数,后台只通过此id参数去进行一系列的查询,一定程度上保证了数据的安全性。

 

MySQL查询之关系查询

标签:一个   关系   tle   连接查询   mysq   ima   直接   查询   mysql查询   

mysql关系型标准查询算法有哪些

技术分享图片

 

技术分享图片

连接查询:select table_b.type,table_b.title,table_b.content,table_b.author from table_a left join table_b on table_a.type = table_b.type where table_a.id = 1;

子查询:   select type,title,content,author from table_b WHERE type = (SELECT type from table_a WHERE id = 1);

如果一个id对应多个type,则用 select type,title,content,author from table_b WHERE type in (SELECT type from table_a WHERE id = 1);

结果如下:

技术分享图片

采用最普通的查询(不采用关系表或中间表的形式),也可以得到相同的效果,如下:

SELECT * from table_b WHERE type = ‘a‘;

那为什么还要花费如此大的力气去建立一个关系表呢?

这两种方式的不同点在于,第二种直接在详情表中查询所有为a类的记录;而第一种则是通过参数id获取到a类别,再到详情表获取所有a类的记录

我个人认为原因可能有:1、加入关系表或中间表,能让数据间的关系更加明确;2、前端传递过来的是一个id参数,后台只通过此id参数去进行一系列的查询,一定程度上保证了数据的安全性。

 

MySQL查询之关系查询

标签:一个   关系   tle   连接查询   mysq   ima   直接   查询   mysql查询   

MySQL中innodb的行锁算法

众所周知,innodb是默认行锁,当然也支持表锁。如下是对于行锁的算法进行的一些实验。

锁的算法为:我知道是行锁,但是是如何锁的,锁多少数据

假如有个索引是:[1,2,3,7]
record lock 锁的是 1,2,3,7
gap lock 锁的是 (- ,1),(2,3),(3,7),(7,+ )反正锁的就是区间,不是行
next-key lock锁的是 (- ,1],[2,3),[3,7),[ 7,+ )既锁范围也锁行

Innodb锁算法规则如下:

在可重复读隔离级别下,innodb默认使用的是next-key lock算法,当查询的索引是主键或者唯一索引的情况下,才会退化为record lock,在使用next-key lock算法时,不仅仅会锁住范围,还会给范围最后的一个键值加一个gap lock。

其中lockmode中的X锁为左边会话中的锁,因为需要显式的commit之后才会释放锁,第二个S锁,为右边的共享锁,因为主键ID为1的已经被锁住了,所以处于锁等待状态,锁的类型为record lock

使用辅助索引a=8进行操作,这个时候理论应该对主键索引加record lock 则 主键ID=8的被锁,然后辅助索引被加next-key lock 则为:
(7,8] 然后对下一个键值加gap锁,则为:(8,11)
所以目前被锁住的记录为:
1.主键为8的被锁
2.辅助索引8的被锁
3.辅助索引8到11之间的被锁,意味着你这个时候往8到11之间写数据会报错

当使用范围条件进行更新时,此时肯定是需要加X锁的,我是用的也是主键,所以按照理论应该是加的record lock ,但是却加了gap lock,因为插入值为10的阻塞了,查看information 也提示X.GAP
这个有点晕为啥主键变成了next-key lock ,不应该是record lock么?
update20200515
在知乎看到的一个解释:

即,在无论使用主键索引还是非主键索引的时候,请求共享锁或者排他锁,innodb会给范围内的记录加锁,而范围内的间隙也会被加锁,
例如一个表t 的 id为1,2,3,7,10
假如执行如下:
select * from t where id >=3 for update
那么这个时候执行
insert into t(id) values(8) 会被阻塞,因为是在请求排他锁时使用了范围,所以[3,10],甚至10以后的任何数据都无法插入。
执行
select * from t where id >=3 lock in share mode
insert into t(id) values(8) 会被阻塞,因为是在请求共享锁时使用了范围,所以[3,10],甚至10以后的任何数据都无法插入。

幻读是同一事务下,连续执行两次同样的sql可能导致不同的结果,第二次返回的数据可能导致以前不存在的行。
同时一般会问它和脏读的区别,脏读为读取到其他事务未提交的数据,但是幻读是读取的其他事务已经提交的数据。

reference:

MySQL中innodb的行锁算法

众所周知,innodb是默认行锁,当然也支持表锁。如下是对于行锁的算法进行的一些实验。

锁的算法为:我知道是行锁,但是是如何锁的,锁多少数据

假如有个索引是:[1,2,3,7]
record lock 锁的是 1,2,3,7
gap lock 锁的是 (- ,1),(2,3),(3,7),(7,+ )反正锁的就是区间,不是行
next-key lock锁的是 (- ,1],[2,3),[3,7),[ 7,+ )既锁范围也锁行

Innodb锁算法规则如下:

在可重复读隔离级别下,innodb默认使用的是next-key lock算法,当查询的索引是主键或者唯一索引的情况下,才会退化为record lock,在使用next-key lock算法时,不仅仅会锁住范围,还会给范围最后的一个键值加一个gap lock。

其中lockmode中的X锁为左边会话中的锁,因为需要显式的commit之后才会释放锁,第二个S锁,为右边的共享锁,因为主键ID为1的已经被锁住了,所以处于锁等待状态,锁的类型为record lock

使用辅助索引a=8进行操作,这个时候理论应该对主键索引加record lock 则 主键ID=8的被锁,然后辅助索引被加next-key lock 则为:
(7,8] 然后对下一个键值加gap锁,则为:(8,11)
所以目前被锁住的记录为:
1.主键为8的被锁
2.辅助索引8的被锁
3.辅助索引8到11之间的被锁,意味着你这个时候往8到11之间写数据会报错

当使用范围条件进行更新时,此时肯定是需要加X锁的,我是用的也是主键,所以按照理论应该是加的record lock ,但是却加了gap lock,因为插入值为10的阻塞了,查看information 也提示X.GAP
这个有点晕为啥主键变成了next-key lock ,不应该是record lock么?
update20200515
在知乎看到的一个解释:

即,在无论使用主键索引还是非主键索引的时候,请求共享锁或者排他锁,innodb会给范围内的记录加锁,而范围内的间隙也会被加锁,
例如一个表t 的 id为1,2,3,7,10
假如执行如下:
select * from t where id >=3 for update
那么这个时候执行
insert into t(id) values(8) 会被阻塞,因为是在请求排他锁时使用了范围,所以[3,10],甚至10以后的任何数据都无法插入。
执行
select * from t where id >=3 lock in share mode
insert into t(id) values(8) 会被阻塞,因为是在请求共享锁时使用了范围,所以[3,10],甚至10以后的任何数据都无法插入。

幻读是同一事务下,连续执行两次同样的sql可能导致不同的结果,第二次返回的数据可能导致以前不存在的行。
同时一般会问它和脏读的区别,脏读为读取到其他事务未提交的数据,但是幻读是读取的其他事务已经提交的数据。

reference:

详解一条sql语句在mysql中是如何执行的

概览

最近开始在学习mysql相关知识,自己根据学到的知识点,根据自己的理解整理分享出来,本篇文章会分析下一个sql语句在mysql中的执行流程,包括sql的查询在mysql内部会怎么流转,sql语句的更新是怎么完成的。

一、mysql架构分析

下面是mysql的一个简要架构图:

mysql主要分为Server层和存储引擎层

Server层:主要包括连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图,函数等,还有一个通用的日志模块 binglog日志模块。

存储引擎: 主要负责数据的存储和读取,采用可以替换的插件式架构,支持InnoDB、MyISAM、Memory等多个存储引擎,其中InnoDB引擎有自有的日志模块redolog 模块。

InnoDB 5.5.5版本作为默认引擎。

连接器

主要负责用户登录数据库,进行用户的身份认证,包括校验账户密码,权限等操作,如果用户账户密码已通过,连接器会到权限表中查询该用户的所有权限,之后在这个连接里的权限逻辑判断都是会依赖此时读取到的权限数据,也就是说,后续只要这个连接不断开,即时管理员修改了该用户的权限,该用户也是不受影响的。

查询缓存

连接建立后,执行查询语句的时候,会先查询缓存,Mysql会先校验这个sql是否执行过,以Key-Value的形式缓存在内存中,Key是查询预计,Value是结果集。如果缓存key被命中,就会直接返回给客户端,如果没有命中,就会执行后续的操作,完成后也会把结果缓存起来,方便下一次调用。当然在真正执行缓存查询的时候还是会校验用户的权限,是否有该表的查询条件。

Mysql 查询不建议使用缓存,因为对于经常更新的数据来说,缓存的有效时间太短了,往往带来的效果并不好,对于不经常更新的数据来说,使用缓存还是可以的,Mysql 8.0 版本后删除了缓存的功能,官方也是认为该功能在实际的应用场景比较少,所以干脆直接删掉了。

分析器

mysql 没有命中缓存,那么就会进入分析器,分析器主要是用来分析SQL语句是来干嘛的,分析器也会分为几步:

第一步,词法分析,一条SQL语句有多个字符串组成,首先要提取关键字,比如select,提出查询的表,提出字段名,提出查询条件等等。做完这些操作后,就会进入第二步。

第二步,语法分析,主要就是判断你输入的sql是否正确,是否符合mysql的语法。

完成这2步之后,mysql就准备开始执行了,但是如何执行,怎么执行是最好的结果呢?这个时候就需要优化器上场了。

优化器

优化器的作用就是它认为的最优的执行方案去执行(虽然有时候也不是最优),比如多个索引的时候该如何选择索引,多表查询的时候如何选择关联顺序等。

执行器

当选择了执行方案后,mysql就准备开始执行了,首先执行前会校验该用户有没有权限,如果没有权限,就会返回错误信息,如果有权限,就会去调用引擎的接口,返回接口执行的结果。

二、语句分析

2.1 查询语句

说了以上这么多,那么究竟一条sql语句是如何执行的呢?其实我们的sql可以分为2中,一种是查询,一种是更新(增加,更新,删除)。我们先分析下查询语句,语句如下:

select * from tb_student A where A.age='18' and A.name='张三';

结合上面的说明,我们分析下这个语句的执行流程:

先检查该语句是否有权限,如果没有权限,直接返回错误信息,如果有权限,在mysql8.0版本以前,会先查询缓存,以这条sql语句为key在内存中查询是否有结果,如果有直接缓存,如果没有,执行下一步。

通过分析器进行词法分析,提取sql语句的关键元素,比如提取上面这个语句是查询select,提取需要查询的表名为tb_student,需要查询所有的列,查询条件是这个表的id='1'。然后判断这个sql语句是否有语法错误,比如关键词是否正确等等,如果检查没问题就执行下一步。

接下来就是优化器进行确定执行方案,上面的sql语句,可以有两种执行方案:

a.先查询学生表中姓名为“张三”的学生,然后判断是否年龄是18。

b.先找出学生中年龄18岁的学生,然后再查询姓名为“张三”的学生。

那么优化器根据自己的优化算法进行选择执行效率最好的一个方案(优化器认为,有时候不一定最好)。那么确认了执行计划后就准备开始执行了。

进行权限校验,如果没有权限就会返回错误信息,如果有权限就会调用数据库引擎接口,返回引擎的执行结果。

2.2 更新语句

mysql的innodb数据库引擎详解

一.mysql体系结构和存储引擎

1.1、数据库和实例的区别

数据库:物理操作系统或其他形式文件类型的集合。在mysql下数据库文件可以是frm,myd,myi,ibd结尾的文件。

数据库实例:由数据库后台进程/线程以及一个共享内存区组成。数据库实例才是真正用来操作数据库文件的。

mysql数据库是单进程多线程的程序,与sql server比较类似。也就是说,Mysql数据库实例在系统上的表现就是一个进程。

1.2、mysql的体系结构

mysql由连接池组件、管理服务和工具组件、sql接口组建、查询分析器组件、优化器组件、缓存组件、插件是存储引擎、物理文件。

1.3、mysql存储引擎

1.3.1、innodb存储引擎,特点支持外键、行锁、非锁定读(默认情况下读取不会产生锁)、mysql-4.1开始支持每个innodb引擎的表单独放到一个表空间里。innodb通过使用MVCC来获取高并发性,并且实现sql标准的4种隔离级别,同时使用一种被称成next-key locking的策略来避免换读(phantom)现象。除此之外innodb引擎还提供了插入缓存(insert buffer)、二次写(double write)、自适应哈西索引(adaptive hash index)、预读(read ahead)等高性能技术。

1.3.2、myisam存储引擎,myisam特点是不支持事物,适合olap应用,myisam表由MYD和MYI组成。mysql-5.0版本之前,myisam默认支持的表大小为4G,从mysql-5.0以后,myisam默认支持256T的表单数据。myisam只缓存索引数据。

1.3.3、NDB存储引擎,特点是数据放在内存中,mysql-5.1版本开始可以将非索引数据放到磁盘上。NDB之前的缺陷是join查询是mysql数据库层完成的,而不是存储引擎完成的,复杂的join查询需要巨大的网络开销,速度很慢。当前mysql cluster7.2版本中已经解决此问题,join查询效率提高了70倍。

1.3.4、memeory存储引擎,将数据放到内存中,默认使用hash索引,不支持text和blob类型,varchara是按照char的方式来存储的。mysql数据库使用memory存储引擎作为临时表还存储中间结果集(intermediate result),如果中间集结果大于memorg表的容量设置,又或者中间结果集包含text和blog列类型字段,则mysql会把他们转换到myisam存储引擎表而放到磁盘上,会对查询产生性能影响。

1.3.5、archive存储引擎,压缩能力较强,主要用于归档存储。

1.3.6、federated存储引擎,不存储数据,他指向一台远程mysql数据库上的表。

1.3.7、maria存储引擎,myisam的后续版本,支持缓存数据和索引,行锁设计,支持mvcc,支持事务和非事务安全的选项,以及更好的BLOG字符类型的处理性能。

1.3.8、其他存储引擎,sphinx用于全文索引,infobright用于数据仓库。

1.4连接Mysql

1.4.1、TCP/IP:基于网络的连接,连接进行权限检查。

1.4.2、命名管道和共享内存:Windows系统上同一服务器上的两进程可通过命名管道连接,需在配置文件中启用--enable-named-pipe选项。

1.4.3、Unix套接字:客户端与服务端位于同一服务器时才可使用,可以在my.cnf中指定-socket=/tmp/mysql.sock,连接时指定./mysql -S/tmp/mysql.sock。

二.InnoDB存储引擎

2.2、innodb引擎架构

InnoDB的多个内存块组成了内存池,负责如下工作:

1).维护所有进程/线程需要访问的多个内部数据结构。

2).缓存磁盘上的数据,方便快速的读取,并且在对磁盘文件的数据进行修改之前在这里缓存。

3).重做日志缓存。

后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存是最近的数据,此外、将已经修改的数据文件刷新到磁盘文件

2.2.1、后台线程

innodb存储引擎后台有7个线程,—–4个IO线程(insert buffer thread,log thread,read thread,write thread),1个master thread,一个lock监控线程,一个错误监控线程。

2.2.2、内存

innodb存储引擎内存由以下三个部分组成:缓冲池(buffer pool),重做日志缓存(redo log buffer),额外的内存池(additional memory pool)。可以使用 show engine innodb status来查看innodb_buffer_pool的使用情况。

innodb_buffer_pool_size:具体看,缓冲池中的数据库类型有:索引页、数据库页、undo页、插入缓存页(insert buffer)、自适应hash(adaptive hashindex)、innodb存储的锁信息(lock info)、数据字典信息(data dictionary)。

InnoDB工作方式:将数据文件按页(每页16K)读入InnoDBbuffer pool,然后按最近最少使用算法(LRU)保留缓存数据,最后通过一定频率将脏页刷新到文件。

2.3、master thread

2.3.1、master thread源码分析

2.3.2、master thread的潜在问题

1、由于硬件的发展,现在的硬件性能已经提高了很多,如果innodb每秒最大刷新100个脏页,那么效率会很低,为了解决这个问题,innodb plugin提供了一个参数innodb_io_capacity,用来表示磁盘IO的吞吐量,默认值是200,规则如下:在合并插入缓存时,合并插入缓存的数量为innodb_io_capacity的5%;在从缓冲区刷新脏页时,啥新脏页的数量为innodb_io_capacity。

2、关于innodb_max_dirty_pages_pct值的争议,如果值过大,内存也很大或者服务器压力很大,那么效率很降低,如果设置的值过小,那么硬盘的压力会增加,建议是在75-80.并且innodb plugin引进了innodb_adaptive_flushng(自适应的刷新),该值影响每秒刷新脏页的数量。

2.4、关键特性,为innodb提高性能的技术

2.4.1、插入缓存

当一个表有非聚集索引时,对于非聚集索引的叶子节点的插入不是顺序的,这时候需要离散的访问非聚集索引页,性能就在这里降低了,这是由于b+树的原理导致的。插入缓存就是用来解决这个问题的。

对于非聚集索引的插入和更新操作,不是每一次都直接插入索引页,而是先判断插入的非聚集索引页是否在缓存中,如果在就直接插入,如果不在就放入到一个插入缓冲区中,好似欺骗数据库这个非聚集索引已经插入到叶子节点了。然后再以一定的频率插入缓存和非聚集索引页字节点的合并操作。

插入缓存的使用需要满足以下两个条件(也就是非唯一的辅助索引):索引是辅助索引;索引不是唯一的。

2.4.2、两次写

两次写给innodb带来的是可靠性,主要用来解决部分写失败(partial page write)。在应用重做日之前,我们需要一个页的副本,当写入失效发生时,先通过页的副本来还原该页,再进行重做,这就是doublewrite。

doublewrite有两部分组成,一部分是内存中的doublewrite buffer,大小为2M,另外一部分就是物理磁盘上的共享表空间中联系的128个页,即两个区,大小同样为2M。当缓冲池的张也刷新时,并不直接写硬盘,而是回通过memcpy函数将脏页先拷贝到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次写,每次写入1M到共享表空间的物理磁盘上,然后马上调用fsync函数,同步磁盘。

2.4.3、自适应哈西索引

由于innodb不支持hash索引,但是在某些情况下hash索引的效率很高,于是出现了 adaptive hash index功能,innodb存储引擎会监控对表上索引的查找,如果观察到建立hash索引可以提高性能的时候,则自动建立hash索引。

2.5、启动、关闭、恢复

innodb_fast_shutdown影响InnoDB表关闭。该参数有0、1、2三个参数。

0 MySQL关闭时 完成所有的full purge和merge insertbuffer操作

1默认值 只将缓冲池内的一些脏页刷新至磁盘

2将日志都写入日志文件不会有任何事务丢失但下次启动时会进行recovery

innodb_force_recovery影响整个innodb存储引擎的恢复状况,该值默认为0,表示当需要恢复时,需要执行所有的恢复操作,当不能进行有效恢复时,如数据页发生了corruption,mysql数据库可能宕机,并把错误写入错误日志中。

三.文件

3.1参数文件

Mysql实例可以不需要参数文件,这是所有的参数值取决于编译Mysql时指定的默认值和源代码中指定参数的默认值。其参数文件是Mysql.cnf。

3.1.1、什么是参数

参数是一个键/值对。可以使用show variables like命令查看,也可以通过information_schema的GLOBAL_VARIABLES视图来查找。

3.1.2、参数类型

参数文件分为两类:动态参数和静态参数。动态参数意味着你可以在Mysql实例运行中进行更改;静态参数说明在整个实例生命周期内都不得进行更改,好像是只读的。对于动态参数,又可以分为global和session关键字,表明该参数的修改是基于当前会话还是真格实例的生命周期。有些动态参数只能在会话中进行修改,如autocommit;有些参数修改完后,在整个实例生命周期中都会生效,如binlog_cache_size;而有些参数既可以在会话又可以在整个实例的生命周期内生效,如read_buffer_size。

3.2、日志文件

3.2.1、错误日志

错误日志对Mysql的启动、运行、关闭过程进行了记录。出现Mysql不能正常启动时,第一个必须查找的文件应该就是错误日志文件。使用show variables like ‘log_error’来定位文件。

3.2.2、慢查询日志

慢查询能为SQL语句的优化带来很好的帮助。设定一个阀值,将运行时间超过该值的所有SQL语句都记录到慢查询日志文件中。用参数long_query_time来设置。另一个参数log_queries_not_using_indexes,若运行的SQL语句没有使用索引,则这条SQL语句会被记录下来。

3.2.3、查询日志

查询日志记录了所有对Mysql请求的信息,不论这些请求是否得到正确的执行。默认文件名为:主机名.log。

3.2.4、二进制日志

二进制记录了对数据库执行更改的所有操作,但是不包括SELECT和SHOW操作,还包括了执行时间和更改操作时间。可用来恢复某些数据,同时也可以用来复制同步远程数据库。将binlog_format设置成row,可以支持事务隔离级别为READ COMMITTED,以获得更好的并发性。在使用MIXED格式下,mysql采用STATEMENT格式进行二进制日志文件的记录,但是有一些情况下会使用ROW格式,可能的情况如下:

1、表的存储引擎为NDB,这个时候DML操作都会以ROW格式记录。

2、使用了uuid()、user(),current_user(),found_rows(),row_count(),等不确定函数。

3、使用了insert delay语句

4、使用了用户定于的函数(UDF)

5、使用了临时表(temporary table)

注意:针对系统库mysql里面的表发生变化的处理规则如下:

1、 如果采用insert,update,delete直接操作表,则日志根据binlog_format设定的格式记录。

2、 如果使用grant,revoke,set password等DCL语句,那么无论如何都会使用SBR模式记录。

3、 blockhole引擎不支持row格式,ndb引擎不支持statement格式。

3.3、套件字文件

Unix系统下本地连接Mysql可以采用Unix套接字方法,需要一个套接字文件,可以使用show variableslike ‘socket’查询。

3.4、pid文件和表结构定义文件

pid文件是实例启动是记录自己进程ID号的文件,表结构定义文件是以frm为后缀名的文件,还可以用来存放视图的定义。

3.5、innodb引擎文件

3.5.1、表空间文件

默认表空间文件为ibdata1文件innodb_data_file_path存储数据,innodb_file_per_table可以按表分别产生一个表空间.db文件,但仅存该表的数据索引和插入缓冲等信息,其他信息如undo信息,系统事务信息,double write buffer等还是存放在默认表空间(ibdata1或表空间组)里。

3.5.2、重做日志文件

redo log是在实例或者介质失败的时候,用来保证数据完整性。每个innodb存储引擎至少有一个重做日志组,每个重做日志文件组下至少又2个重做日志文件,如默认的ib_logfile0、ib_logfile1.为了得到更高的可靠性,你可以设置多个重做镜像日志组。

因为重做日志条目先被写到日志缓冲中,然后根据一定条件刷新到磁盘重做日志文件中。与redo log相关的就是innodb_flush_log_at_trx_commit的值,对innodb的性能影响很大。他有0,1,2三个值,0代表提交事务时,并不同步写redo log,而是等master threas每秒写。1代表commit的时候就将redo log缓存写入磁盘,2代表commit的时候将redo log缓存异步的写入磁盘。

本文如未解决您的问题请添加抖音号:51dongshi(抖音搜索懂视),直接咨询即可。

上一篇:纸杯蛋糕怎么保存

下一篇:

热门图文

  • 水晶报表图片不显示两种问题分析及解决方法

    不是pdf的事,是水晶报表设置的原因,大概原因如下:原因1:CR输出的汉字格式不对(简体还是繁体),简体要先在区域设成(中国),然後在cr里设字体为&quot;宋体“即可 原因2:字符集问题。应查看web.config中字符集配置 原因3:数据流量过大。有时候,在水晶报表中导入的数据过多,并配置有图表,而服务器的配置相对较低,那么程序运行并不会报错,只是在显示的页面上显示乱码!至于原因,还没有搞明白。原因4:Crystal Report 8.5导出的PDF是为乱码,但CryStal Repo

  • ajaxToolkit:ModalPopupExtender演示及实现代码

    AJAX Control Toolkit 的一个服务器端控件ModalPopup 【功能概述】 ModalPopup 扩展控件允许在页面上模式弹出内容并阻止用户和页面上其他区域的交互。模式弹出区域的样式都是可以自定义的。 用户可以在模式弹出框选择OK/Cancel,对用户选择的处理方式有两种:使用客户端脚本或者PostBack到服务器端。这样我们就得到了用户的选择结果! 【细节】 (1) 看下面的代码可以看到执行客户端脚本的方法。 (2) 应该说这个控件是提供了一个模式弹出对话框的模板

  • ASP.NET简化编辑界面解决思路及实现代码(2)

    我们在.NET程序的开发过程中,常常需要和用户进行信息交互,比如执行某项操作是否成功,“确定”还是“取消”,以及选择“确定”或“取消”后是否需要跳转到某个页面等,下面是本人对常用对话框使用的小结,希望对大家有所帮助,同时也欢迎大家补充。(1) 点击页面上的按钮,弹出一个对话框提示是“确定”还是“取消”操作,我们采用在按钮中添加属性来完成: 举例如下: 代码如下:public System.Web.UI.WebControls.Button btnDelRow; btnDelRow.Attrib

  • GridView选择记录同时confirm用户确认删除

    实现方法:双击GridView的OnRowDataBound事件;在后台的GridView1_RowDataBound()方法添加代码,最后代码如下所示: protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e) { //如果是绑定数据行 if (e.Row.RowType == DataControlRowType.DataRow) {

  • ASP.NET简化编辑界面解决思路及实现代码

       &nbsp; 界面设计( )    样式   有时Web站点需要一个前台界面 这可能相当容易 只要打开常用的编辑器 然后编写一页一页的页面即可 但当突然被告知要修改页面的布局 样式 或者其他基本的UI内容就相当麻烦了 恐怕没有什么比因为颜色或者其他微不足道的原因而让人不得不重新编写页面更糟糕的事情了 为了避免这类维护方面的噩梦发生 用户界面最好要做到易于维护和修改   通常使用级联样式表来划分不同类型的UI元素 如标题 各种表 背景色以及字型 这样将有一个主样式表来帮助提供

Top