MySQL的MyISAM引擎如今愈来愈被淡化了,可是仍是有必要再温习总结一下的。mysql
容许你改变语句调度的优先级,它可使来自多个客户端的查询更好地协做,这样单个客户端就不会因为锁定而等待很长时间。改变优先级还能够确保特定类型的查询被处理得更快。这一部 分讲解MySQL的默认的调度策略和能够用来影响这些策略的选项。它还谈到了并发性插入操做的使用和存储引擎锁定层次对客户端的并发性的影响。为了讨论的 方便,咱们把执行检索(SELECT)的客户端称为"读取者",把执行修改操做(DELETE、INSERT、REPLACE或UPDATE)的客户端称 为"写入者"。sql
MySQL的默认的调度策略可用总结以下:
· 写入操做优先于读取操做。
· 对某张数据表的写入操做某一时刻只能发生一次,写入请求按照它们到达的次序来处理。
· 对某张数据表的多个读取操做能够同时地进行。
MyISAM和MEMORY存储引擎借助于数据表锁来实现这样的调度策略。当客户端访问某张表的时候,首先必须获取它的锁。当客户端完成对表的 操做的时候,锁就会被解除。经过LOCK TABLES和UNLOCK TABLES语句来显式地获取或释放锁是可行的,可是在一般状况下,服务器的锁管理器会自动地在须要的时候获取锁,在再也不须要的时候释放锁。获取的锁的类 型依赖于客户端是写入仍是读取操做。
对某张表进行写入操做的客户端必须拥有独占的(排他的)访问权的锁。操做在进行的过程当中,该数据表处于不一致的(inconsistent)状 态,由于数据记录在删除、添加或修改的时候,数据表上的索引也可能须要更新以相互匹配。这个数据表在变化的过程当中,若是容许其它的客户端访问,会出现问 题。很是明显,容许两个客户端同时写入一张数据表是不利的,由于这样的操做会很快使数据表中的信息成为一堆无用的垃圾。可是容许客户端读取变化之中的数据 表也很差,由于正在读取的位置中的数据可能正在变化(修改),读取的结果可能不是真实的。
对某张表执行读取操做的客户端必须获取一个锁,防止在读取的过程当中,其它的客户端写入或改变表。可是这个锁不须要独占的访问权。读取操做不会改变数据,所以没有理由让某个读取者阻止其它的读取者访问这张表。所以读取锁容许其它的客户端在同一时刻读取这张表。
MySQL提供了几个语句调节符,容许你修改它的调度策略:
· LOW_PRIORITY关键字应用于DELETE、INSERT、LOAD DATA、REPLACE和UPDATE。
· HIGH_PRIORITY关键字应用于SELECT和INSERT语句。
· DELAYED关键字应用于INSERT和REPLACE语句。服务器
LOW_PRIORITY和HIGH_PRIORITY调节符影响那些使用数据表锁的存储引擎(例如MyISAM和MEMORY)。DELAYED调节符做用于MyISAM和MEMORY数据表。并发
改变语句调度的优先级
LOW_PRIORITY关键字影响DELETE、INSERT、LOAD DATA、REPLACE和UPDATE语句的执行调度。一般状况下,某张数据表正在被读取的时候,若是有写入操做到达,那么写入者一直等待读取者完成操 做(查询开始以后就不能中断,所以容许读取者完成操做)。若是写入者正在等待的时候,另外一个读取操做到达了,该读取操做也会被阻塞(block),由于默 认的调度策略是写入者优先于读取者。当第一个读取者完成操做的时候,写入者开始操做,而且直到该写入者完成操做,第二个读取者才开始操做。
若是写入操做是一个LOW_PRIORITY(低优先级)请求,那么系统就不会认为它的优先级高于读取操做。在这种状况下,若是写入者在等待的时候,第 二个读取者到达了,那么就容许第二个读取者插到写入者以前。只有在没有其它的读取者的时候,才容许写入者开始操做。理论上,这种调度修改暗示着,可能存在 LOW_PRIORITY写入操做永远被阻塞的状况。若是前面的读取操做在进行的过程当中一直有其它的读取操做到达,那么新的请求都会插入到 LOW_PRIORITY写入操做以前。
SELECT查询的HIGH_PRIORITY(高优先级)关键字也相似。它容许 SELECT插入正在等待的写入操做以前,即便在正常状况下写入操做的优先级更高。另一种影响是,高优先级的SELECT在正常的SELECT语句以前 执行,由于这些语句会被写入操做阻塞。
若是你但愿全部支持LOW_PRIORITY选项的语句都默认地按照低优先级来处理,那么请使用--low-priority-updates选项来启动服务器。经过使用INSERT HIGH_PRIORITY来把INSERT语句提升到正常的写入优先级,能够消除该选项对单个INSERT语句的影响。高并发
使用延迟插入操做
DELAYED调节符应用于INSERT和REPLACE语句。当 DELAYED插入操做到达的时候,服务器把数据行放入一个队列中,并当即给客户端返回一个状态信息,这样客户端就能够在数据表被真正地插入记录以前继续 进行操做了。若是读取者从该数据表中读取数据,队列中的数据就会被保持着,直到没有读取者为止。接着服务器开始插入延迟数据行(delayed-row) 队列中的数据行。在插入操做的同时,服务器还要检查是否有新的读取请求到达和等待。若是有,延迟数据行队列就被挂起,容许读取者继续操做。当没有读取者的 时候,服务器再次开始插入延迟的数据行。这个过程一直进行,直到队列空了为止。
感受上LOW_PRIORITY和DELAYED是相 似的,二者都容许数据行插入操做被延迟,可是它们对客户端操做的影响却有很大的差别。LOW_ PRIORITY强迫客户端等待,直到那些数据行能够被插入数据表。DELAYED容许客户端继续操做,服务器在内存中缓冲那些数据行,直到本身有时间处 理它们。
若是其它的客户端可能运行很长的SELECT语句而且你不但愿阻塞,等待插入操做完成的时候,INSERT DELAYED就很是有用处了。客户端提交INSERT DELAYED的时候可能处理得很快,由于服务器只是简单地把要插入的数据行排队。
可是,你也必须知道正常的INSERT与INSERT DELAYED行为之间的一些其它的差别。若是INSERT DELAYED语句包含语法错误,客户端会获得一个错误,可是却没法获得其它一些在正常状况下可使用的信息。例如,当语句返回的时候,你没法依赖(得 到)AUTO_INCREMENT(自动增加)值。一样,你没法获得惟一索引的副本数量。发生这种状况的缘由在于插入操做在真正地被执行以前已经返回了状 态信息。另外一种可能出现的状况是,因为INSERT DELAYED语句的数据行都在内存中排队,当服务器崩溃或者使用kill -9退出的时候,数据行可能丢失(正常状况下,kill -TERM终止命令不会致使这种状况,由于服务器在退出以前会把数据行插入表中)。性能
使用并发的插入操做
MyISAM存储引擎有一条例外的规则,它容许读取者阻塞写入者。这种现象发生在MyISAM数据表中间没有"空洞"(多是删除或更新数据行的结果) 的状况下。当数据表没有"空洞"的时候,任何INSERT语句必然在末尾而不是中部添加数据行。在这种状况下,MySQL容许其它客户端在读取数据的同时 向数据表添加数据行。这就是"并发性插入操做",由于它们同时发生,检索并无被阻塞。
若是你但愿使用并发性插入操做,请注意下面一些事项:
· 在INSERT语句中不要使用LOW_PRIORITY调节符。它会引发INSERT常常被读取者阻塞,所以阻碍了并发性插入操做的执行。
· 若是读取者须要显式地锁定数据表以执行并发性插入操做,就应该使用LOCK TABLES ... READ LOCAL,而不是LOCK TABLES ... READ。LOCAL关键字会获取一个锁,容许并发性操做继续进行,由于它只能应用于数据表中已有的数据行,不会阻塞那些添加到末尾的新数据行。
· LOAD DATA操做应该使用CONCURRENT调节符,容许该数据表上的SELECT语句同时执行。
· 中间包含了"空洞"的MyISAM数据表不能使用并发性插入操做。可是,你可使用OPTIMIZE TABLE语句来整理该数据表的碎片。----concurrent_insert:0,1,2spa
锁的层次和并发性
前面讨论的调度调节符容许你改变默认的调度策略。其中的大部份内容都是介绍使用这些调节符来解决数据表层次(table-level)的锁引发的问题,这都是MyISAM和MEMORY存储引擎用来管理数据表争用的问题的。
BDB和InnoDB存储引擎实现了不一样层次的锁,因此其性能特征和对争用的管理是不一样的。BDB引擎使用页面层次(page-level)的锁。 InnoDB引擎使用数据行层次(row-level)的锁,可是只在必要的时候使用(在不少状况下,例如当读取操做都完成的时候,InnoDB可能根本 就不使用锁)。
存储引擎使用的锁的层次对客户端的并发操做有很大的影响。假设两个客户端都但愿更新某个数据表中的一行。因为要执行更新,每一个客户端都须要一个写入锁。对于MyISAM数据表,引擎会为第一个客户端分配一个锁,这会引发第二个客户端阻塞,直到第一个客户端完成操做。对于 BDB数据表,它能够实现更大的并发性:两个更新操做会同步进行,除非两个数据行都位于同一个页面中。在InnoDB数据表中,并发性更高;只要两个客户 端没有更新同一行,两个更新操做就能同时发生。索引
通常的规则是,锁的层次越细微,并发性越好,由于只要客户端使用数据表的部分不一样,那么使用表的客户端就能够更多。
· MyISAM检索的速度很是快。可是使用表层次的锁可能成为混合的检索和更新环境中的问题,特别是检索倾向于长时间运行的时候。在这些条件下,更新可能须要等待好久才能进行。
· 当更新操做不少的时候,BDB和InnoDB数据表能够提供更好的性能。因为锁在页面或数据行层次进行,表被锁定的范围较小。这会减小锁的争用,提升并发性。队列
在防止死锁(deadlock)方面,表锁比行锁更有优点。使用表锁的时候,死锁不会发生。由于服务器能够经过查看语句来检测须要的数据表,并提早锁定它们。而InnoDB会发生死锁,由于存储引擎没有在事务开始的时候分配全部必要的锁。而是在事务处理的过程当中,当检测到须要锁的时候才分配。这就可能出现两个语句获取了锁,接着试图进一步获取锁(须要多个锁),可是这些锁却被对方保持着,等待对方释放。其结果是每一个客户端都拥有一个锁,同时还须要利用其它的客户端拥有的锁才能继续执行。这会致使死锁,服务器必须终止其中一个事务。事务
使用方法:
优先操做 HIGH_PRIORITY
HIGH_PRIORITY可使用在select和insert操做中,让MYSQL知道,这个操做优先进行。
SELECT HIGH_PRIORITY * FROM TABLE1;
滞后操做 LOW_PRIORITY
LOW_PRIORITY可使用在insert和update操做中,让mysql知道,这个操做滞后。
update LOW_PRIORITY table1 set field1= where field1= …
延时插入 INSERT DELAYED
INSERT DELAYED INTO table1 set field1= …
INSERT DELAYED INTO 是客户端提交数据给MySQL,MySQL返回OK状态给客户端。而这是并非已经将数据插入表,而是存储在内存里面等待排队。当mysql有空余时,再插入。另外一个重要的好处是,来自许多客户端的插入被集中在一块儿,并被编写入一个块。这比执行许多独立的插入要快不少。坏处是,不能返回自动递增 的ID,以及系统崩溃时,MySQL尚未来得及插入数据的话,这些数据将会丢失。