设计MySQL数据库表的时候,一定会考虑主键的设计。mysql官方推荐不要使用uuid或者不连续不重复的雪花id,推荐连续自增的主键id,官方的推荐是auto_increment。为什么不建议采用uuid,使用uuid究竟有什么坏处?
如果设计表不设置主键,MySQL官方有以下说明:
If you do not define a PRIMARY KEY for your table, MySQL picks the first UNIQUE index that has only NOT NULL columns as the primary key and InnoDB uses it as the clustered index. If there is no such index in the table, InnoDB internally generates a clustered index where the rows are ordered by the row ID that InnoDB assigns to the rows in such a table. The row ID is a 6-byte field that increases monotonically as new rows are inserted. Thus, the rows ordered by the row ID are physically in insertion order.
翻译:如果没有主动设置主键,就会选一个第一个不包含NULL的唯一索引列作为主键列,并把它用作一个聚集索引。如果没有这样的索引就会使用行号生成一个聚集索引,把它当做主键,这个行号6bytes,自增。可以用select _rowid from table来查询。
mysql 数据库表存放关系型结构化数据,一定会提供对数据的CRUD操作。在查询操作时,如果没有索引,MySQL必须从第一行开始,然后读取整个表以查找相关行。表越大,成本越高。通过建立索引,MySQL可以根据索引文件快速确定要在数据文件中间寻找的位置,而无需查看所有数据。
MySQL的索引主要分为主键索引(PRIMARY KEY),唯一索引(UNIQUE) ,普通索引(INDEX)和全文索引(FULLTEXT) 。主键索引是一种特殊的唯一索引,不允许有空值。
MySQL中索引是如何发挥功效的呢?先看一下MySQL的执行过程:
所有与数据的交互是会通过引擎服务的,MySQL中常见的引擎包括MyIsam和InnoDb。二者的差别这里不做叙述,可参见:CSDNhttps://mp.csdn.net/mp_blog/creation/editor/96205289
InnoDB的存储文件有两个,后缀名分别是 .frm和 .idb;其中 .frm是表的定义文件, .idb是表的数据文件。InnoDB引擎采用B+Tree结构来作为索引结构,InnoDB
主键的叶子节点是该行的数据,而其他索引则指向主键。
页是 InnoDB 管理的最小单位,常见的有 FSP_HDR
,INODE
, INDEX
等类型。页结构分为文件头(前38字节),页数据和文件尾(后8字节)。每个数据页大小为16kb,结构如下:
系统从磁盘中读取数据到内存时是以磁盘块(block)为基本单位,位于同一个磁盘块中的数据会被一次性读取出来。block大小空间往往没有16kb大,因此innodb每次io操作时都会将若干个地址连续的磁盘块的数据读入内存,从而实现整页读入内存。
MySQL写入数据时,会把数据存放到索引页中。使用UUID作为主键,新行的主键值不一定比之前的主键值大,所以innoDb无法做到总是把新行插入到索引的最后,而需要为新行寻找合适的位置来分配新的空间,这个过程会导致:
使用自增主键则可以避免上述问题:
结论:使用innodb应该尽可能的按主键的自增顺序插入,并且尽可能使用单调的增加的聚簇键的值来插入新行
Auto_increment的锁争抢问题,可以通过调优innodb_autoinc_lock_mode的配置,总共有三个有效值可供设定,即0、1、2,具体说明如下:
0:是MySQL 5.1.22版本之前自增长的实现方式,即通过表锁的AUTO-INC Locking方式,所有的insert语句在开始时都会获得一个表锁AUTO-INC Locking。该锁会一直持有到insert语句执行结束才会被释放。对于一条insert插入多个行记录的语句,保证了同一条语句插入的行记录的自增ID是连续的。
1:这是该参数的默认值,对于”simple inserts”,该值会用互斥量(mutex)去对内存中的计数器进行累加的操作。insert语句在开始时会获得一个表锁AUTO-INC Locking,但对于bulk insert,自增锁会被一直持有直到语句执行结束才会被释放。这种模式仍然保证了同一条语句插入的行记录的自增ID是连续的。
2:对于所有的插入操作”INSERT-LIKE”自增长值的产生都是通过互斥量,而不是AUTO-INC Locking的方式,不管什么情况都使用轻量级互斥的锁。因为并发插入的存在,在每次插入时,自增长的值可能不是连续的。最重要的是,基于Statement的主从复制会出现问题,任何时候都应该使用Row方式,这样才能保证最大的并发性能及主从数据的一致。