最近在梳理数据生命周期管理的细节时,发现了一个小问题,那就是MySQL的主键命名策略,似乎会忽略任何形式的自定义命名。也就意味着你给主键命名为idx_pk_id这种形式,在MySQL里面会统一按照PRIMARY来处理。 首先来复现下问题,我们连接到数据库test,然后创建表test_data2.
mysql> create table test_data2 (id int ,name varchar(30));Query OK, 0 rows affected (0.05 sec)接着创建一个主键,命名为idx_pk_id,从执行情况来看,MySQL是正常处理了。
mysql> alter table test_data2 add primary key idx_pk_id(id);Query OK, 0 rows affected (0.02 sec)Records: 0 Duplicates: 0 Warnings: 0为了进一步对比,我们添加一个唯一性索引(辅助索引),来看看它们的差异。
mysql> alter table test_data2 add unique key idx_uniq_name(name);Query OK, 0 rows affected (0.00 sec)Records: 0 Duplicates: 0 Warnings: 0查看主键命名方法1:使用show indexes命令要查看MySQL索引的信息,使用show indexes from test_data2就可以。mysql> show indexes from test_data2\G*************************** 1. row ****************************************************** 2. row ***************************查看主键命名方法2:使用数据字典information_schema.statistics使用命令的方式不够通用,我们可以使用数据字典information_schema.statistics来进行数据提取。
mysql> select *from information_schema.statistics where table_schema='test' and table_name='test_data2' limit 20 \G *************************** 1. row ****************************************************** 2. row *************************** INDEX_NAME: idx_uniq_name查看主键命名方法3:使用show create table 命令mysql> show create table test_data2\G*************************** 1. row ***************************Create Table: CREATE TABLE `test_data2` ( `name` varchar(30) DEFAULT NULL, UNIQUE KEY `idx_uniq_name` (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8有的同学可能想,是不是分别执行了create,alter语句导致处理方式有差异,我们可以一步到位,在create语句里面声明主键名。CREATE TABLE `test_data3` ( `name` varchar(30) DEFAULT NULL, PRIMARY KEY idx_pk_id(`id`), UNIQUE KEY `idx_uniq_name` (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;这个时候查看建表语句,会发现结果和上面一样,主键名都是PRIMARY.
mysql> show create table test_data3\G *************************** 1. row ***************************Create Table: CREATE TABLE `test_data3` ( `name` varchar(30) DEFAULT NULL, UNIQUE KEY `idx_uniq_name` (`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf8当然还有多种验证方式,比如我们使用约束的方式来命名,得到的主键名都是PRIMARY.CREATE TABLE IF NOT EXISTS `default_test` ( `default_test`.`id` SMALLINT NOT NULL AUTO_INCREMENT, `default_test`.`name` LONGTEXT NOT NULL,CONSTRAINT `pk_id` PRIMARY KEY (`id`)当然还有其他多种形式可以验证,比如我们使用DML语句。mysql> insert into test_data2 values(1,'aa');Query OK, 1 row affected (0.02 sec)mysql> insert into test_data2 values(1,'aa');ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY'以上的方法都可以让我们对这个细节有更深入的理解,当然我们可以再深入一些。 关于主键的描述,大体内容如下,有一条是专门做了声明,主键名为PRIMARY.
- PRIMARY KEY的名称始终为PRIMARY,因此不能用作任何其他类型的索引的名称。
- 如果您没有PRIMARY KEY,而应用程序要求您在表中提供PRIMARY KEY,则MySQL将返回没有NULL列的第一个UNIQUE索引作为PRIMARY KEY。
- 在InnoDB表中,将PRIMARY KEY保持较短,以最小化辅助索引的存储开销。每个辅助索引条目都包含对应行的主键列的副本。
- 在创建的表中,首先放置一个PRIMARY KEY,然后放置所有UNIQUE索引,然后放置非唯一索引,这有助于MySQL优化器确定使用哪个索引的优先级,还可以更快地检测重复的UNIQUE键。
在sql_table.cc 里面对主键名称做了定义声明。const char *primary_key_name="PRIMARY";顺着这条路,可以看到在不同层的实现中的一些逻辑情况。通过这样的一些方式,我们对主键的命名情况有了一个整体的认识,为什么会采用PRIMARY这样一个命名呢,我总结了几点:2)和唯一性索引能够区别开来,比如一个唯一性索引非空,从属性上来看很相似的,通过主键命名就可以区分出来,在一些特性和索引使用场景中也容易区分。3)主键是一个表索引的第一个位置,统一命名可以在逻辑判断中更加清晰,包括字段升级为主键的场景等等。
4)在优化器处理中也会更加方便,提高MySQL优化器确定使用哪个索引的优先级。
转文至此。
以下为个人公众号“一森咖记”,欢迎关注。
近期热文
你可能也会对以下话题感兴趣。点击链接便可查看。
最后修改时间:2020-01-30 15:21:22
文章转载自
一森咖记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。