mariadb之查询及存储引擎
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mariadb之查询及存储引擎相关的知识,希望对你有一定的参考价值。
在关系型数据库中,如果要设计成表机制来存储数据,必须满足基本的范式,至少满足前三个范式。
第一范式(1NF):是指在关系模型中,对域(域代表字段)添加的一个规范要求,所有的域都应该是原子性的(不可分拆),即数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项。即实体(每一行)中的某个属性有多个值时,必须拆分为不同的属性。在符合第一范式(1NF)表中的每个域值只能是实体的一个属性或一个属性的一部分。简而言之,第一范式基本要求就是无重复的域。
第二范式(2NF):是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或记录必须可以被唯一地区分(不能有两个行是一样的)。选取一个能区分每个实体的属性或属性组,作为实体的唯一标识。
第三范式(3NF):是第二范式(2NF)的一个子集,即满足第三范式(3NF)必须满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个关系中不能包含已在其它关系已包含的非主关键字信息。简而言之,第三范式就是属性不依赖于其它非主属性,也就是在满足2NF的基础上,任何非主属性不得传递依赖于主属性。
关系运算可以有复杂查询操作,用来实现较为复杂的表和表之间的运算;例如,对表进行连接运算,做笛卡尔乘积;做自然连接、外连接、左外连接、右外连接、全外连接、内连接、自连接等等都是关系运算;
数据库:表,索引,视图(虚表)
视图又称为虚表,实际上就是存储下来的select语句,select语句的查询结果展示为一个表的形式,但事实上可以把一个语句存下来,然后对这个语句本身再次做查询操作,类似于做了一次子查询;
mysql现在主要由Oracle维护的;在基本功能上mysql和mariadb仍然是兼容的,二者是两种不同的发布路线;
在众多解决方案中mysql和mariadb与其它们所不同的地方在于,虽然每一个关系型数据库管理系统都需要自己的物理层,都需要存储引擎将逻辑组件最终转换为物理组件,以存储在文件系统上;但mysql采用非常精巧的方案,叫插件式存储引擎,也就意味着mysql能支持众多存储引擎,而且有能力的话仍然可以开发专属于自己的存储引擎;在mysql和mariadb就有很多存储引擎可选择,有的是开源的有的可能是额外购买的商业版本;
另外不同存储引擎由于它们是物理层的实现,所以使得mysql中是否支持某些功能是由存储引擎决定的;例如,mysql是否支持事务,则取决于存储引擎自己是否支持;处理mysql-server是关键组件之外,而存储引擎是另外一个关键的核心要件;
第二个特点是,mysql是单进程多线程模型,也就意味着mysql启动后能看到的进程就只有一个,其内部靠多线程分别完成不同的功能;在众多线程中最关键的有两类,
一类叫连接线程,一类叫做守护线程;还有很多其它线程,连接线程主要负责维护用户连接的,而守护线程包括向对应的数据从内存中刷写到磁盘上,从磁盘加载数据至内存中维护一个cache和buffer等等都是由守护线程完成;
单进程多线程由于mysql早期5.1左右版本,本身认为自己不是面对对企业级尤其是重量级企业级的应用;所以mysql由于是单进程模型,它对于多cpu核心的应用能力不是特别好;后来到5.5以后mysql能支持多达64核心不确定?但是,一个select查询语句的整个运行过程,无论mysql server支持多少颗cpu,但每一个查询语句还是只能在一个cpu上运行;这使得一个复杂查询语句想实现快速解析是不可能的;
另外,还不能使用大量内存空间,到现在能够支持越来越多的内存空间;mysql通过不断的技术改进不断发展而来的;
获取运行中的mysql进程使用的各种参数
MariaDB [(none)]> show global variables\G
MariaDB [(none)]> show session variables\G
修改服务器变量的值
修改全局变量,只对新连接的会话有效,对当前会话无效
MariaDB [(none)]> set global system_var_name=value;
MariaDB [(none)]> set @@global.system_var_name=value;
修改当前会话变量,对出会话即失效
MariaDB [(none)]> set session system_var_name=value;
MariaDB [(none)]> set @@session.system_var_name=value;
状态变量:用于保存mysqld运行中的历史统计变量
MariaDB [(none)]> show global status\G
MariaDB [(none)]> show session status\G
sql_mode:定义mysqld对约束等的响应行为
MariaDB [(none)]> show session variables like ‘sql_mode‘\G *************************** 1. row *************************** Variable_name: sql_mode Value: 1 row in set (0.00 sec)
常用的mode:
TRADITIONAL:传统模型,要求不允许对非法值做插入操作;
STRICT_TRANS_TABLES:表示对所有支持事务类型的表做严格约束;
STRICT_ALL_TABLES:表示对所有表做严格约束;
select语句的执行流程:
FROM Clause --> WHERE Clause --> GROUP BY --> HAVING Clause --> ORDER BY --> SELECT --> LIMIT
distinct:数据去重
字段显示可使用别名
group by:根据指定的条件把查询结果进行分组,以用于做聚合运算
常用函数:
avg(),max(),min(),count(),sum()
having:对分组聚合运算后的结果指定过滤条件
order by:根据指定字段进行排序,默认为升序asc,order by NAME desc为降序排序
limit [[offset,]row_count]:限制查询的结果的显示行数
对数据施加锁:
写锁:独占锁,排它锁,必须等待其他所有人都释放读锁后才可以
读锁:共享锁,当其他人加写锁后,将无法加读锁
MariaDB [hellodb]> lock table students read|write;
unlock tables;
多表查询:
交叉连接:笛卡尔乘积(多项式相乘);
内连接:
等值连接:让表之间的字段以等值建立连接关系;
不等值连接:
自然连接:
自连接:
外连接:
左外连接:左表中的每一项都有出现;而右表中没有对应时留空
FROM tb1 LEFT JOIN tb2 ON tb1.col=tb2.col
右外连接:
FROM tb1 RIGHT JOIN tb2 ON tb1.col1=tb2.col
子查询:在查询语句中嵌套查询语句,基于某语句的查询结果再次进行的查询
用在where中的子查询:
1、用于比较表达式中的子查询;子查询仅能返回单个值;
SELECT Name,Age FROM students WHERE Age>(SELECT avg(Age) FROM students);
2、用在IN中的子查询,子查询应该单键查询并返回一个或多个值从构成列表;
SELECT Name,Age FROM students WHERE Age IN (SELECT Age FROM teachers);
3、用EXISTS;用在where子句中;
用在from中的子查询:
SELECT tb_alias.col1, ... FROM (SELECT clause) AS tb_alias WHERE Clause;(不建议使用,子查询得到的表必须用别名表示)
联合查询:union,把两个select语句查询结果合并成一个;
mysql存储引擎:
是否支持事务取决于存储引擎,存储引擎是表级别的概念;
MyISAM不支持事务;在创建数据库时可以选择使用的存储引擎;
事务必须遵循:acid,原子性、一致性、隔离性、持久性;
为了能保证acid这四大特性,需要借助于redo和undo两种日志来保证随时能把未完成的事务回滚叫undo,完成的事务写到磁盘上叫redo;
数据库存储一般都在事务日志中完成,未提交的事务回滚,倒回去;已经提交的事务,只保存在事务日志中还没有保存在磁盘上,就需要把事务日志的文件读出来,保存到数据文件中;
InnoDB存储引擎,把数据存储在一个文件中,是个黑盒,和varnish是一样,varnish中的数据缓存都存储在一个文件中,但其内部完全有自组织有序的结果从外部看来就是一个文件,内部可以有自己的元数据,数据是构建在文件系统之上的文件系统;而InnoDB也是这样,默认情况下可以将n张表放在一个表空间里,在外部看来就是一个表,其内部存放了n张表甚至存放了n张表的索引;不过把n张表的索引放在同一表中很难实现高级功能;比如像单表导入导出等;因此,这就是为什么在安装MariaDB时,都要求使用innodb_file_per_table这表示每张表使用一个表空间;
InnoDB的表空间为了能跨文件系统(分区),InnoDB的表空间背后所对应的文件 可以不止一个,而且还可以自动增长;表空间刚创建时,就占用固定大小的空间,如果再许愿空间时,就又占用固定大小的空间,用不用都占用;可理解为是基于步进的方式进行划分;InnoDB将所有的表和索引放在一个表空间中;
创建表时指定存储引擎:
CREATE TABLE ... ENGINE[=]STORAGE_ENGINE_NAME...
显示表的状态信息:
SHOW TABLE STATUS[LIKE|WHERE]
InnoDB存储引擎是事务型存储引擎,适合处理大量的短期事务;
基于MVCC支持高并发;支持所有的四个隔离级别;默认级别为REPEATABLE READ;支持间隙锁防止幻读;
第一级别:读未提交read uncommitted
第二级别:读提交read committed
第三级别:可重读repeatable read
第四级别:可串行化serializable
级别越高事务发生冲突性越小,事务安全性越高但并发性就越低;
事务隔离中最核心组件就是锁;这么一来事务也没法并发了,既然锁了,看上去事务同时启动,但是还得等待一个个完成;所以,隔离级别至关重要了;
MyISAM内部的复杂机制很少,特别适应于读多写少的应用;但是,mysql自己的表,内部的元数据的库还是使用的MyISAM存储引擎;
MyISAM存储引擎最大特性是支持全文索引,全文索引指的是全文中的每一个关键字都可以被搜索;
搜索引擎与mysql的查询的区别:
对于关系型数据库,以mysql为例,索引构建在哪个字段上,就可以针对哪个字段做查询,如果没有索引,也可查询,只不过性能很差;即便有索引,查询条件也很独特;mysql使用的是平衡树索引,平衡树索引的最大特点是最左前缀模式,也就是索引如果在某一字段中的数据量很大,例如使用varchar或text类型,一个字段上可以存放几百甚至几千个字节的数据;索引时为了减小索引体积,一般只索引前面有限的字节,例如前100个字节;因此,在做查询时,根据条件查询只能找前100字节内的关键字,没有被添加至索引中的就查询不到;这就是全文索引的所在之处,全文索引就是索引的不是单个字段最左侧的有限个字节,而是整行内容全可以被索引;可以根据任意关键字进行查询,而这时全文索引所带来的特性就类似于搜索引擎;搜索引擎是可以根据某个关键字直接可以查出这个关键字所在的文档其实就是网页,只不过在存储上是以文档形式存储的;所以搜索引擎的索引的倒排机制的,可以根据一个或几个关键字查询文档;但是mysql的索引是根据一张表查询某个行数据,这就是搜索引擎和mysql索引的区别;
那全文索引就有点类似于搜索引擎的概念;而MyISAM就支持全文索引且需要专门的全文索引的函数来处理;支持基于空间函数进行空间索引;
MyISAM在崩溃后无法安全恢复,有可能会导致某些数据丢失,比如要入一行数据,刚插一半数据库崩溃,只能把刚插入的半行删了,保证数据是一致的;
解决办法是,MyISAM有个表修复工具,会对全表扫描,一行行扫描,看哪一行中的数据是不完整的给它删了;所以这就是崩溃后的恢复,如果表要大的话,恢复时间会非常长;所以说,可以接受较长时间(几分钟或几十分钟)的修复操作才能使用MyISAM;这个较长时间还是指的较小的表,如果表大可能修复一天都有可能;
MyISAM存储引擎特性:
加锁和并发:支持表级锁;
修复:只能手动或自动修复(使用工具)、但可能会丢失数据;并不是安全恢复;索引:使用的是非聚集索引;
支持延迟更新索引;
支持表压缩;压缩后表数据不能修改;
对于存储引擎来讲,mariadb中的MyISAM只支持表级锁,且不支持事务,而InnoDB支持行级锁,所以所粒度比较小;其实锁是mysql实现并发访问控制的重要组件;
锁策略:在锁粒度及数据安全性之间寻求的一种平衡机制;
锁粒度小所需要的开销就大;mysql支持两种形式的锁:myslq锁和存储引擎锁;
mysql锁就是由mysql核心组件施加的锁;
由存储引擎施加的锁叫存储引擎锁;
MySQL在服务器级也实现了锁,但仅支持表级锁;支持显是请求;而存储引擎级别使用表级锁和行级锁均可自动管理,但不能手动请求;
根据锁本身根据用户手动施加还是由服务器自动实现,锁又可分两种类型:
显式锁:用户手动请求施加的锁;
隐式锁:由存储引擎(或mysql服务器)自行根据需要施加的锁;
MySQL事务:
事务日志:就是在mysql是数据文件之外的另外一个存储区域,这个存储区域带来的作用是,当一个事务型存储引擎在运行过程当中,需要启动一事务并完成数据修改时,所有的修改操作(由多个sql语句组成),每一次的操作所涉及到的数据修改,这个改的操作要转换成底层存储引擎所支持的相关的操作过程,它会把每一次sql语句所涉及的操作步骤,具体的过程记录在事务日志文件中;
注意,记录的是每一步的具体操作;例如,插入一行的数据是什么、插入什么位置、什么时候插入的等都记录下来;再例如,如果是修改几行,先修改哪行后修改哪行、几点开始修改、几点结束等等都记录下来;而这个日志要能够重现操作就叫做事务日志;
一个事务型存储引擎它的操作借助于事务日志来保证其对应的事务特性;所以,任何事务型存储引擎的相关操作,默认不会直接写在数据库文件上,而是先写在事务日志中,并且事务日志为保证足够可靠,基本上很少在内存中缓冲,写文件基本比较差,都会先写内存,然后等过一会再同步到磁盘上;
事务日志也有这段缓冲区,这个缓冲区放的量不能太大时间不能太久,因为如果允许缓存5秒钟,如果系统崩溃最大会丢失5秒钟的数据;所以建议这个时间要足够短,一般为1秒钟同步到磁盘上一次;但是,同步越频繁性能就越差,数据可靠性就越高;
每一步在记录时,还会把修改之前的原始数据内容也记录下来这是为了支持undo机制而记录的;
事务日志支持redo和undo;当记录是的修改数据时会把修改的数据之前的数据记录下来;
假如,进行到一半服务崩溃了,把修改的操作日志撤销了即可,因为它还没有同步到磁盘上;
如果为了保证数据的稳定性,一个大事务中间有可能事务还没完成,已经在事务日志记录了30个,再记录事务日志会先把一部分信息往磁盘上同步,开始真正修改原始数据了,这时崩溃,则只能把已经同步到表中的数据撤销,需要undo日志参与;
还有一种情况是,比如一个事务有60个sql语句都写完了且都记录在事务日志中了,但只有其中30个语句同步到磁盘上,此时数据是不一致的;因为有些事务已经提交,但是没存储到磁盘上;这样就必须把事务日志中未完成的语句同步到磁盘上;同步的要做提交,没能完成的要做回滚;这个就叫崩溃后恢复;
如果日志文件非常大,恰好写满了崩溃了,下次mysql启动时,必须把里面的所有语句统统同步到磁盘上才能正常启动;如果事务日志文件大到2G,为了能够把2G的语句都同步到磁盘上,有可能mysql服务器启动半小时;所以,为了避免崩溃后启动时间太长,把日志文件设置小一点;但是,有时会出现,日志填满了,但是日志内容还没来得急同步到磁盘上,还有新的日志需要写进来,就再启动一个文件;
也就说日志文件一般启动2个或3个是轮转使用的,所谓轮转指的是第一个日志文件填满了就用第二个,同时把第一个日志文件同步到磁盘上;等第二个日志写满了就可以使用第一个了,这样轮转使用;有多个事务日志文件组成的叫做事务日志组,日志组内至少应该有两个文件,但是多了就不好了;
事务日志文件和数据文件不应该放在同一磁盘上,因为会对磁盘写io操作很多压力,影响其性能;分开存放比较理想,但是有些场景又要必须放在一起,例如基于逻辑卷操作时;
如果事务日志所在磁盘崩溃,则数据库数据无法保持一致;所以,要把事务日志磁盘做镜像;建议使用raid1;数据文件也很重要建议使用raid10;
事务:一组原子性的SQL查询,或者多个SQL语句组成了一个独立的工作单元;
事务日志:将随机写转换为顺序写;
判断存储引擎是否支持事务:经过ACID测试
A:automicity,原子性;整个事务中的所有操作要么全部成功执行,要么全部失败后回滚;
C:consistency,一致性;数据库总是从一个一致性状态转换为另一个一致性状态;
I:isolation,隔离型;一个事务所做出的操作在提交之前,是不能为其它事务所见,隔离有多种级别,主要是为了并发;隔离级别一共有4个;
D:durability,持久性;事务一旦提交,其所做的修改会永久保存于数据库中;
MyISAM存储引擎是不支持事务的,InnoDB支持事务,所以要想使用事务得确保使用的是InnoDB等支持事务的存储引擎;
mysql默认把每个语句当做一个事务提交,可以手动关闭自动提交功能,手动来启动事务;
以上是关于mariadb之查询及存储引擎的主要内容,如果未能解决你的问题,请参考以下文章