一.MySQL服务器架构的逻辑视图
1.连接管理与安全性
2.优化查询
1>解析查询
2>创建内部数据结构(解析树)
3> 优化
重写查询
2>创建内部数据结构(解析树)
3> 优化
重写查询
决定查询的
读表顺序
选择需使用的
索引
- 存储引擎对服务器的查询优化过程有影响。
- 服务器会“询问”查询缓存。
- 用户可以通过特殊的关键字给优化器传递各种提示,影响它的优化过程。还可以请求服务器给出优化过程的各种说明.使用户可以知晓服务器是如何进行优化决策的,为用户提供一个参考基准。方便用户重写查询,架构和修改相关配置,便于应用尽可能高效的运行。
二.
并发控制
1.
读锁(Read Lock)/
写锁(Write Lock)
某一资源上的
读锁是共享的,或者说是互补阻塞的。在同一时间,多个用户可以同时读取同一资源,而互不干扰。
写锁是排他的,一个写锁会阻塞其他的读锁或者写锁。在给定时间里,只有一个用户能写入资源。
2.
锁粒度(Lock Granularity)
一种提高共享资源并发性的方法:
只锁定部分须修改的数据,而不是所有的资源。任何时间,在给定的资源上,被加锁的数据量越小,就可以允许更多的并发修改,只要相互之间互不冲突即可。
另外一方面,
加锁也会消耗系统资源。每一种锁操作,如获得锁,检查锁是否已解除,以及释放锁等。都会增加系统的开销。如果系统花大量时间来管理锁,而不是读/写数据,那么系统整体性能可能会受此影响。
所谓的锁策略,就是在锁开销和数据安全之间寻求一种平衡,这种平衡也能影响系统性能。
表锁
MySQL中,开销最小的锁策略是
表锁。
行级锁
行级锁可以带来最大的并发处理(同时也带来最大的开销)。
三.
事务
关于事务,银行应用是一个
经典的案例,可以解释事务应用的必要性。假设一银行数据库有两张表,checking表和saving表。现在要从Jane的支票账户(checking Account)转账200美元到她的存款账户(savings Account),那么需要完成至少三步操作:
1.检查支票存款账户的余额是否大于200$
2.从支票存款账户余额中减去200$
3.在存款账户余额中增加200$
所有的操作被打包到一个事务里,如果某一步失败,就
回滚(rollback)所有已完成的步骤。
可以用start transaction 语句开始一个事务,用COMMIT语句提交整个事务,永久的修改数据,或者用ROLLBACK语句回滚整个事务,取消已做的修改。事务SQL案例如下:
1.start transaction;
2.
select balance
from checking
where custom_id = 1005373;
3.
update checking
set balance = balance -200.00
where customer_id = 1005373;
4.
update savings
set balance = balance + 200.00
where customer_id = 1005373;
5.
commit;
试想一下,如果数据库服务器在执行第4句语句时,数据库突然崩溃,会发生什么事儿?没有人知道,但是用户可能会损失200元美元。再加入,在执行第3和第4句之间时,另一个进程同时运行,它的母的是要先删除支票账户的全部余额,那么结果可能是,银行根本不知道有这个逻辑事先发生,白白给用户增加了200元存款。
除非系统通过ACID测试,否则空谈事务概念是不够的,ACID代表了原子性,一致性,隔离性和持久性。这些概念与事务的处理标准密切关联,一个有效的事务处理系统必须满足相关标准。
a.原子性 b.一致性 c.隔离性 d.持久性
1.隔离级
读取未提交内容
读取提交内容
可重读
可串行化
读取未提交内容和可重读的区别:
如果你从控制的角度来看,两者的区别就比较大:对于前者,只需要锁住满足条件的记录;对于后者,要锁住满足条件及其附近的记录。
2.
死锁
死锁是指两个或者多个事务在同一资源上互相占用,并请求加锁时,而导致的恶性循环现象。当多个事务以不同顺序试图对同一资源加锁时,就会产生死锁。任何时间,多个事务同时加锁一个资源,一定产生死锁。例如,设想下列两个事务同时处理StockPrice表:
事务1
start transaction;
update StockPrice set close = 45.50 where stock_id = 4 and date = '2002-05-01';
update StockPrice set close = 19.80 where stock_id = 3 and date = '2002-05-02';
commit;
事务2
start transaction;
update StockPriceset close = 19.80where stock_id = 3and date ='2002-05-02';
update StockPriceset close = 45.50where stock_id = 4and date ='2002-05-01';
commit;
如果很不幸凑巧,每个事务在处理过程中,都执行了第一个查询,又更新了数据行,也加锁了该数据行。接着,每个事务都去视图更新第二个数据行,却发现该行已被(对方)加锁,然后两个事务都开始互相等待对方完成,陷入无限等待中,除非有外部因素介入,才能解除死锁。
为了解决这个问题,数据库系统事先了各种死锁检测和死锁超时机制。对于更复杂的系统。例如InnoDB存储引擎,可以
预测循环相关性,并立即返回错误。这种解决方式实际很有效,否则死锁将导致很慢的查询,其他的解决方式,是
让查询到达一个锁等待超时时间,然后再放弃争用,但这种方式不够好。目前InnoDB处理死锁的方法是,回滚拥有最少排他行级的事务(一种对最易回滚事务的大致估算)
三.
事务日志
事务日志可使事务处理过程更加高效,和每次数据以改变就更新磁盘中表数据的方式不同,存储引擎可以先更新数据的内存中得拷贝。这非常快,然后,存储引擎将数据改变记录写入事务日志,它位于磁盘上,因此具有持久性。这相对较快,因为
追加日志事件导致的写操作,只涉及了磁盘很小区域上得顺序I/O(Sequential I/O),而替代了写磁盘中表所需要的大量随机I/O(Random I/O). 最后,相关进程会在某个事件把表数据更新到磁盘上。因此大多存储引擎都选用了这种技术,也是通常所说的预写式日志,利用两次磁盘写入操作把数据改变磁盘。
四,
多版本并发控制(MVCC , Multiversion Concurrentcy Control)
五.
为自己的应用选择合适的数据库引擎
在设计基于MySQL的应用时,要决定选择何种存储引擎来存储数据。如果不在设计阶段就考虑这个问题,在后续工作中可能就会面临复杂的问题。用户可能会发现默认配置的引擎并不能满足自己的某种需要,比如事务。或者,应用产生的混合读写查询需要更细粒度的加锁机制,而不是MyISAM提供的表锁。
引擎的选择可以基于每一张表,因此,需要清醒的考虑如何使用每一张表,以及如何存储数据。这种考虑也有助用户从整体上正确的理解应用,并且预测应用的增长需求,理解和掌握相关信息
为自己的应用选择合适的引擎。