去IOE:
去掉IBM的小型机、Oracle数据库、EMC存储设备,代之以自己在开源软件基础上开发的系统。
Mysql最重要,最与众不同的的特性是它的存储引擎架构,这种架构的设计将查询处理(Query Processing)及其他系统任务(Server Task)和数据的存储/提取相分离。这种处理和存储分离的设计可以在使用时根据性能,特性,以及其他需求来选择数据存储的方式。
第一层:
并不是Mysql所独有的,大多数基于网络的客户端/服务器的工具或者服务都有类似的架构,比如连接处理,授权认证,安全等等。
第二层:
大多数Mysql的核心服务功能都在这一层,包括查询解析,分析,优化,缓存以及所有内置函数(例如,日期,时间,数学和加密函数),所有跨存储引擎的功能都在这一层实现:存储过程,触发器,视图等。
第三层:
包含了存储引擎,存储引擎负责Mysql中数据的存储和提取。和GNU/Linux下各种文件系统一样,每个存储引擎都有它的优势和劣势。服务器通过API与存储引擎进行通信,这些接口屏蔽了不同存储引擎之间的差异,使得这些差异对上层的查询过程透明。存储引擎API包含几十个底层函数,用于执行执行诸如“开始一个事务”等操作。但存储引擎不会去解析SQL(InnoDB是一个例外,它会解析外键定义,因为Mysql服务器本身没有实现该功能),不同存储引擎之间也不会相互通信,而是简单的响应上层服务器的请求。
每个客户端连接都会在服务器进程中拥有一个线程,这个连接的查询只会在这个单独的线程中执行。服务器会负责缓存线程,因此不需要为每一个新建的连接创建或者销毁线程。(Mysql5.5或者更新的版本提供了一个API,支持线程池(Thread Pooling)插件中,可以使用池中少量的线程来服务大量的连接)。
Mysql会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写查询,决定表的读取顺序,以及选择合适的索引等。
优化器并不关心表使用的是什么存储引擎,但存储引擎对于优化查询是有影响的。
对于SELECT语句,在解析查询之前,服务器会检查查询缓存(Query Cache),如果能够在其中找到对应的查询,服务器就不必再执行查询解析,优化和执行的整个过程,而是直接返回查询缓存中的结果集。
无论何时,只要有多个查询需要在同一时刻修改数据,都会产生并发控制的问题。主要讨论两个层面的并发控制:1.服务器层,2.存储引擎层。
在处理并发读或者写时,可以通过实现一个由两种类型的锁组成的锁系统来解决问题。这两种类型的锁通常成为共享锁(shared lock)和排他锁(exclusive lock),也叫读锁(read lock)和写锁(write lock)。
一种提高共享资源并发性的方式是让锁定对象更有选择性。任何时候,在给定的资源上,锁定的数据量越少,则系统的并发程度越高,想要相互之间不发生冲突即可。
但锁不是越多越好,锁的各种操作都会增加系统的开销。
Mysql提供了多种锁选择。每种Mysql存储引擎都可以实现自己的锁策略和锁粒度。
将锁粒度固定在某个级别,可以为某些特定的应用场景提供更好的性能,但同时却会失去对另外一些应用场景的良好支持。下面介绍两种最重要的锁策略。
表锁(table lock)
表锁是Mysql中最基本的锁策略,并且是开销最小的策略。
行级锁(row lock)
行级锁可以最大程度地支持并发处理(同时也带来了最大的锁开销)。
除非系统通过严格的ACID测试,否则空谈事务的概念是不够的。ACID表示原子性(atomicity),一致性(consistency),隔离性(isolation)和持久性(durability)。
就像锁粒度的升级会增加系统开销一样,这种事务处理过程中额外的安全性,也会需要数据库系统做更多的额外工作,一个实现了ACID的数据库,相比没有实现ACID的数据库,通常会需要更强的CPU处理能力,更大的内存和更多的磁盘空间。
这也是Mysql的存储引擎架构可以发挥优势的地方,用户可以根据业务是否需要事务处理,来选择合适的存储引擎。
在SQL标准中定义了四种隔离级别,每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。较低级别的隔离通常可以执行更高的并发,系统的开销也更低。
四种隔离级别:
1.READ UNCOMMITTED(未提交读)
其他事务可以读取未提交的数据,也被成为脏读(Dirty Read)。这个级别会导致很多问题,性能上也不会好太多,缺乏其他级别的很多好处,除非真的非常有必要,在实际应用中很少使用。
2.READ COMMITTED(提交读)
READ COMMITTED满足前面提到的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说,一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。也叫不可重复读。因为两次执行同样的查询,可能会得到不一样的结果。
3.REPEATABLE READ(可重复读)
该级别保证了在同一个事务中多次读取同样的记录的结果是一致的。可重复读是Mysql的默认事务隔离级别。
4.SERIALIZABLE(可串行化)
SERIALIZABLE会在读取的每一行数据上偶加锁,所以可能导致大量的超时和锁争用的问题。实际中很少使用这个级别,只有在非常需要确保数据的一致性而且可以接收没有并发的情况下,才考虑采用该级别。
为了解决死锁的问题,数据库系统实现了各种死锁检测和死锁超时机制。越复杂的系统,比如InnoDB存储引擎,越能检测到死锁的循环依赖,并立即返回一个错误。
事务日志可以帮助提高事务的效率。
Mysql默认采用自动提交(AUTOCOMMIT)模式。
也就是说,如果不是显式地开始一个事务,则每个查询都会被当做一个事务执行提交操作。
注意:
修改AUTOCOMMIT对于非事务型的表,比如MyISAM或者内存表,不会有任何影响。对于这类表来说,没有COMMIT或者ROLLBACK的概念,也可以说是相当于一直处于AUTOCOMMIT启用的模式。
Mysql可以铜鼓执行 SET TRANSACTION LEVEL命令来设置隔离级别。新的隔离级别会在下一个事务开始的时候生效。可以在配置文件中设置整个数据库的隔离级别,也可以只改变当前会话的隔离级别。比如:
SET SESSION TRANSACTION ISLATION LEVEL READ COMMITTED//改变当前连接的隔离级别,另外的连接
//不受影响
查看数据库信息的命令:
show variables;//返回全部的信息
show variables like "%isolation%";//返回包含特定
//字符串的信息
在事务中混合使用存储引擎:
Mysql服务器层不管理事务,事务是由下层的存储引擎实现的。
所以在同一个事务中,使用多种存储引擎是不可靠的。
如果在事务中混合使用了事务型和非事务型的表,在正常情况下没有什么问题。但是!如果事务要回滚,非事务型的表上的变更就无法撤销,这会导致数据库处于不一致的状态,这种情况将很难修复。
所以,为每张表选择合适的存储引擎非常重要。
隐式和显式锁定:
Mysql的大多数事务型存储引擎实现的都不是简单的行级锁。它们一般都同时实现了多版本并发控制(MVCC)。
可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作,因此开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。
SHOW TABLE STATUS;//显示表的相关信息
InnoDB是Mysql的默认事务型引擎,它被设计用来处理大量的短期(short-lived)事务,短期事务大部分情况下是正常提交的,很少会被回滚。InnoDB的性能和自动崩溃恢复特性,使得它在非事务型存储的需求中也很流行。
除非有非常特别的原因需要使用其他的存储引擎,否则应该优先考虑InnoDB引擎。
还有其他很多的引擎
这么多存储引擎,该怎么选择?大部分情况下,InnoDB都是正确的选择,在Mysql5.5即以后都将InnoDB作为默认的存储引擎了。
除非万不得已,否则建议不要混合使用多种存储引擎。
如果应用需要不同的存储引擎,请先考虑以下几个因素。
1.事务:
如果需要事务支持,那么选InnoDB(或者XtraDB)。如果不需要事务,并且主要是SELECT和INSERT操作,那么MyISAM是不错的选择。
2.备份:
如果可以定期关闭服务器来执行备份,那么备份的因素可以忽略。如果需要在线热备份,那么选择InnoDB就是基本的要求。
3.崩溃恢复:
数据量比较大的时候,系统崩溃后如何快速恢复是一个需要考虑的问题。InnoDB这方面比MyISAM好很多。
4.特有的特性:
下面有几个例子可以看看数据库存储引擎的选型问题:
1.日志型应用
假设需要实时地记录一台中心电话机的每一通电话的日志到Mysql中,或者将网站的所有访问信息直接记录到表中。
这类应用的特点是:对插入的速度有很高的要求,数据库不能成为瓶颈。MyISAM或者Archive存储引擎对这类应用比较合适,因为它们开销低,而且插入速度非常快。
再深入一点,还需要对记录的日志做分析报表,这样,生成报表的SQL很有可能会导致插入效率明显降低,该怎么办呢?
方案一:
利用Mysql内置的复制方案将数据复制一份到备库,然后在备库上执行比较消耗时间和CPU的查询。这样主库只用于高效的插入工作,而备库上执行的查询也无须担心影响到日志的插入性能。
方案二:
在日志记录表的名字中包含年和月的信息,这样可以在已经没有插入操作的历史表上做频繁的查询操作,而不会干扰到最新的当前表上的插入操作。
2.只读或者大部分情况下只读的表
注意:
不要低估崩溃恢复问题的重要性,有些存储引擎不会保证讲数据安全地写入到磁盘中,而很多用户实际上并不清楚这样有多大的风险(MyISAM只将数据写入内存中,然后等待操作系统定期将数据刷出到硬盘上)。
当设计上述类型的应用时,建议采用InnoDB。MyISAM引擎在一开始可能没有任何问题,但随着应用压力的上升,各种锁争用,崩溃后的数据丢失等问题会随之而来。
3.订单处理
如果涉及订单处理,那么支持事务是必要选项。还有就是存储引擎对外键的支持情况。InnoDB是订单处理类应用的最佳选择。
4.大数据量
什么样的数据量算大?我们创建或者管理的很多InnoDB数据库的数据量在3-5TB之间,或者更大,这时单台机器上的量,不是一个分片(shard)的量。运行得都很好,只要合理地选择硬件,做好物理设计,并为服务器的I/O做好规划就行。
如果数据量增加到10TB之上,就需要建立数据仓库。Infobright是Mysql数据仓库最成功的解决方案。
注意:
如果转换表的存储引擎,将会失去和原引擎相关的所有特性。例如,如果将一张InnoDB表转换为MyISAM,然后再转换回InnoDB,原InnoDB表上所有的外键将丢失。
有很多种方法可以将表的存储引擎转换为另外一种引擎。
1.ALTER TABLE
ALTER TABLE mytable ENGINE=InnoDB;
上述语法可以适用于任何存储引擎,但有个问题,需要执行很长时间。
2.导出与导入
使用mysqldump将数据导出到文件,然后修改文件中CREATE TABLE语句的存储引擎选项,注意同时修改表名,因为同一个数据库中不能存在相同的表名,即使使用不同的存储引擎。
3.创建与查询(CREATE和SELECT)
第三种技术综合了第一种方法的高效和第二种方法的安全。代码如下:
CREATE TABLE innodb_table LIKE myisam_table;
ALTER TABLE inno_table ENGINE=InnoDB;
INSERT INTO innodb_table SELECT * FROM myisam_table;
如果数据库量很大,可以分批处理:
START TRANSACTION;
INSERT INTO innodb_table SELECT × FROM myisam_table WHERE id BETWEEN x AND y;
COMMIT;
Mysql拥有分层的架构,上层是服务器层的服务和查询执行引擎,下层则是存储引擎。
基准测试(benckmark)是针对系统设计的一种压力测试,通常的目标是掌握系统的行为。
基准测试有两种主要的策略:一是针对整个系统的整体测试,另外是单独测试Mysql。这两种策略也被成为集成式(full-stack)以及单组件式(single-component)基准测试。
一般指标:
1.吞吐量
吞吐量指的是单位时间内的事务处理数。这类基准测试主要针对在线事务处理(OLTP)的吞吐量。非常适用于多用户的交互式应用。常用的测试单位是每秒事务数(TPS)。
2.响应时间或者延迟
3.并发性
并发性是一个非常重要又经常被误解和误用的指标。例如,它经常被表示成多少用户在同一时间浏览同一个Web站点,经常使用的指标是有多少个会话(特别是一些论坛软件,已经让很多管理员错误地相信同时有成千上万的用户正在同时访问网站)。然而,HTTP协议是无状态的,大多数用户只是简单的读取浏览器上显示的信息,这并不等同于Web服务器的并发性。而且,Web服务器的并发性也不等同于数据库的并发性,而仅仅只表示会话存储机制可以处理多少数据的能力。Web服务器的并发性更准确的度量指标,应该是在任意时间有多少同时发生的并发请求。
Web服务器的高并发,一般也会导致数据库的高并发,但服务器采用的语言和工具集对此都会有影响。注意不要将创建数据库连接和并发性搞混淆。一个设计良好的应用,同时可以打开成百上千个Mysql数据库服务器连接,但可能同时只有少数连接在执行查询,所以说,一个Web站点“同时有50000个用户访问”,但可能只有10-15个并发请求到Mysql数据库。
工具如下:
1.ab
ab是一个Apache HTTP服务器基准测试工具。可以测试HTTP服务器每秒最多可以处理多少请求。如果测试的是Web应用服务,这个结果可以转换成整个应用每秒可以满足多少请求。只能针对单个URL进行尽可能快的压力测试。
2.http_load,JMeter等等,自己用时查吧
有一些可用的工具可以测试Mysql和Mysql系统的性能。
工具如下;
1.mysqlslap
2.MYSQL Benchmark Suite(sql-bench)
3.Super Smack
4.Database Test Suite
5.sysbench
最常碰到的三个性能相关的服务请求是:
1.如何确认服务器是否达到了性能最佳的状态
2.找出某条语句为什么执行不够快
3.诊断被用户描述成“停顿”,“堆积”,或者“卡死”的某些间歇性疑难故障
我们将性能定义为完成某件任务所需要的时间度量,换句话说,性能即响应时间,这是一个重要的原则。
还有另一个问题:什么是优化?
假如你认为性能优化是降低CPU利用率,那么可以减少对资源的使用。但这是一个陷阱,资源是用来消耗并用来工作的,所以有时候消耗更多的资源能够加快查询速度。
同样,如果把性能优化仅仅看成是提升每秒查询量,这其实只是吞吐量优化。吞吐量的提升可以看做是性能优化的副产品。
如果目标是降低响应时间,那么就需要理解为什么服务器执行查询需要这么多的时间,然后去减少或者消除那些对获得查询结果来说不必要的工作。
这引出了优化的第二个原则:无法测量就无法有效地优化。所以第一步应该测量时间花在什么地方。