首页 数据库 mysql教程 InnoDB一定会在索引中加上主键吗

InnoDB一定会在索引中加上主键吗

Jun 07, 2016 pm 04:35 PM
dba innodb 主键 索引 讨论

DBA 群里在讨论一个问题,到底InnoDB会不会在索引末尾加上主键,什么时候会加? 我之前看代码记得是如果索引末尾就是主键,那么InnoDB就不再添加主键了,如果索引末尾不是主键,那么会添加主键,但是这跟测试结果不符: CREATETABLE t ( a char(32)notnullpr

DBA群里在讨论一个问题,到底InnoDB会不会在索引末尾加上主键,什么时候会加?

我之前看代码记得是如果索引末尾就是主键,那么InnoDB就不再添加主键了,如果索引末尾不是主键,那么会添加主键,但是这跟测试结果不符:

CREATETABLE t (
  a char(32)notnullprimarykey,
  b char(32)notnull,KEY idx1 (a,b),KEY idx2 (b,a)) Engine=InnoDB;
登录后复制

插入部分数据后可以看到idx1和idx2两个索引的大小相同。这说明idx1和idx2的内部结构是一样的,因此 不可能 是idx1在内部存为(a,b,a)。

在登博的指导下看了 dict0dict.cc:dict_index_build_internal_non_clust() 这个函数,就是构造索引的数据字典的过程,理解了这个过程就明白了,我们接下来解读下这个函数(基于5.6最近trunk):

2727/*******************************************************************//**2728 Builds the internal dictionary cache representation for a non-clustered2729 index, containing also system fields not defined by the user.2730 @return own: the internal representation of the non-clustered index */2731static2732 dict_index_t*2733 dict_index_build_internal_non_clust(2734/*================================*/2735const dict_table_t* table,  /*!mutex)));2748   ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);27492750/* The clustered index should be the first in the list of indexes */2751   clust_index = UT_LIST_GET_FIRST(table->indexes);27522753   ut_ad(clust_index);2754   ut_ad(dict_index_is_clust(clust_index));2755   ut_ad(!dict_index_is_univ(clust_index));27562757/* Create a new index */2758   new_index = dict_mem_index_create(2759     table->name, index->name, index->space, index->type,
2760     index->n_fields +1+ clust_index->n_uniq);27612762/* Copy other relevant data from the old index2763   struct to the new struct: it inherits the values */27642765   new_index->n_user_defined_cols = index->n_fields;27662767   new_index->id = index->id;27682769/* Copy fields from index to new_index */2770   dict_index_copy(new_index, index, table, 0, index->n_fields);27712772/* Remember the table columns already contained in new_index */2773   indexed =static_cast<ibool>(2774     mem_zalloc(table->n_cols *sizeof*indexed));27752776/* Mark the table columns already contained in new_index */2777for(i =0; i n_def; i++){27782779     field = dict_index_get_nth_field(new_index, i);27802781/* If there is only a prefix of the column in the index2782     field, do not mark the column as contained in the index */27832784if(field->prefix_len ==0){27852786       indexed[field->col->ind]= TRUE;2787}2788}27892790/* Add to new_index the columns necessary to determine the clustered2791   index entry uniquely */27922793for(i =0; i n_uniq; i++){27942795     field = dict_index_get_nth_field(clust_index, i);27962797if(!indexed[field->col->ind]){2798       dict_index_add_col(new_index, table, field->col,
2799              field->prefix_len);2800}2801}28022803   mem_free(indexed);28042805if(dict_index_is_unique(index)){2806     new_index->n_uniq = index->n_fields;2807}else{2808     new_index->n_uniq = new_index->n_def;2809}28102811/* Set the n_fields value in new_index to the actual defined2812   number of fields */28132814   new_index->n_fields = new_index->n_def;28152816   new_index->cached = TRUE;28172818return(new_index);2819}</ibool>
登录后复制

这是整个函数,读者最好可以先自己读读这个函数理解一下,然后再看分析。

好了,下面我们开始分析了,首先把 dict_table_t 这个结构体的相关成员解释一下:

474unsigned  n_user_defined_cols:10;475/*!
登录后复制

注释很好理解,主要是 n_uniq 表示索引中需要多少个字段来唯一标识一行数据,只对唯一索引有效;n_def 是有多少个字段用了扩展存储空间,就是索引中只存前缀; n_fields 是索引最终一共有多少字段,包括系统加的;n_user_defined_cols 是用户定义的字段数,不包括系统自动加的。

然后我们来看两段最主要的代码:

2772/* Remember the table columns already contained in new_index */2773   indexed =static_cast<ibool>(2774     mem_zalloc(table->n_cols *sizeof*indexed));27752776/* Mark the table columns already contained in new_index */2777for(i =0; i n_def; i++){27782779     field = dict_index_get_nth_field(new_index, i);27802781/* If there is only a prefix of the column in the index2782     field, do not mark the column as contained in the index */27832784if(field->prefix_len ==0){27852786       indexed[field->col->ind]= TRUE;2787}2788}</ibool>
登录后复制

InnoDB首先创建了一个布尔型数组,然后依次循环索引上的每一个字段,如果这个字段不是只有前缀,那么就在数组中记下它的索引号,标记这个字段在索引中出现了。因此indexed数组就存下了索引中用户定义的所有字段序号。

2790/* Add to new_index the columns necessary to determine the clustered2791   index entry uniquely */27922793for(i =0; i n_uniq; i++){27942795     field = dict_index_get_nth_field(clust_index, i);27962797if(!indexed[field->col->ind]){2798       dict_index_add_col(new_index, table, field->col,
2799              field->prefix_len);2800}2801}
登录后复制

这一段就开始循环聚集索引(主键)的每个字段,盘下indexed数组中这个字段是不是有了,如果没有,那么再调用 dict_index_add_col 把字段加到索引中。

因此只要用户定义的索引字段中包含了主键中的字段,那么这个字段就不会再被InnoDB自动加到索引中了,如果用户的索引字段中没有完全包含主键字段,InnoDB就会把剩下的主键字段加到索引末尾。

因此我们最初的例子中, idx1 和 idx2 两个索引内部大小完全一样,没有区别。

最后再补充下组合主键的例子:

CREATETABLE t (
  a char(32)notnull,
  b char(32)notnull,
  c char(32)notnull,
  d char(32)notnull,PRIMARYKEY(a,b)KEY idx1 (c,a),KEY idx2 (d,b)) Engine=InnoDB;
登录后复制

这个表InnoDB会自动补全主键字典,idx1 实际上内部存储为 (c,a,b),idx2 实际上内部存储为 (d,b,a)。
但是这个自动添加的字段,Server层是不知道的,所以MySQL优化器并不知道这个字段的存在,所以如果你有一个查询:

SELECT * FROM t WHERE d=x1 AND b=x2 ORDER BY a;
登录后复制

其实内部存储的idx2(d,b,a)可以让这个查询完全走索引,但是由于Server层不知道,所以最终MySQL优化器可能选择 idx2(d,b) 做过滤然后排序 a 字段,或者直接用PK扫描避免排序。

而如果我们定义表结构的时候就定义为 KEY idx2(d,b,a) ,那么MySQL就知道(d,b,a)三个字段索引中都有,并且InnoDB发现用户定义的索引中包含了所有的主键字段,也不会再添加了,并没有增加存储空间。

因此,由衷的建议,所有的DBA建索引的时候,都在业务要求的索引字段后面补上主键字段,这没有任何损失,但是可能给你带来意外的惊喜。

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

oracle索引类型有哪些 oracle索引类型有哪些 Nov 16, 2023 am 09:59 AM

oracle索引类型有:1、B-Tree索引;2、位图索引;3、函数索引;4、哈希索引;5、反向键索引;6、局部索引;7、全局索引;8、域索引;9、位图连接索引;10、复合索引。详细介绍:1、B-Tree索引,是一种自平衡的、可以高效地支持并发操作的树形数据结构,在Oracle数据库中,B-Tree索引是最常用的一种索引类型;2、位图索引,是一种基于位图算法的索引类型等等。

红米RedmiK70Pro如何设置返回键和主键? 红米RedmiK70Pro如何设置返回键和主键? Feb 23, 2024 pm 01:40 PM

手机是现在中轻年人的必备之物,当然每个年龄段的人对手机需求是不一样的。RedmiK70Pro作为现在比较火爆的机型之一,内部拥有非常多样的功能以及服务,可以满足不同年龄段消费者们的需求。红米RedmiK70Pro怎么设置返回键和主键?也是需要了解清楚的,清楚之后才会决定要不要购买这款手机,那就跟随小编一起来看看下面的内容吧!红米RedmiK70Pro怎么设置返回键和主键?要访问手机的设置菜单,您可以通过下拉通知栏或在主屏幕上查找设置图标来打开设置界面。在设置界面中,查找并点击“按钮”或“导航栏”

如何让MySQL外键和主键自动关联起来? 如何让MySQL外键和主键自动关联起来? Mar 15, 2024 pm 12:54 PM

如何让MySQL外键和主键自动关联起来?在MySQL数据库中,外键和主键是非常重要的概念,它们能够帮助我们在不同表之间建立关联关系,保证数据的完整性和一致性。在实际的应用过程中,经常需要让外键自动关联到对应的主键上,以避免数据不一致的情况发生。下面将介绍如何通过具体的代码示例实现这一功能。首先,我们需要创建两个表,一个表作为主表,另一个表作为从表。在主表中创

索引超出了数组界限如何解决 索引超出了数组界限如何解决 Nov 15, 2023 pm 05:22 PM

解决方法有:1、检查索引值是否正确:首先确认你的索引值是否超出了数组的长度范围。数组的索引从0开始,所以最大索引值应该是数组长度减1;2、检查循环边界条件:如果是在循环中使用索引进行数组访问,要确保循环的边界条件正确;3、初始化数组:在使用数组之前,要确保数组已经被正确地初始化;4、使用异常处理:在程序中可以使用异常处理机制来捕获索引超出数组界限的错误,并进行相应的处理。

说明InnoDB全文搜索功能。 说明InnoDB全文搜索功能。 Apr 02, 2025 pm 06:09 PM

InnoDB的全文搜索功能非常强大,能够显着提高数据库查询效率和处理大量文本数据的能力。 1)InnoDB通过倒排索引实现全文搜索,支持基本和高级搜索查询。 2)使用MATCH和AGAINST关键字进行搜索,支持布尔模式和短语搜索。 3)优化方法包括使用分词技术、定期重建索引和调整缓存大小,以提升性能和准确性。

PHP返回一个字符串在另一个字符串中开始位置到结束位置的字符串 PHP返回一个字符串在另一个字符串中开始位置到结束位置的字符串 Mar 21, 2024 am 10:31 AM

这篇文章将为大家详细讲解有关PHP返回一个字符串在另一个字符串中开始位置到结束位置的字符串,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。PHP中使用substr()函数从字符串中提取子字符串substr()函数可从字符串中提取指定范围内的字符。其语法如下:substr(string,start,length)其中:string:要从中提取子字符串的原始字符串。start:子字符串开始位置的索引(从0开始)。length(可选):子字符串的长度。如果未指定,则提

如何通过索引提升PHP与MySQL的数据分组和数据聚合的效率? 如何通过索引提升PHP与MySQL的数据分组和数据聚合的效率? Oct 15, 2023 am 11:39 AM

如何通过索引提升PHP与MySQL的数据分组和数据聚合的效率?引言:PHP和MySQL是目前应用最广泛的编程语言和数据库管理系统,常常被用于构建web应用程序和处理大量数据。在处理大量数据时,数据分组和数据聚合是常见的操作,但如果不合理地设计和使用索引,这些操作可能会变得非常低效。本文将介绍如何通过索引来提升PHP与MySQL的数据分组和数据聚合的效率,并提

荣耀X50Pro怎么设置返回键和主键? 荣耀X50Pro怎么设置返回键和主键? Mar 18, 2024 am 11:34 AM

荣耀X50Pro是最近刚刚正式发布的一款旗舰手机,这款手机采用了全新的外观设计,颜值确实是非常不错的,除了颜值之外这款手机的性能配置也很出色,那么荣耀X50Pro怎么设置返回键和主键?下面就让我们来一起看看吧!荣耀X50Pro怎么设置返回键和主键?1、在主屏幕上找到“设置”图标,点击“系统和更新”功能选项;2、点击系统和更新功能项目中的“系统导航方式”;3、荣耀手机提供三种返回键设置,可以根据自己的设置进行调整:荣耀X50Pro这款手机设置返回键和主键的方法还是很简单的,大家可以按照上面的步骤来

See all articles