您的位置:首页 > 数据库 > SQL

高性能Mysql学习(一):Mysql架构与历史

2015-04-23 10:59 344 查看

1.1逻辑架构



第一层架构图:也就是最上层的服务并不是mysql独有的,大多数基于网络的客户端/服务器的工具或者服务器都有类似的架构,比如链接处理,授权认证,安全等等

第二层架构:这个是MySql比较有意思的部分,大部分MySql核心服务和功能都在这一层,包括查询解释,分析,优化,缓存以及所有的内置函数(例如,日期,时间,数学和 加密函数),所有跨存储引擎的功能都在这一层实现:存储过程,触发器,视图等。

第三层架构:包含了存储引擎,存储引擎负责MySql中数据的存储和提取,和GNU/Linux写的各个文件系统一样,每个存储引擎都有它的优势和劣势,服务器通过API与存储引擎进行通信,这些接口屏蔽了不同存储引擎之间的差异,使得这些差异对于上层的查询过程透明,存储引擎API包含十几个底层函数,用于执行诸如 '开始一个事务'或者'根据主键提取一行记录‘等操作,但存储引擎并不会去解析Sql,不同存储引擎之间也不会相互通信,而只是简单的响应上层服务器的请求。

1.1.1链接管理与安全性

没个客户端连接都会在服务器进程中拥有一个线程,这个链接的查询只会在单独的线程中执行,服务器负责缓存线程,因此不需要为没一个新建的链接创建或者销毁线程。

客户端(应用)链接到MySql服务器时,服务器需要对其进行认证,认证基于用户名,原始主机信息和密码,如果使用了字节套(SSL)的链接方式,还可以使用X.509证书认证,

一旦客户端连接成功,服务器会继续验证该客户端是否具有执行某个特定查询的权限。

1.1.2优化与执行

MySql会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重查询,决定表的读取顺序,以及选择合适的索引等,用户可以通过特殊的关键字提示(hint)优化器,影响他的决策过程,也可以请求解释器解释(explain)优化过程的各个因素。

有呼气并不关系表使用的是什么存储引擎,但是存储引擎对于优化查询是有影响的,优化器会请求存储引擎提供容量或者某个具体操作的开销信息,以及表数据的统计信息。例如,某些存储引擎的某种索引,可能对一些特定的查询有优化。

对于SELECT语句,在解析查询之前,服务器会先检查查询缓存,如果能够在其中找到对应的查询,服务器就不必再执行查询解析,优化和执行过程,而是直接返回查询缓存中的结果集。

1.2并发控制

无论何时,只要有多个查询需要在同一时刻修改数据,都会产生并发控制的问题。

1.2.1读写锁

在处理并发读或者写时,可以通过实现一个由两种类型的锁组成的锁系统来解决问题。

共享锁(读锁):读锁是共享的,或者说是相互不阻塞的,多个客户在同一时刻可以同时读取同一资源,而互不干扰。

排它锁(写锁):写锁是排他的,一个写锁会阻塞其他的写锁和读锁。确保在给定时间内,只有一个用户能执行写入,并防止其他用户读取正在写入的同一资源。

写锁比读锁有更高的优先级,因此一个写锁请求可能会被插入到读锁队列的前面,反之则不行。

1.共享锁(S锁):如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。
2.排他锁(X锁):如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获准排他锁的事务既能读数据,又能修改数据。
3.共享锁下其它用户可以并发读取,查询数据。但不能修改,增加,删除数据。资源共享.

1.2.2锁粒度

一种提高共享资源的并发性的方式就是让锁定的对象更具有选择性,尽量只锁定需要修改的部分数据,而不是所有资源。在任何时候,给定的资源上,锁定的数据量越少,则系统并发性越高,只要互相之间不发生冲突即可。

解锁需要资源消耗。锁的各种操作,包括过的锁,检查锁是否已经解除,释放锁等,都会增加系统的开销。如果系统花费大量的时间来管理锁,而不是存取数据,那么系统可能会因此受到影响。

锁策略

锁策略就是在所的开销和数据的安全性之间寻求平衡。
表锁
MySql最基本的锁策略,开销最小,锁定整张表。一个用户在对表进行写操作(插入,删除,更新)前,需要获获得写锁。

行级锁

行级锁可以最大程度的支持并发处理,同时也带来了最大的锁开销,在InnoDB和XtraDB,以及其他一些存储引擎中实现了行级所,行级锁只在存储引擎层实现,而MySql服务层没有实现。

1.3事务

事务时一组原子性的SQL查询,或者说是一个独立的工作单元,如果数据库引擎能够成功的对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中任何一条语句因为崩溃或者其他原因无法执行,那么所有的语句都不会执行,也就是说,事务内的语句,要么全部执行成功,要么全部执行失败。

一个运行良好的事务处理系统,必须具备这些标准特征:

1.原子性:一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中一部分的操作,这就是事务的原子性。

2.一致性:数据库总是从一个一致性的状态转换到另一个一致性的状态。

3.隔离性:通常来说,一个事务所做的修改在最终提交之前,对于其他事务时不可见的。

4.持久性:一旦事务提交,则其所有的修改会永久保存到数据库中。

就像锁粒度的升级会增加系统开销一样,这种事务处理过程中的安全性,也会需要数据库系统做更多额外的工作,一个实现了ADIC的数据库,相比没有实现ACID的数据库,通常需要更强的CPU处理能力,更大的内存,更多的磁盘空间。

MYsql用户可以根据业务是否需要事务处理,来选择合适的存储引擎。即使不支持事务的存储引擎,也可以通过LOCK TABLES语句为应用提供一定程度的保护。

1.3.1隔离级别

每一种隔离级别都规定了一个事务中所做的修改,哪些在事务内和事务间事可见的,哪些是不可见的,较低级别的隔离通常可以执行更高的并发性,系统的开销也更低。

1.READ UNCOMMITTED(未提交读):在READ UNCOMMITTED级别,事务中的修改,即使没有提交,对于其他事务也都是可见的,事务可以读取未提交的数据,这也被称为脏读。

2.READ COMMITTED(提交读):大多数数据库的默认级别(MYSQL不是)。READ COMMITTED满足前面提到的隔离性的定义:一个事务开始时,只能看见已经提交的事务所做的修改,换句话说,一个事务开始直到结束之前,所做的任何修改对其他事务都是不可见的,这个级别有时也叫不可重复读,因为两次执行相同的查询,可能会得到比一样的结果。

3.REPETABLE READ(可重复读):解决了脏读的问题,该级别保证了同一事物中多次读取相同的记录结果是一致的,但是理论上,可重复读隔离级别还是无法解决另一个幻读的问题。所谓幻读指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围插入了新纪录,当之前的事务再次读取该范围的记录时,会残成幻行。InnoDB和XtraDB存储殷勤通过多版本并发控制解决了幻读的问题。可重复读是MySql的默认隔离级别

4.SERIALIZABLE(可串行化):最高的隔离级别,它通过强制事务串行执行,别面了前面说的幻读的问题,简单来说,它会在每一行数据上都加锁,所以可能导致大量的超时和锁争用问题。

可以通过SET SESSION TRANSACTION ISOLATION LEVEL XXX 来设置隔离级别,新的隔离级别会在下个事务开始生效。

1.3.2死锁

死锁指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环现象。当多个事务试图以不同顺序锁定资源时,可能产生死锁。多个事务同时锁定同一资源时,也会产生死锁。

InnoDB解决死锁方式:将持有最少行级排它锁的事务进行回滚,大多数情况下只有需要重新执行因死锁回滚的事务即可。

1.3.3事务日志

事务日志可以帮助提高事务的效率,使用事务日志,存储引擎子啊修改表数据时只会修改内存拷贝,再把该修改行为记录到持久的硬盘上的事务日志中,而不用每次都将修改的数据本身持久到硬盘。事务日志采用的是追加的方式,因此写日志的操作是磁盘上一小块区域内的顺序I/O,而不像随机I/O那样需要在磁盘的多个地方移动磁头,所以采用事务日志的方式相对来说要快的多。事务日志持久以后,内存中被修改的数据在后再可以慢慢的刷回磁盘,目前大多数存储引擎都是这样实现的,我们通常称之为预写式日志,修改数据需要写两次磁盘。

如果数据的修改已经记录到事务日志并持久化,但是数据本身没写回到磁盘,此时系统崩溃,存储引擎子啊重启时能够自动恢复这部分修改的数据;具体方式视存储引擎而定

1.3.4MySql中的事务

MySql提供了两种食物类型的存储引擎:InnoDB和NDB Cluster。另外还有一些第三方存储引擎也支持事务,比较知名的包括XtraDBhe PBXT.

自动提交:
MySql默认采用自动提交模式,也就是说如果不是显示的开启一个事务,没个查询都会被当作一个事务执行提交操作。
查看是否是自动提交:SHOW VARIABLES LIKE 'AUTOCOMMIT'
设置自动提交:SET AUTOCOMMIT = 1(1或ON表示启用,0或者OFF表示禁用)

修改AUTOCOMMIT对于非事务型的表不会有任何影响,对于这类表而言,没有COMMIT和ROLLBACK的概念,也可以说是一直处于AUTOCOMMIT启用模式。

还有一些命令,在执行之前会执行COMMIT提交当前活动的所有事物。典型的例子是在数据定义语言(DDL)中,如果是会导致到两数据改变的操作,比如ALTER TABLE。
另外还有LOCK TABLES等其他语句也会导致同样的结果。

在事务中混合使用存储引擎:
Mysql服务器层不管理事务,事务是有下层的存储疫情实现的,所以在同一个事物中,使用多种存储引擎是不可靠的
如果在事务中混合使用了事务型和非事务型的表,在正常提交情况写不会有什么问题,但是如果要回滚该事务,非事务类型的表上的更改是无法撤销的,这回导致数据库处于不一致状态,这种情况很难修复,事务的最终结果将无法确定,所以为每张表选择合适的存储引擎是非常重要的。

隐式和显式锁定:
InnoDB采用的是两阶段的锁定协议。在事务执行过程中,随时可以执行锁定,锁只有在执行COMMIT 或者 ROLLBACK的时候才会释放,并且所有锁是在同一时刻被释放。前面秒速的锁定都是隐式锁定,InnoDB会根据隔离级别在需要的时候自动加锁。

InnoDB也支持通过特定的语句进行显示锁定,这些语句不属于SQL规范
SELECT ...... LOCK IN SHARE MOOE
SELECT ...... FOR UPDATE
MySql也支持LOCK TABLES 和 UNLOCK TALBES语句,这实在服务器层实现的,和存储引擎无关,他们有自己的用途,并不能替代事务处理,如果应用需要用到事务,还是应该选择事务型的存储引擎。

经常可以发现,应用已经将表从MyISAN 转换到 InnoDB,但还是显式的使用LOCK TABLES语句,这不但没有必要,还会严重影响性能,实际上I你弄DB的行级锁工作得更好。
LOCK TABLES和事务之间互相影响的话,情况会变得非常复杂,在某些MySql版本中甚至会产生无法预料的结果,因此,这本书的建议是,除了事务中禁用AUTOCOMMIT,可以使用LOCK TABLES之外,其他任何时候都不要显示的执行LOCK TABLES,不关使用的是什么存储引擎。

1.4多版本并发控制(MVCC)

MySql的大多数事务型引擎实现都不是简单的行级锁。基于提升并发性能的考虑,他们一般都实现了多版本并发控制(MVCC)不仅是MySql,包括Oracle,PostgreSQL等其他数据库也都实现了MVCC,但各自实现的机制不尽相同,因为MVCC没有一个统一的实现标准。

可以认为MVCC是行级所的一种变种,但是他在很多情况下避免了加锁操作,因此开销更低,虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只是锁定必要的行。

MVCC的实现,是通过保存数据在某个时间点的快照来实现的。也就是说,不管需要执行多长时间,每个事务看到的数据都是一直的。根据事务开始的时间不同,每个事务对同一张表,同一时刻看到的数据可能是不一样的。如果之前没有这方面的概念,这句话听起来有点迷惑。熟悉之后会发现,这句话其实还是很容易理解的。

前面说到不同存储引擎的MVCC实现是不同的,典型的有乐观并发控制和悲观并发控制。

InnoDB的MVCC是通过每行记录后面保存两个隐藏的列来实现的,这两个列,一个保存了行的创建时间,一个保存行的过期时间(或者删除时间)。当然存储的并不是实际的时间值,而是系统版本号。每开始一个新的事物,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。

上面的是书本里面的原话,说实话我是看不懂啥意思。暂时按照书本中的例子来理解吧。

REPEATABLE READ隔离级别下,MVCC的操作。
SELECT
InnoDB会根据以下两个条件检查每行记录:
a.InnoDB只检查版本号早于当前事务版本的数据行(小于等于的关系),这样可以确保事务读取的行,要么是在事务开始前已经存在,要么是事务自身插入或者修改的
b.行的删除版本要么未定义,要么大于当前事务版本号。这可以确保事务读取到的行,是在事务开始之前未被删除。
INSERT
InnoDB为新插入的每一行保存当前系统版本号作为行版本号
DELETE
InnoDB为删除的每一行保存当前系统版本号作为删除标识
UPDATE
InnoDB为插入一行新纪录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识

保存这两个额外的系统版本号,使大多数都操作都可以不用加锁,这样设计使得读数据操作很简单,性能很好,并且能保证只会读取到符合标准的行,不足之处是每行记录都需要额外的存储空间,需要做更多的行检查工作,以及一些额外的维护工作。

MVCC只在REPEATABLE READ和READ COMMIT两个隔离级别下工作,其他两个隔离级别都和MVCC不兼容,因为READ UNCOMMITTED总是读取最新的数据行,而不是符合当前事务版本的数据行,而SERIALIZABLE则会对所有读取的行都加锁。

1.5MySql存储引擎

在文件系统中,MySql将每个数据库(也可以称之为schema)保存为数据目录下的一个子目录。创建表时,MySql会在数据库子目录下创建一个和表名相同的.frm文件保存表的定义。因为MySql使用文件系统的目录和文件来保存数据库和表的定义,大小写敏感性和平台密切相关,在Windows中,大小写是不敏感的;而在类Unix中则是敏感的,不同的存储引擎保存数据和索引的方式是不同的,但表的定义则是在mysql服务层统一处理的。

可以使用SHOW TABLE STATUS显示所有表的相关信息,如果查看某个表可以通过SHOW TABLE STATUS LIKE 'TABLE_NAME'
Name:表明
Engine:表的存储引擎类型。在就版本中,该列的名字叫做Type
Row_format:行的格式。对于MyISAM表,可选值为Dynamic,Fixed或者Compressed。Dynamic的行长度是可变的,一般包含可变长度的字段,如VARCHAR或者BLOB。Fixed的行长度则是固定的,只包含固定长度的列。如CHAR和INTEGER。Compressed的行则只在压缩表中存在。
Rows:表中的行数。对于MyISAM和其他的一些存储引擎,该值是精确的,但对于InnoDB该值是估计值
Avg_row_length:平局每行包含的字节数
Data_length:表数据的大小(以字节为单位)。
Max_data_length:表数据的最大容量,该值和存储引擎有关。
Index_length:索引的大小(以字节为单位)
Data_free:对于MyISAM表,表示已分配但目前没有使用的空间。这部分空间包括了之前删除的行,以及后续可以被INSERT可以用到的空间
Auto_increment:下一个AUTO_INCREMENT的值
Create_time:表创建时间。
Update_time:表数据的最后修改时间
Check_time:使用CKECK TABLE命令或者myisamchk工具最后一次检查表的时间。
Collation:表的默认字符集和字符列排序规则
Checksum:如果启用,保存的是整张表的实时校验和
Create_options:创建表时指定的其他选项。
Comment:该列包含了一些其他的额外信息。对于MyISAM表,保存的是表在创建时带的注释。对于InnoDB表,则保存的是InnoDB表空间的剩余空间信息。如果是一个视图,则该列包含"VIEW"的文本字样。

1.5.1InnoDB存储引擎

MySql默认的存储引擎,也是应用最重要的,使用最广泛的存储引擎,他被设计用来处理大量的短期事务,短期事务大部分情况是正常提交的,很少会被回滚。InnoDB的性能和自动崩溃恢复特性,使得他在非事务型存储的需求中也很流行,除非有非常特别的原因需要使用其他的存储引擎,否则应该有限考虑InnoDB引擎。

InnoDB的数据存储在表空间,表空间由InnoDB管理的一个黑盒子,由一系列的数据文件组成。在mysql4.1以后的版本中,InnoDB可以将每个表的数据和索引存放在单独的文件中。InnoDB也可以使用裸设备作为表空间的存储介质,但现在的文件系统是的裸设备不再是必要的选择。

InnoDB采用MVCC支持高并发,并且实现了四个标准的隔离级别。其默认级别是REPEATABLE READ,并且通过间隙锁策略防止幻读的出现,间隙锁是的InnoDB不仅仅锁定查询涉及的行,还会对索引中的间隙进行锁定,以防止幻行的插入

InnoDB表是居于聚簇索引建立的。InnoDB的索引结构和MySql的其他存储引擎有很大的不同,聚簇索引对主键查询有很高的性能。不过它的二级索引中必须包含主键列,主键应当尽可能小,InnoDB的存储格式是平台独立的,也就是说可以将数据和索引文件从Intel平台复制到PowerPC或者Sum SPARC平台。

InnoDB内部做了很多就花,包含从磁盘读取数据时采用的可预测性预读,能够自动在内存中创建hash索引以加速读操作的自适应哈希索引,以及能够加速插入操作的插入缓存等。

作为事务型的存储引擎,InnoDB通过一些机制和工具支持真正的热备份,Oracle提供的MySql Enterprise Backup , Percona提供的开源的XtraBackup都可以做到这一点。MySql的其他存储引擎不支持热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能意味着停止读取。

1.5.2MyISAM存储引擎

MySql5.0及之前的版本,MyISAN是默认的存储引擎。MyISAM提供了大量的特性,包括全文索引,压缩,空间函数(GIS)等,但MyISAM不支持事务和行级锁,而且有一个毫无疑问的缺陷就是崩溃后无法安全恢复。对于只读的数据,或者表比较小,可以忍受修复操作,则依然可以继续使用MyISAM

存储:
MyISAM会将表存储在两个文件中:数据文件和索引文件,分别以.MYD和.MYI为扩展名。MyISAM表可以包含动态或者静态行。mysql会根据表的定义来决定采用何种行格式。MyISAM表可以存储的行记录数,一般受限于可用磁盘空间,或者操作系统中单个文件的最大尺寸。
在mysql5.0中myisam表如果是变长行,则默认配置只能处理356TB的数据,因为指向数据记录的指针长度6个字节。而在更早的版本中,指针长度默认是4字节,所以只能处理4GB的数据。而所有的mysql版本都支持8字节的指针。要改变myisam表指针的长度(调高或者调低),可以通过修改表的MAX_ROWS和***G_ROW_LENGTH选项的值来实现,两者相乘就是表可能达到的最大大小。修改这两个参数会导致重建整个表和表的所有索引,这可能需要很长世间才能完成。

MyISAM特性:
作为mysql最早的存储引擎之一,MyISAM有一些已经开发出来很多年的特性,可以满足用户的实际需求。
加锁与并发:
MyISAM对整张表加锁,而不是针对行。读取时会对需要读取到的所有表加共享锁,写入时则对表加排它锁。但是表有读取查询的同时,也可以往表中插入新的记录(这被称为并发插入,CONCURRENT INSERT)。
修复:
对于MyISAM表,MySQL可以手工或者自动执行检查和修复操作,但这里说的修复和事务恢复以及崩溃恢复是不同的概念。执行表的修复可能导致一些数据丢失,而且
修复操作是非常慢的。可以通过CHECK TABLE mytable检查表的错误。如果有错误可以通过执行REPAIR TABLE mytable进行修复。另外如果MySQL服务器已经关
闭,可以通过myisamchk命令行工具进行检查和修复操作。
索引特性:
对于MyISAM表,即使是BLOB和TEXT等长字段,也可以基于其前500个字符创建索引。MyISAM也支持全文索引,这是一种基于分词创建的索引,可以支持复杂的查
询。
延迟更新索引键
创建MyISAM表的时候,如果指定了DELAY_KEY_WRITE选项,在每次修改执行完成时,不会立刻将修改的索引数据写入磁盘,而是会写到内存中的缓存冲区,只有
在清理键缓冲区或者关闭表的时候才会将对应的索引块写入到磁盘。这种方式可以极大的提升写入性能,但是在数据库或者主机崩溃时会照成索引损坏,需要执行修复
操作。延迟更新索引键的特性,可以在全局设置,也可以为单个表设置。

MyISAM压缩表:
如果表在创建并导入数据以后,不会再进行修改操作,那么这样的表或许适合采用MYISAM压缩表。
可以使用myisampack对MyISAM

1.5.3MySql内建的其他存储引擎

1.5.4第三方存储引擎

1.5.5选择合适的引擎

1.5.6转换表的引擎



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: