Chinaunix首页 | 论坛 | 博客
  • 博客访问: 17135
  • 博文数量: 22
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 240
  • 用 户 组: 普通用户
  • 注册时间: 2014-02-18 10:33
文章分类
文章存档

2015年(22)

我的朋友

分类: Mysql/postgreSQL

2015-03-01 12:05:29

    MySQL的管理争用锁表的内容:
  • 内部锁是MySQL服务器本身进行管理争用多个线程表的内容。这种类型的锁的是内部,因为它是由服务器完全执行,并且不涉及任何其它程序。

  • 外部锁出现在服务器和其他程序锁定MyISAM表文件本身之间进行协调的程序此时可以访问的表。

1.内部锁方法(Internal Locking Methods)

    这种类型的锁的是内部,因为它是由服务器完全执行,并且不涉及任何其它程序。

行级锁(Row-Level Locking)

    MySQL使用行级锁的InnoDB表,以支持多个会话同时进行写访问权限,使得它们适用于多用户,高并发和OLTP应用程序。

    要在一个单一的InnoDB表执行多个并发写操作时,为了避免死锁,获得必要的锁在事务开始执行SELECT... FOR UPDATE语句为每个组有望被修改的行,即使在DML语句来稍后在该事务执行。如果事务修改或锁定多个表,发出的每个事务中以相同的顺序的应用语句。死锁会影响性能而不是表示一个严重的错误,因为InnoDB 自动检测死锁条件,并回滚受影响的其中一个事务。

    行级锁的优点:
  • 在不同的会话访问不同行更少的锁冲突。
  • 回滚更少的变化。
  • 可以锁定单个行很长一段的时间。

表级锁(Table-Level Locking)

    MySQL使用表级锁定对MyISAM,MEMORY和MERGE表,只允许一个会话时间来更新这些表,这使得它们更适合于只读,读为主,或单用户应用程序。

    这些存储引擎避免死锁始终要求所有需要锁立即在查询的开始始终锁定表中的顺序相同。代价是这种策略减少并发;想要修改表中的其他会话必须等到当前DML语句 结束。
    
    MySQL的授权表锁如下:
  1. 如果在表上没有锁,放一个写锁就可以了。
  2. 否则,放在写锁队列中的请求。

    MySQL的授权表读锁如下:
  1. 如果存在表上没有写锁,放一个读锁就可以了。
  2. 否则,放在读锁队列中的请求。

    表更新的优先级高于表检索。因此,当锁被释放时,该锁被提供给在写锁定队列中的请求,然后在读锁队列中的请求。这可确保更新的表不是“starved”,即使有大的活跃SELECT访问该表。但是,如果一个表有许多更新,SELECT语句等待直到有没有更多的更新。

    可以通过系统上Table_locks_immediateTable_locks_waited状态变量检查分析表锁争用,这表明对于表锁可以立即授予请求的次数并且必须等待数,分别:
        mysql> SHOW STATUS LIKE 'Table%';
        +-----------------------+---------+
        | Variable_name         | Value |
        +-----------------------+---------+
        | Table_locks_immediate | 1151552 |
        | Table_locks_waited | 15324 |
        +-----------------------+---------+

    MyISAM存储引擎支持的并发插入,以减少reader和writer之间的竞争给定表:如果一个MyISAM表中有数据文件的中间没有空闲块,行总是插入到数据文件的结尾。在这种情况下,可以自由地混合并行的INSERT和SELECT语句而不锁MyISAM表。也就是说,可以在同一时间其他客户都从中读取插入行的MyISAM表。Holes会导致从行已经被删除或者在表的中间更新。如果有Holes,并发性插入操作被禁止,但当所有的Holes已填充新的数据再次被自动启用..此行为是由concurrent_insert系统变量更改。

    如果明确地获得了一个LOCK TABLES表锁,可以要求READ LOCAL锁定,而不是一个读锁,使其他会话执行并行插入同时你有该表锁。

    在表real_table执行许多INSERT和SELECT操作时并发插入是不可能的,可以插入行到一个临时表temp_table并与定期从临时表更新行到真正的表 。这可以用下面的代码来实现:
        mysql> LOCK TABLES real_table WRITE, temp_table WRITE;
        mysql> INSERT INTO real_table SELECT * FROM temp_table;
        mysql> DELETE FROM temp_table;
        mysql> UNLOCK TABLES;

    表级锁的优点:
  • 需要相对较少的内存。
  • 速度快因为当使用一个表大部分内容时只有一个锁被激活。
  • 如果经常做GROUP BY操作上的数据的很大一部分,或者如果要频繁扫描整个表会更快。

    通常,表锁适合于以下情况:
  • 大多数语句对表是读取操作。
  • 该表的语句是一个混合的读取和写入,在写操作更新或删除的,可以用的一个关键读取可读取单行:
        UPDATE tbl_name SET column=value WHERE unique_key_col=key_value; 
        DELETE FROM tbl_name WHERE unique_key_col=key_value;
  • SELECT结合并行的INSERT语句,只有极少数的UPDATE或DELETE语句。
  • 整个表上的许多扫描或GROUP BY操作,没有任何写操作。

2.表锁的问题(Table Locking Issues)

    InnoDB表使用行级锁使多个会话和应用程序可以同时读写同一个表,而不进行相互等待或产生不一致的结果。对于这个存储引擎,避免使用LOCK TABLES语句,因为它没有提供任何额外保护,反而会降低并发。自动行级锁定让这些表适用于最繁忙的数据库的最重要数据,同时还简化了应用程序逻辑,因为不需要锁定和解锁表。因此,在MySQL5.6默认存储引擎InnoDB。

    MySQL使用表锁定(代替页,行或列锁定)的所有存储引擎,InnoDB的除外。锁定操作本身并没有太多的开销。但由于只有一个会话可以在任何一个时间写一个表,与这些其他存储引擎的最佳性能,请使用它们主要是为那些经常查询而很少插入或更新的表。

InnoDB主要表现的性能注意事项

    当选择是否要创建一个使用InnoDB的或者不同的存储引擎的表,记住表锁定的以下缺点:
  • 表锁定使许多会话从表中读取的同时,但如果一个会话想要写一个表,它必须首先获得独占访问,这意味着它可能需要等待其他会话与表完成第一次访问。在更新过程中,其他所有会话希望访问这个特殊的表必须等到更新完成。
  • 当一个会话正在等待因为磁盘已满并且自由空间需要变得可用在会话可以继续进行之前表锁定引起问题。在这种情况下,要访问的问题表的所有会话都给出在一个等待状态,直到更多的磁盘空间可用。
  • 一个SELECT语句是需要很长的时间来运行阻止其他会话不能更新该表的同时,使得其它会话出现缓慢或无响应。当一个会话正在等待获得独占访问表的更新,即发出SELECT语句等会议将排队背后,减少并发即使是只读会话。

解决锁定性能问题方法(Workarounds for Locking Performance Issues)

    以下各项介绍一些方法来避免或减少争用所造成的表锁定:
  • 考虑转换该表到InnoDB存储引擎,或者使用安装过程中CREATE TABLE... ENGINE = INNODB,或现有表使用ALTER TABLE... ENGINE = INNODB。更多信息查看14.2, “The InnoDBStorage Engine”。
  • 优化SELECT语句使它们运行得更快使锁定表的时间更短。可能需要创建一些汇总表来做到这一点。
  • 启动mysqld  --low-priority-updates。对于只使用表级锁(如MyISAM表,MEMORY和MERGE)存储引擎,这使所有语句更新(修改)一个表的优先级低于SELECT语句。在这种情况下,在前面的情况下第二个SELECT语句将在UPDATE语句前执行,而不会等待第一个SELECT完成。
  • 要指定一个特定的连接发出的所有更新应该以低优先级来实现,设置LOW_PRIORITY_UPDATES服务器系统变量为1。
  • 授予一个具体的INSERT,UPDATE或DELETE语句优先级较低的,使用LOW_PRIORITY属性。
  • 为了给出一个具体的SELECT语句更高的优先级,使用HIGH_PRIORITY属性。
  • 启动mysqld的max_write_lock_count系统变量较低的值来强制MySQL暂时提升已插入的特定次数后等待一个表到表发生的所有SELECT语句的优先级。这允许一定数量的WRITE锁定后读锁。
  • 如果有问题的INSERT结合SELECT的,可考虑改用MyISAM表,它支持并发的SELECT和INSERT语句。
  • 如果混合插入和删除操作在同一个非事务表,插入延迟可能会有帮助。详见13.2.5.2, “INSERT DELAYEDSyntax”
          注意:从MySQL5.6.6中,INSERT DELAYED不建议使用,并且将在未来的版本被删除 。使用INSERT(without DELAYED)代替。
  • 如果有问题的混合SELECT和DELETE语句,LIMIT选项删除可能会有帮助。
  • 使用SQL_BUFFER_RESULT使用SELECT语句可以帮助使表锁定较短的期限。
  • 分割表的内容到单独的表可能会有帮助,通过允许查询一个表中针对列运行,而更新仅限于列在不同的表。
  • 可以更改锁定代码MYSYS/ thr_lock.cto使用单一的队列。在这种情况下,写锁定和读锁定将具有相同的优先级,这可能有助于一些应用。

3.并发插入(Concurrent Inserts)

    MyISAM存储引擎支持的并发插入,以减少一个给定表的reader和writer之间的竞争:如果一个MyISAM表有数据文件中没有holes(孔)(删除的行的中间),INSERT语句可以被执行的行添加到表的末尾,同时SELECT语句从表中读取行。如果有多个INSERT语句,它们排队,按顺序进行的,同时使用SELECT语句。并发插入的结果可能不会立即可见。

    该concurrent_insert系统变量可以被设置为修改并发插入处理。默认情况下,变量设置为AUTO(自动)和并发性插入操作如刚才所描述的处理。如果concurrent_insert设置为NEVER(或0),并发性插入操作被禁止。如果该变量被设置为ALWAYS(或2),并发性插入操作在表的末尾允许甚至已删除的行的表。详见concurrent_insert系统变量说明

    并发插入即可使用在情况下,里面很少有任何需要使用INSERT语句延迟修正。

    如果使用的是二进制日志,并发性插入操作转换为普通CREATE... SELECT或INSERT... SELECT语句。这样做是为了确保可通过在备份操作过程中应用该日志重新创建表的精确副本。此外,对于那些语句的读锁被放置在选定从表使得插入到该表中被阻塞。其效果是并发插入该表必须等待。

    用LOAD DATA INFILE,如果指定一致与满足的并发插入(即,它包含在中间没有空闲块),其它会话可以检索同时LOAD DATA正在执行从表中数据该条件的MyISAM表。使用并行选项的影响LOAD DATA的性能了,即使没有其他会话同时使用该表。

    如果指定了HIGH_PRIORITY,它将覆盖--low-priority-updates选项的效果,如果服务器启动时使用该选项。它也可引起不使用并发插入。

    锁表,READ LOCAL和READ之间的区别是,READ LOCAL允许不冲突的INSERT语句(同时插入)来执行同时持有锁。但是,这不能如果你要操纵数据库在你持有锁时使用外部进程到服务。

    
4.元数据锁(Metadata Locking)

    MySQL使用元数据锁来管理访问对象(表,触发器等等)。元数据锁是用来保证数据的一致性但确实需要一些系统开销,从而增加作为查询的查询量。元数据争用增加了更多的多个查询尝试访问 相同的对象。

    元数据锁定是不能代替该表定义的情况下,它的互斥锁,并从LOCK_open互斥不同。

    为了保证事务的串行化,服务器必须不允许一个会话就被用在未完成的事务在另一个会话表执行数据定义语言(DDL)语句。该服务器通过收购在事务中使用的元数据表锁和延迟的这些锁的释放直到这个事务结束。一个表上的元数据锁可防止修改表的结构。这种锁定方法具有正被在一个会话中使用由事务表直至事务结束不能被其他会话使用DDL语句含义。

    这个原理不仅适用于事务表,也能非事务性表。假设一个会话开始使用事务性表t和非事务表NTAS如下交易:
        START TRANSACTION;
        SELECT * FROM t; 
        SELECT * FROM nt;

    元数据锁持有T和NT直至事务结束。如果另一个会话试图在两个表上DDL操作,它会阻止直到元数据锁释放的事务结束。例如,第二会话模块如果它尝试这些操作:
        DROP TABLE t;
        ALTER TABLE t ...;
        DROP TABLE nt;
        ALTER TABLE nt ...;

    如果服务器获取元数据锁的语句在语法上是有效的,但在执行过程中出现故障,它不会提前释放锁。锁定释放仍推迟到事务的结束因为失败的语句写入二进制日志和锁保护日志一致性。

    在自动提交模式下,每个语句实际上是一个完整的事务,因此获得该语句的元数据锁只保留到语句的结束。

    a准备语句中获得元数据锁被释放,一旦语句已经预备好,即使准备发生多语句事务中。

    MySQL5.5以前,当一个事务获取的元数据锁在一个语句中相当于使用的表,它在声明的最后释放锁。这种方法有缺点,如果一个DDL语句发生了当时正在在活动事务中的使用另一个会话,语句以错误的顺序写成二进制日志中。

5.外部锁(External Locking)

    外部锁定使用文件系统锁定以管理争用多进程的MyISAM数据表。外部锁定用于在单个进程情况下,如MySQL的服务器不能被认为是需要访问表中的唯一进程。下面是一些例子:
  • 如果您运行多台服务器使用同一个数据库目录(不推荐),每台服务器都必须启用外部锁定。
  • 如果使用myisamchk来对MyISAM表进行表维护操作,您必须确保服务器没有运行,或者服务器已经启用外部锁定,使其锁定表的文件,需要用myisamchk来协调访问的表。这同样适用于使用的myisampack的挑选MyISAM表。

    如果服务器运行与外部锁定启用,您可以使用myisamchk随时进行读操作这样的检查表。在这种情况下,如果服务器尝试使用myisamchk更新的是一个表,服务器将等待myisamchk完成。

    如果使用myisamchk进行写操作,如修复或优化表,或者使用myisampack包装表,必须始终确保mysqld服务器没有使用表。如果不停止mysqld的,至少运行myisamchk前做一个mysqladmin的flush-tables。你的表可能会损坏,如果服务器和myisamchk的同时访问的表。

    随着外部锁影响,每个进程需要访问的表继续访问表之前获得的文件系统锁表文件。如果所有必需的锁不能获得,该方法是从之前的锁可以得到(后当前拥有锁的过程中释放它们)访问该表受阻。

    外部锁定会影响服务器的性能,因为服务器有时必须等待其他进程才可以访问表。

    如果运行在一台服务器来访问一个给定的数据目录(这是通常的情况下),如果没有其它方案,如使用myisamchk需要修改表的服务器运行时的外部锁是不必要的。如果其他程序只读表,不需要外部锁定,虽然使用myisamchk会报告警告,如果服务器更改表,而myisamchk的是读取它们。

    随着外部锁定禁用,以使用myisamchk,则必须停止服务器,而使用myisamchk执行时要不锁和运行myisamchk的之前清空表。为了避免这种情况的要求,使用CHECK TABLE和REPAIR TABLE语句来检查和修复MyISAM表。

    对于mysqld,外部锁定由skip_external_locking系统变量的值来控制。当这个变量被启用,外部锁定被禁用,反之亦然。从MySQL4.0,外部锁定默认情况下禁用。

    使用外部锁可以在服务器启动时使用--external-locking--skip-external-locking选项来控制。

    如果使用外部锁定选项来启用从很多MySQL的进程中更新MyISAM表,你必须确保满足以下条件:
  • 不要使用查询缓存该使用由另一个进程更新表的查询。
  • 不要用 --delay-key-write=ALL选项启动服务器或对任何共享使用DELAY_KEY_WRITE=1表选项。否则,索引可能会损坏。

    满足这些条件的最简单方法是始终使用--external-locking连同--delay-key-write=OFF 并且--query-cache-size=0。(这不是默认设置,因为在许多设置也有上述选项的混合物是有用的。)



阅读(332) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~