[转]mysql锁表,修改表结构
7.3 锁
7.3.1 锁机制
当前MySQL已经⽀持 ISAM, MyISAM, MEMORY (HEAP) 类型表的表级锁了,BDB 表⽀持页级锁,InnoDB 表⽀持⾏级锁。
很多时候,可以通过经验来猜测什么样的锁对应⽤程序更合适,不过通常很难说⼀个锁⽐别的更好,这全都要依据应⽤程序来决定,不同的地⽅可能需要不同的锁。
想要决定是否需要采⽤⼀个⽀持⾏级锁的存储引擎,就要看看应⽤程序都要做什么,其中的查询、更新语句是怎么⽤的。例如,很多的web 应⽤程序⼤量的做查询,很少删除,主要是基于索引的更新,只往特定的表中插⼊记录。采⽤基本的MySQL MyISAM 表就很合适了。
MySQL中对表级锁的存储引擎来说是释放死锁的。避免死锁可以这样做到:在任何查询之前先请求锁,并且按照请求的顺序锁表。
MySQL中⽤于 WRITE(写) 的表锁的实现机制如下:
如果表没有加锁,那么就加⼀个写锁。
否则的话,将请求放到写锁队列中。
MySQL中⽤于 READ(读) 的表锁的实现机制如下:
如果表没有加写锁,那么就加⼀个读锁。
否则的话,将请求放到读锁队列中。
当锁释放后,写锁队列中的线程可以⽤这个锁资源,然后才轮到读锁队列中的线程。
这就是说,如果表⾥有很多更新操作的话,那么 SELECT 必须等到所有的更新都完成了之后才能开始。
从 MySQL 3.23.33 开始,可以通过状态变量 Table_locks_waited 和 Table_locks_immediate 来分析系统中的锁表争夺情况:
mysql> SHOW STATUS LIKE 'Table%';
+-----------------------+---------+
| Variable_name | Value |
+-----------------------+---------+
| Table_locks_immediate | 1151552 |
| Table_locks_waited | 15324 |
+-----------------------+---------+
在 MySQL 3.23.7(在Windows上是3.23.25)以后,在 MyISAM 表中只要没有冲突的 INSERT 操作,就可以⽆需使⽤锁表⾃由地并⾏执⾏ INSERT 和 SELECT 语句。也就是说,可以在其它客户端正在读取 MyISAM 表记录的同时时插⼊新记录。如果数据⽂件的中间没有空余的磁盘块的话,就不会发⽣冲突了,因为这种情况下所有的新记录都会写在数据⽂件的末尾(当在表的中 间做删除或者更新操作时,就可能导致空洞)。当空洞被新数据填充后,并⾏插⼊特性就会⾃动重新被启⽤了。
如果想要在⼀个表上做⼤量的 INSERT 和 SELECT 操作,但是并⾏的插⼊却不可能时,可以将记录插⼊到临时表中,然后定期将临时表中的数据更新到实际的表⾥。可以⽤以下命令实现:
mysql> LOCK TABLES real_table WRITE, insert_table WRITE;
mysql> INSERT INTO real_table SELECT * FROM insert_table;
mysql> TRUNCATE TABLE insert_table;
mysql> UNLOCK TABLES;
InnoDB 使⽤⾏级锁,BDB 使⽤页级锁。对于 InnoDB 和 BDB 存储引擎来说,是可能产⽣死锁的。这是因为 InnoDB 会⾃动捕获⾏
锁,BDB 会在执⾏ SQL 语句时捕获页锁的,⽽不是在事务的开始就这么做。
⾏级锁的优点有:
在很多线程请求不同记录时减少冲突锁。
事务回滚时减少改变数据。
access转mysql教程视频
使长时间对单独的⼀⾏记录加锁成为可能。
⾏级锁的缺点有:
⽐页级锁和表级锁消耗更多的内存。
当在⼤量表中使⽤时,⽐页级锁和表级锁更慢,因为他需要请求更多的所资源。
当需要频繁对⼤部分数据做 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 操作,但是没有任何写表。
表级锁和⾏级锁或页级锁之间的不同之处还在于:
将同时有⼀个写和多个读的地⽅做版本(例如在MySQL中的并发插⼊)。也就是说,数据库/表⽀持根据开始访问数据时间点的不同⽀持各种不同的试图。其它名有:时间⾏程,写复制,或者是按需复制。
原⽂: Versioning (such as we use in MySQL for concurrent inserts) where you can have one writer at the same time as many readers. This means that the database/table supports different views for the data depending on when you started to access it. Other names for this are time travel, copy on write, or copy on demand.
按需复制在很多情况下⽐页级锁或⾏级锁好多了。尽管如此,最坏情况时还是⽐其它正常锁使⽤了更多的内存。
可以⽤应⽤程序级锁来代替⾏级锁,例如MySQL中的 GET_LOCK() 和 RELEASE_LOCK()。但它们是劝告锁(原⽂:These are advisory locks),因此只能⽤于安全可信的应⽤程序中。
7.3.2 锁表
为了能有快速的锁,MySQL除了 InnoDB 和 BDB 这两种存储引擎外,所有的都是⽤表级锁(⽽⾮页
、⾏、列级锁)。
对于 InnoDB 和 BDB 表,MySQL只有在指定⽤ LOCK TABLES 锁表时才使⽤表级锁。在这两种表中,建议最好不要使⽤ LOCK TABLES,因为 InnoDB ⾃动采⽤⾏级锁,BDB ⽤页级锁来保证事务的隔离。
如果数据表很⼤,那么在⼤多数应⽤中表级锁会⽐⾏级锁好多了,不过这有⼀些陷阱。
表级锁让很多线程可以同时从数据表中读取数据,但是如果另⼀个线程想要写数据的话,就必须要先取得排他访问。正在更新数据时,必须要等到更新完成了,其他线程才能访问这个表。
更新操作通常认为⽐读取更重要,因此它的优先级更⾼。不过最好要先确认,数据表是否有很⾼的 SELECT 操作,⽽更新操作并⾮很‘急需’。
表锁锁在⼀个线程在等待,因为磁盘空间满了,但是却需要有空余的磁盘空间,这个线程才能继续处理时就有问题了。这种情况下,所有要访问这个出问题的表的线程都会被置为等待状态,直到有剩余磁盘空间了。
表锁在以下设想情况中就不利了:
⼀个客户端提交了⼀个需要长时间运⾏的 SELECT 操作。
其他客户端对同⼀个表提交了 UPDATE 操作,这个客户端就要等到 SELECT 完成了才能开始执⾏。
其他客户端也对同⼀个表提交了 SELECT 请求。由于 UPDATE 的优先级⾼于 SELECT,所以 SELECT 就会先等到 UPDATE 完成了之后才开始执⾏,它也在等待第⼀个 SELECT 操作。
下列所述可以减少表锁带来的资源争夺:
让 SELECT 速度尽量快,这可能需要创建⼀些摘要表。
启动 mysqld 时使⽤参数 --low-priority-updates。这就会让更新操作的优先级低于 SELECT。这种情况下,在上⾯的假设中,第⼆个SELECT 就会在 INSERT 之前执⾏了,⽽且也⽆需等待第⼀个SELECT 了。
可以执⾏ SET LOW_PRIORITY_UPDATES=1 命令,指定所有的更新操作都放到⼀个指定的链接中去完成。详情请看“14.5.3.1 SET Syntax”。
⽤ LOW_PRIORITY 属性来降低 INSERT,UPDATE,DELETE 的优先级。
⽤ HIGH_PRIORITY 来提⾼ SELECT 语句的优先级。详情请看“14.1.7 SELECT Syntax”。
从MySQL 3.23.7 开始,可以在启动 mysqld 时指定系统变量 max_write_lock_count 为⼀个⽐较低的值,它能强制临时地提⾼表的插⼊数达到⼀个特定值后的所有 SELECT 操作的优先级。它允许在 WRITE 锁达到⼀定数量后有 READ 锁。
当 INSERT 和 SELECT ⼀起使⽤出现问题时,可以转⽽采⽤ MyISAM 表,它⽀持并发的SELECT 和 INSERT 操作。
当在同⼀个表上同时有插⼊和删除操作时,INSERT DELAYED 可能会很有⽤。详情请看“14.1.4.2 INSERT DELAYED Syntax”。
当 SELECT 和 DELETE ⼀起使⽤出现问题时,DELETE 的 LIMIT 参数可能会很有⽤。详情请看“14.1.1 DELETE Syntax”
执⾏ SELECT 时使⽤ SQL_BUFFER_RESULT 有助于减短锁表的持续时间.详情请看“14.1.7 SELECT Syntax”。
可以修改源代码 `mysys/thr_lock.c',只⽤⼀个所队列。这种情况下,写锁和读锁的优先级就⼀样了,这对⼀些应⽤可能有帮助。
以下是MySQL锁的⼀些建议:
只要对同⼀个表没有⼤量的更新和查询操作混在⼀起,⽬前的⽤户并不是问题。
执⾏ LOCK TABLES 来提⾼速度(很多更新操作放在⼀个锁之中⽐没有锁的很多更新快多了)。将数据拆分开到多个表中可能也有帮助。
当MySQL碰到由于锁表引起的速度问题时,将表类型转换成 InnoDB 或 BDB 可能有助于提⾼性能。详情请看“16 The InnoDB Storage Engine”和“15.4 The BDB (BerkeleyDB) Storage Engine”。
修改表结构:
ALTER TABLE history add norenewdays int default 0;
alter TABLE history modify norenewdays int default 0;
alter table infos add ex tinyint not null default '0';

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。