INNODB引擎下auto_increment的应用

标签:
innodbauto_incrementit |
分类: Web架构及DB |
在Innodb engine的primary key是 clustered index,这种索引是不同于其他索引,它的查询效率非常高,它指向的就是对应的row data, 其他索引即secondary index里面也存有primary key(clustered index)的列数据,在查询时,是先利用sencondary index找到primary key,然后在利用primary key找到row data,这个也解释了为什么在innodb engine里primary key效率非常高的原因,同时也说明了为什么innodb engine表的数据文件比myisam engine表大的原因之一。
在innodb engine中很多人都喜欢使用auot_increment做primary key。我个人持否定态度,甚至有点讨厌使用自增。因为当一个innodb engine的表里有一个auto_increment字段的时候,innodb engine会在内存里保存一个计数器用来记录auto_increment的值,当插入一个新行数据时,就会用一个table lock来锁住这个计数器,直到插入操作完成。如果是一行一行的插入数据基本上没有什么问题,但是如果大量的并发插入就会因为产生的表锁导致SQL语句堵塞,不仅使效率很低,而且可能会瞬间达到max_connections而导致数据crash。
这里总结一下我个人讨厌使用自增作为主键的主要原因:
1.自增在很多情况下没有意义,业务的查询语句不用使用这个自增来查询,浪费了作为clustered index这个索引的好处。
2.自增作为主键容易产生auto_inc lock,虽然innodb engine是采用的基于mvcc的row lock,但在高并发时这个auto_inc lock反而会影响并发,auto_inc lock是table lock,这个table lock是在一个SQL语句结束才释放,而不是在一个事务结束了释放。有些资料显示在线程个数大约10时这个锁将成为这个表的瓶颈。在mysql5.1.22之后的版本可以通过innodb_autoinc_lock_mode这个参数来调节锁策略。
但不可否认在某些情况使用自增效果很好,毕竟合适的才是最好的。
下面两种情况可以考虑使用自增作为主键:
1.
2.
需要说明的是:对于第一种情况,也可以不定义主键,innodb engine会自动使用隐式的row id来作为主键,这个row id类似一个自增。对于第二种情况,必须定义主键,因为不定义的话,innodb engine会按照次序把第一个unique key作为主键,即为clustered index, 这样就又会出现上面说的问题。反之,不建议使用主键。
使用自增的最大好处就是能减少表文件的大小,如果使用了一个很大的字符串做primary key,再加上有很多的secondary key,你会发现次表数据文件大小和myisam engine相比有指数级的增加。
两种情况做了一个测试。
表结构如下:
CREATE TABLE m_a (
message_id INT AUTO_INCREMENT NOT NULL PRIMARY KEY,
uid INT NOT NULL,
subject VARCHAR(256),
content VARCHAR(5000),
ctime TIMESTAMP NOT NULL,
KEY(uid)
) ENGINE=innodb
利用自增作为primary key,建立一个secondary key: uid进行测试。
CREATE TABLE m_c (
uid INT NOT NULL,
message_id INT NOT NULL,
subject VARCHAR(256),
content VARCHAR(5000),
ctime TIMESTAMP NOT NULL,
PRIMARY KEY(uid, message_id)
) ENGINE=innodb
把uid和message_id作为primary key.进行测试。
使用如下语句进行查询:
SELECT message_id,subj,content,ctime FROM m_a(or m_c) WHERE uid=? LIMIT 100
测试的结果如下:
http://s4/middle/502c8cc4t8e10c1871703&690
http://s2/middle/502c8cc4t8e10c237e211&690