一般状况下,当访问某张表的时候,读取者首先必须获取该表的锁,若是有写入操做到达,那么写入者一直等待读取者完成操做(查询开始以后就不能中断,所以容许读取者完成操做)。当读取者完成对表的操做的时候,锁就会被解除。若是写入者正在等待的时候,另外一个读取操做到达了,该读取操做也会被阻塞(block),由于默认的调度策略是写入者优先于读取者。当第一个读取者完成操做并解放锁后,写入者开始操做,而且直到该写入者完成操做,第二个读取者才开始操做。mysql
经过LOCK TABLES和UNLOCK TABLES语句能够显式地获取或释放锁,可是在一般状况下,服务器的锁管理器会自动地在须要的时候获取锁,在再也不须要的时候释放锁。获取的锁的类型依赖于客户端是写入仍是读取操做。sql
对某张表进行写入操做的客户端必须拥有独占的(排他的)访问权的锁。操做在进行的过程当中,该数据表处于不一致的(inconsistent)状态,由于数据记录在删除、添加或修改的时候,数据表上的索引也可能须要更新以相互匹配。容许两个客户端同时写入一张数据表是不利的,由于这样的操做会很快使数据表中的信息成为一堆无用的垃圾。同时容许客户端读取变化之中的数据表也不正确,由于正在读取的位置中的数据可能正在变化(修改),读取的结果可能并非真实的。所以对某张表执行读取操做的客户端也必须获取一个锁,防止在读取的过程当中,其它的客户端写入或改变表。可是这个锁不须要独占的访问权。由于读取操做不会改变数据,所以没有理由让某个读取者阻止其它的读取者访问这张表。故读取锁可容许其它的客户端在同一时刻读取这张表。数据库
虽然经过锁机制,能够实现多线程同时对某个表进行操做,但当某个线程做更新操做时,首先要得到独占的访问权。在更新的过程当中,全部其它想要访问这个表的线程必需要等到其更新完成为止。此时就会致使锁竞争的问题,从而致使用户等待时间的延长。 缓存
要提升MySQL的更新/插入效率,应首先考虑下降锁的竞争,减小写操做的等待时间。 服务器
1.同时插入多行记录时,宜使用多个值表的INSERT 语句多线程
若是能够同时从同一客户插入不少行时,宜使用多个值表的INSERT 语句。多个值表的 INSERT 语句 ,能够大大缩减客户端与数据库之间的链接、语法分析等消耗,使得效率比分开执行的单个 INSERT 语句快不少。性能
如批量插入:线程
INSERT INTO tb (fa, fb, fc) VALUES ('1', '12', '13'), ('2', '22', '23'), ('3', '32', '33'), 索引
多值的 INSERT语句还能够经过调整 bulk_insert_buffer_size 参数来提升数据插入的效率,这个参数设置的是 bulk insert 的缓存大小,默认是 8M 。注意,这只能对myisam表使用。队列
2.考虑使用replace 语句代替insert语句
根据应用状况可使用replace 语句代替insert/update语句。例如:若是一个表在一个字段上创建了惟一索引,当向这个表中使用已经存在的键值插入一条记录,将会抛出一个主键冲突的错误。若是咱们想用新记录的值来覆盖原来的记录值时,就可使用REPLACE语句。
使用REPLACE插入记录时,若是记录不重复(或往表里插新记录),REPLACE功能与INSERT同样,若是存在重复记录,REPLACE就使用新记录的值来替换原来的记录值。使用REPLACE的最大好处就是能够将DELETE和INSERT合二为一,造成一个原子操做。这样就能够没必要考虑同时使用DELETE和INSERT时添加事务等复杂操做了。
在使用REPLACE时,表中必须有惟一有一个PRIMARY KEY或UNIQUE索引,不然,使用一个REPLACE语句没有意义。
mysql replace语句:
用法1:replace into:
replace into table (id,name) values('1','aa'),('2','bb')
此语句的做用是向表table中插入两条记录。若是主键id为1或2不存在就至关于插入语句:
insert into table (id,name) values('1','aa'),('2','bb')
若是存在相同的值则不会插入数据。
用法2:replace(object, search, replace)
做用是把object中出现search的所有替换为replace,例:
select replace(‘abc’, ‘b’, ‘x’);
例:把表table中的name字段中的aa替换为bb
update table set name=replace(name,'aa','bb')
注意:UPDATE和REPLACE的区别:
1)UPDATE在没有匹配记录时什么都不作,而REPLACE在有重复记录时更新,在没有重复记录时插入。
2)UPDATE能够选择性地更新记录的一部分字段。而REPLACE在发现有重复记录时就将这条记录完全删除,再插入新的记录。也就是说,将全部的字段都更新了。
3.在插入大量数据以前,能够先将表锁定(Lock Tables)
为了提升数据插入的效率,能够考虑在插入以前先将表锁定。这主要是由于直到全部的INSERT语句都完成以后,索引缓存一次性刷新到磁盘中。一般状况下,有多少次INSERT语句就会有多少次索引缓存刷新到磁盘中的开销。为此在数据插入以前,将数据表进行锁定,就能够大幅度的提升数据插入的效率。固然,若是你能够用一个插入语句实现全部行的插入,则无需使用显式锁定语句。(针对非事务性表)
所以若是一个表的更新频率比较高时,那么可使用Lock Tables选项来提升更新速度。
对于事务性表,要想更快地进行表插入,可使用START TRANSACTION和COMMIT语句代替LOCK TABLES来提升更新速度。
4.能够对myisam表并行插入Concurrent_insert系统变量能够被设置用于修改concurrent-insert处理。
该变量默认设置为1。若是concurrent_insert被设置为0,并行插入就被禁用。若是该变量被设置为2,在表的末端能够并行插入,即使该表的某些行已经被删除。
5.使用插入延迟
若是客户无需等待插入完成的时候(即用户对插入数据的即时性要求可能并非很高),此时就能够考虑采用插入延迟特性。Delayed 的含义是让insert 语句立刻执行并返回,而数据被放在内存的队列中等待被插入,并无真正的写入磁盘;这比每条语句都分别插入要快的多。
使用插入延迟的另外一个好处就是从多个客户插入的状况会被绑定并记录在同一个block中。
默认状况下,在MySQL数据库中,更新操做比Select查询有更高的优先级。MySQL的默认的调度策略可用总结以下:
• 写入操做优先于读取操做。
• 对一张数据表的写入操做同一时刻只能发生一次,写入请求按照它们到达的次序来处理。
• 对一张数据表的多个读取操做能够同时地进行。
MySQL容许改变语句调度的优先级,它可使来自多个客户端的查询更好地协做,这样单个客户端就不会因为锁定而等待很长时间。改变优先级还能够确保特定类型的查询被处理得更快。经过如下三种方式来修改它的调度策略:
• LOW_PRIORITY关键字应用于DELETE、INSERT、LOAD DATA、REPLACE和UPDATE。这个属性能够将某个特定的语句的优先级下降。如能够调低某个特定的更新语句或者插入语句的优先级。不过须要注意的是,这个属性只有对特定的语句有用。即其做用域只针对某个特定的语句,而不会对全局形成影响。
例:UPDATE [LOW_PRIORITY] tbl_name SET col_name1=expr1,col_name2=expr2,...
mysql中update用low_priority让update不锁定表
• HIGH_PRIORITY关键字应用于SELECT和INSERT语句。这个属性能够用来提升某个特定的Select查询语句的优先级。LOW_PRIORITY恰好相反,在全部其余用户对表的读写完成后才进行插入。这里须要注意,跟上面这个属性同样,这个做用域也只限于特定的查询语句。而不会对没有加这个参数的其余查询语句产生影响。也就是说,其余查询语句若是没有加这个属性,那么其优先级别仍然低于更新进程。
• DELAYED关键字应用于INSERT和REPLACE语句。
LOW_PRIORITY和HIGH_PRIORITY调节符影响那些使用数据表锁的存储引擎(例如MyISAM和MEMORY)。DELAYED调节符做用于MyISAM和MEMORY数据表。
一般状况下,某张数据表正在被读取的时候,若是有写入操做到达,那么写入者一直等待读取者完成操做(查询开始以后就不能中断,所以容许读取者完成操做)。若是写入者正在等待的时候,另外一个读取操做到达了,该读取操做也会被阻塞(block),由于默认的调度策略是写入者优先于读取者。当第一个读取者完成操做的时候,写入者开始操做,而且直到该写入者完成操做,第二个读取者才开始操做。
若是写入操做是一个LOW_PRIORITY(低优先级)请求,那么系统就不会认为它的优先级高于读取操做。在这种状况下,若是写入者在等待的时候,第二个读取者到达了,那么就容许第二个读取者插到写入者以前。只有在没有其它的读取者的时候,才容许写入者开始操做。理论上,这种调度修改暗示着,可能存在LOW_PRIORITY写入操做永远被阻塞的状况。若是前面的读取操做在进行的过程当中一直有其它的读取操做到达,那么新的请求都会插入到LOW_PRIORITY写入操做以前。
SELECT查询的HIGH_PRIORITY(高优先级)关键字也相似。它容许SELECT插入正在等待的写入操做以前,即便在正常状况下写入操做的优先级更高。另一种影响是,高优先级的SELECT在正常的SELECT语句以前执行,由于这些语句会被写入操做阻塞。
若是但愿某一链接支持LOW_PRIORITY选项来处理,那么经过Set LOW_PRIORIT_UPDATES=1来设置链接变量,经过这个设置能够制定具体链接中的全部更新进程都是用比较低的优先级。但注意这个选项只针对特定的链接有用。对于其余的链接,就不适用。
若是但愿全部支持LOW_PRIORITY选项的语句都默认地按照低优先级来处理,那么请使用--low-priority-updates选项来启动服务器。采用这个选项启动数据库时,系统会给数据库中全部的更新语句比较低的优先级。经过使用INSERT HIGH_PRIORITY来把INSERT语句提升到正常的写入优先级,能够消除该选项对单个INSERT语句的影响。
6.使用LOAD DATA INFILE从文本下载数据将比使用插入语句快20倍。
Load Date Infile是从一个文件中导入数据。若是采用这种方式的话,用户须要预先准备一个固定格式的文件。若是插入的数据量比较多,例如软件运行环境配置时可能会导入大量预配置数据时,此时使用Load Date Infile的方式可以取得比较好的性能。
执行LOAD DATA INFILE,数据插入到表中,因为无需更新表索引,所以这将很是快。
7.将大表分为多个小表来下降锁竞争
一些大表或频繁更新的表中,因为表的访问量较大,所以锁竞争也比较严重。此时,能够人为地将表合理分为多个小表,使表访问分散到多张表上,相互之间不会产生干扰时,就会下降表上锁的竞争,从而提升了访问效率。而当须要访问完整数据时,能够经过视图进行整合成一张表。
在实际应用中,会赶上即有更新操做又有插入操做又有查询操做时,要根据特定的状况,综合应用上述方法来提升访问效率。