另外,如果删除索引i_index,则结果如下:
例1-6
Session 1
|
Session 2
|
mysql> drop index i_index on t;
Query OK, 3 rows affected (0.25 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from t;
+------+
| i |
+------+
| 4 |
| 10 |
| 9 |
+------+
3 rows in set (0.00 sec)
|
|
|
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select i from t lock in share mode;
+------+
| i |
+------+
| 4 |
| 10 |
| 9 |
+------+
3 rows in set (0.00 sec)
|
mysql> insert into t(i) values(8);
等待。。。
|
|
另外,针对插入(INSERT)操作,只要多个事务不会在同一索引区间的同一个位置插入记录,它们就不用互相等待,这种情况可以称为插入意向间隙锁(insertion intention gap lock)。例如,索引记录的值为4和7,两个独立的事务分别插入5和6,仅管它们都持有4—7之间的间隙锁,但是它们不会相互阻塞。这可以提高事务的并发性。
例1-7
Session 1
|
Session 2
|
mysql> select * from t;
+------+
| i |
+------+
| 4 |
| 10 |
| 9 |
| 8 |
+------+
4 rows in set (0.00 sec)
mysql> create unique index i_index on t(i);
Query OK, 4 rows affected (0.34 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
|
|
|
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
|
mysql> insert into t(i) values(5);
Query OK, 1 row affected (0.00 sec)
|
|
|
mysql> insert into t(i) values(5);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> insert into t(i) values(6);
Query OK, 1 row affected (0.00 sec)
|
间隙锁是可以显示关闭的,如果你将事务的隔离级别设为READ COMMITTED,或者打开innodb_locks_unsafe_for_binlog系统变量,间隙锁就会关闭。在这种情况下,查找或扫描索引仅会进行外键约束检查和重复键值检查。 此外,READ COMMITTED隔离级别和关闭nodb_locks_unsafe_for_binlog还有另外一个负作用:MySQL会释放掉不匹配Where条件的记录锁。例如,对于UPDATE语句,InnoDB只能进行“半一致性(semi_consistent)读”,所以,它会返回最新提交事务所做改变,从而产生不可重复读和幻像问题。
1.3.8、使用next-key lock防止幻像问题 例1-4展示了一个幻像问题。使用next-key锁的select语句可以解决幻像问题,但例1-4的之所以会产生总是在于唯一索引,使得select语句没有使用gap lock,而只使用了index-record lock。
1.4、存储引擎 插件式存储引擎是MySQL最重要特性之一,也是最不同于其它DBMS的地方。MySQL支持很多存储引擎,以适用于不同的应用需求,常用的包括MyISAM、InnoDB、BDB、MEMORY、MERGE、NDB Cluster等。其中,BDB和NDB Cluster提供事务支持。 MySQL默认的存储引擎为MyISAM,当然,创建表的时候可以指定其它的存储引擎,你可以在同一个数据库中对不同的表使用不同的存储引擎(这是非常强大而独特的特性)。可以通过SHOW TABLE STATUS命令查询表所使用的存储引擎,例如,查看mysql数据库的user表:
mysql> SHOW TABLE STATUS LIKE 'user' \G
*************************** 1. row ***************************
Name: user
Engine: MyISAM
Version: 10
Row_format: Dynamic
Rows: 4
Avg_row_length: 61
Data_length: 244
Max_data_length: 281474976710655
Index_length: 2048
Data_free: 0
Auto_increment: NULL
Create_time: 2009-06-16 21:50:34
Update_time: 2009-09-30 14:59:08
Check_time: NULL
Collation: utf8_bin
Checksum: NULL
Create_options:
Comment: Users and global privileges
1 row in set (0.00 sec)
|
Name:表的名称; Engine:表使用的存储引擎; Row_format:记录的格式。MyISAM支持三种不同的存储格式:静态(固定长度)表(默认格式)、动态表及压缩表。静态表的字段都是固定长度的,例如CHAR和INTEGER;动态表的字段可以是变长的,例如,VARCHAR或者BLOB。 Rows:表中记录的数量。 Avg_row_length:记录的平均长度(字节数); Data_length:表中数据的全部字节数; Max_data_length:表中数据最大的字节数; Index_length:索引消耗的磁盘空间; Data_free:对于MyISAM表,表示已经分配但还没有使用的空间;该空间包含以前删除的记录留下的空间,可以被INSERT操作重用。 Auto_increment:下一个自增的值。 Check_time:上次使用CHECK TABLE或myisamchk检查表的时间。
1.4.1、MyISAM 1.4.1.1、存储 MySQL的默认存储引擎,性能与功能的折中,包括全文索引(full-text index)、数据压缩,支持空间(GIS)数据,但是,不支持事务和行级锁。一般来说,MyISAM更适用于大量查询操作。如果你有大量的插入、删除操作,你应该选择InnoDB。 每个表包含3个文件: (1).frm:表定义文件,对于其它存储引擎也一样。 (2).MYD文件:数据文件。 (3).MYI文件:索引文件。 可以在创建表时通过DATA DIRECTORY和INDEX DIRECTORY为数据文件和索引文件指定路径,它们可以位于不同目录。另外,MyISAM的存储格式是跨平台的,你可以将数据文件和索引文件从Intel平台拷贝到PPC或者SPARC平台。 5.0中,MyISAM的变长记录表默认处理256TB数据,使用6字节的指针来指向数据记录;而之前的版本使用默认的4字节指针,所以只能处理4GB数据。所有的版本都可以将指针增加到8字节指针,如果你想改变MyISAM表的指针的大小,可以通过设置MAX_ROWS和AVG_ROW_LENGTH来实现: CREATE TABLE mytable ( a INTEGER NOT NULL PRIMARY KEY, b CHAR(18) NOT NULL ) MAX_ROWS = 1000000000 AVG_ROW_LENGTH = 32; 上面的例子中,MySQL将至少可以存储32GB的数据。可以查看一下表的信息:
mysql> SHOW TABLE STATUS LIKE 'mytable' \G
*************************** 1. row ***************************
Name: mytable
Engine: MyISAM
Row_format: Fixed
Rows: 0
Avg_row_length: 0
Data_length: 0
Max_data_length: 98784247807
Index_length: 1024
Data_free: 0
Auto_increment: NULL
Create_time: 2002-02-24 17:36:57
Update_time: 2002-02-24 17:36:57
Check_time: NULL
Create_options: max_rows=1000000000 avg_row_length=32
Comment:
1 row in set (0.05 sec)
|
可以看到,Create_options列出了创建时的选项,而且该表的最大的数据量为91GB。你可以用ALTER TABLE来改变指针的大小,但是那会导致表和索引的重建,这会花费很长的时间。
1.4.1.2、MyISAM的特性 (1)锁与并发性:MyISAM只有表级锁,不支持行级锁。所以不适合于大量的写操作,但是它支持并发插入(concurrent inserts),这是一个非常重要且有用的特性。 (2)自动修复:MySQL支持自动检查和修复MyISAM表。 (3)手动修复:你可以使用CHECK TABLE检查表的状态,并用REPAIR TABLE修复表。 (4)索引:你可以为BLOB和TEXT的前500个字符创建索引。而且,MyISAM还支持全文索引,但仅限于CHAR、VARCHAR、和TEXT列。 (5)延迟键写(Delayed key writes):如果创建MyISAM表时指定DELAY_KEY_WRITE,MySQL在查询结束时,不会将改变的索引数据写入磁盘,而将修改保存在key buffer中。只有要改变缓存或者关闭表时,才会把索引数据刷入磁盘。
1.4.2、InnoDB InnoDB是一个高性能的事务存储引擎,此外,BDB也支持事务处理(关于BDB,以前曾较为详细的阅读过其源码,以后有时间再讨论),它有以下一些特点: 1.4.2.1、表空间 InnoDB存储表和索引有两种方式: (1)共享表空间存储:这种方式下,表的定义位于.frm文件中,数据和索引保存在innodb_data_home_dir和innodb_data_file_path指定的表空间中。 (2)多表空间存储:表的定义仍位于.frm文件,但是,每个InnoDB表和它的索引在它自己的文件(.idb)中,每个表有它自己的表空间。 对那些想把特定表格移到分离物理磁盘的用户,或者那些希望快速恢复单个表的备份而无须打断其余InnoDB表的使用的用户,使用多表空间会是有益的。你可以往my.cnf的[mysqld]节添加下面行来允许多表空间: [mysqld] innodb_file_per_table 重启服务器之后,InnoDB存储每个新创建的表到表格所属于的数据库目录下它自己的文件tbl_name.ibd里。这类似于MyISAM存储引擎所做的,但MyISAM 把表分成数据文件tbl_name.MYD和索引文件tbl_name.MYI。对于InnoDB,数据和所以被一起存到.ibd文件。tbl_name.frm文件照旧依然被创建。 如果你从my.cnf文件删除innodb_file_per_table行,并重启服务器,InnoDB在共享的表空间文件里再次创建表。 innodb_file_per_table只影响表的创建。如果你用这个选项启动服务器,新表被用.ibd文件来创建,但是你仍旧能访问在共享表空间里的表。如果你删掉这个选项,新表在共享表空间内创建,但你仍旧可以访问任何用多表空间创建的表。 InnoDB总是需要共享表空间,.ibd文件对InnoDB不足以去运行,共享表空间包含熟悉的ibdata文件,InnoDB把内部数据词典和undo日志放在这个文件中。
1.4.2.2、外键约束 MySQL中,支持外键的存储引擎只有InnoDB,在创建外键时,要求被参照表必须有对应的索引,参照表在创建外键时也会自动创建对应的索引。
1.4.2.3、MVCC与后码锁(next-key locking) InnoDB将MVCC机制与next-key lock结合起来,实现事务的各个隔离级别,这是非常用意思的。在nodb_locks_unsafe_for_binlog变量被设置或者事务的隔离级别不是SERIALIZABLE的情况下,InnoDB对于没有指定FOR UPDATE 或 LOCK IN SHARE MODE的INSERT INTO ... SELECT, UPDATE ... (SELECT), 和CREATE TABLE ... SELECT语句使用一致性读(参照前面),在这种情况下,查询语句不会对表中的元组加锁。否则,InnoDB将使用锁。
主要参考:
《MySQL Manual》
《High Performance MySQL》
(责任编辑:admin) |