Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MySQL InnoDB创建索引

MySQL InnoDB创建索引

原创
作者头像
devsql
发布于 2018-10-24 11:50:40
发布于 2018-10-24 11:50:40
5.9K10
代码可运行
举报
文章被收录于专栏:MySQL内核MySQL内核
运行总次数:0
代码可运行

1.基本概念

1.1 聚簇索引

InnoDB的索引基于B+树实现,每张InnoDB的表都有一个特殊的索引,叫做聚簇索引(Clustered Index),聚簇索引存储了表中的真实数据。索引项的顺序和真实的表数据顺序是一致的,B+树的叶子节点存储了真实的数据。这也就是所谓的“数据即索引”。聚簇索引的创建方式一般有三种:

  1. 用户定义了主键,那么InnoDB依据主键创建聚簇索引
  2. 用户没有定义主键,那么InnoDB根据表上的第一个唯一非空的列创建聚簇索引
  3. 如果以上两条都不符合,那么InnoDB会自动指定一个系统列作为聚簇索引(后面提到)
1.2 二级索引

InnoDB中,所有的非聚簇索引都叫二级索引(Secondary Indexes),与聚簇索引不同,二级索引的叶子节点不再是数据,而是存储类似<索引值,主键>的结构,通过主键查询聚簇索引。二级索引的创建可以由用户在SQL中自定义。

1.3 InnoDB系统列

InnoDB在创建表的时候,除了用户自定义的列之外,还会额外地增加几个隐藏的列,这些列在MySQL Server看来是不可见的,我们称之为系统列。比如,用户建表语句为 CREATE TABLE t (a int, b int) ENGINE=InnoDB; 在InnoDB中,实际创建的列为| DB_ROW_ID | DB_TRX_ID | DB_ROLL_PTR | a | b |,对这些字段的解释如下:

字段名

长度

描述

DB_ROW_ID

6B

一个单调递增的行ID

DB_TRX_ID

6B

表示记录最后被插入或更新时对应的事务ID

DB_ROLL_PTR

7B

指向回滚段中的UNDO log

在聚簇索引的创建过程中,若用户既没有定义主键,也没有符合要求的唯一非空列,则InnoDB使用DB_ROW_ID作为主键创建聚簇索引。

1.4 索引相关基本数据结构
  1. dict_index_t 这个是描述索引的数据结构,其大多成员会在dict_mem_index_create()被初始化成0, NULL, false. dict_mem_index_create()用于创建一个索引的内部对象。
  2. dict_table_t 这个是描述表结构的数据结构,其大多成员会在dict_mem_table_create()被初始化成0, NULL, false. dict_mem_table_create()用于创建一个表的内部对象。其中一个和索引直接相关的成员是indexes,这是一个链表,代表了该表上的所有索引。

2.代码分析

2.1 建表时创建索引

假设我们在建表时不创建主键,但是创建一个二级索引,SQL语句形如: CREATE TABLE t (a int, b int, index idx(b)) ENGINE=InnoDB; step1: 无论如何,聚簇索引都是会在第一步产生的,这里我们没有定义主键,也,没有定义唯一非空列,所以只能让InnoDB自动创建聚簇索引。其大致的函数调用关系如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
|-ha_create_table ()
  |-handler::ha_create ()
	  |-ha_innobase::create ()
	    |-innobase_basic_ddl::create_impl<dd::Table> ()
	      |-create_table_info_t::create_table ()
	        |-create_clustered_index_when_no_primary ()
	          |-...
	            |-dict_index_add_to_cache ()
				        |-dict_index_add_to_cache_w_vcol () //把新建的索引加入索引链表
				          |-dict_index_build_internal_clust () //创建聚簇索引缓存
					          |-dict_index_add_col ()  //将需要索引的列添加到索引中

整个创建默认聚簇索引的过程在InnoDB层完成,主要涉及的开始创建的函数create_table在文件ha_innodb.cc,判断表定义是否有主键的信息来自于结构体TABLE_SHARE->primary_key以及TABLE_SHARE->keys,如果用户没有定义主键,则调用函数create_clustered_index_when_no_primary()进行默认主键的创建任务,期间的调用关系如上文所示,还需要注意的就是这个dict_index_build_internal_clust(),该函数为聚簇索引创建了一个内部数据字典缓存。

step2: 还是基于上述的建表语句,当聚簇索引创建成功后,紧接着需要创建二级索引,也即上表中'idx'. 创建二级索引的函数调用和创建聚簇索引基本一致,大致关系如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
|-ha_create_table ()
  |-handler::ha_create ()
	  |-ha_innobase::create ()
	    |-innobase_basic_ddl::create_impl<dd::Table> ()
	      |-create_table_info_t::create_table ()
	        |-create_index ()
	          |-...
	            |-dict_index_add_to_cache ()
				        |-dict_index_add_to_cache_w_vcol () //把新建的索引加入索引链表
				          |-dict_index_build_internal_non_clust () //创建二级索引缓存
				    	      |-dict_index_add_col ()  //将需要索引的列添加到索引中

二级索引的判断依据是TABLE_SHARE->keys,keys代表了表中定义的索引键值的数量,在创建二级索引的过程中,会通过一个for循环扫描所有键,并为之创建二级索引,当然,主键已经创建了聚簇索引,所以会被排除在外。create_index()函数是创建二级索引的入口,最后通过dict_index_build_internal_non_clust()创建二级索引的内部缓存,从整个流程上来看,两者的区别不大。

2.2 重启后创建索引

MySQL重启后,内部索引对象丢失,需要在启动后重新创建相关的索引。MySQL重启后首先会将数据字典内的信息进行读取和初始化,然后根据数据字典的信息进行索引的创建。还是以上文的表t为例,假设现在MySQL重启,如何在t上构建索引? step1: 创建聚簇索引 无论如何,聚簇索引都会第一个创建。当我们首次对t进行查询或者更新时,由于默认聚簇索引不会被持久化到数据字典,所以对于表t来说,重启之后系统需要重新为之创建一个默认的聚簇索引。其大致的函数调用关系如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
|-open_tables_for_query ()
  |-open_tables ()
    |-open_and_process_table ()
	    |-open_table ()
	      |-open_table_from_share ()
		      |-handler::ha_open ()
		        |-ha_innobase::open ()
			        |-dd_open_table<dd::Table> ()
			          |-dd_open_table_one<dd::Table> ()
				          |-dd_fill_dict_index ()
				            |-dict_index_add_to_cache ()
                      |-...	// 和建表时创建索引的流程一致				

可以看出,首先我们会打开一个表对象,并获取其中的信息。当然,首先会打开系统表以查看持久化的信息。关键的函数是dd_fill_dict_index(),该函数用于实例化索引相关的元数据。对于没有定义聚簇索引的情况,在该函数中作出判断,并创建新的聚簇索引,加入缓存。 step2: 创建二级索引 创建二级索引的过程和创建聚簇索引的过程稍有不同,原因在于用户自定义的二级索引是需要持久化的,所以需要先读数据字典,然后建立索引。在dd_fill_dict_index()中一个一个建立二级索引,基于函数dd_fill_one_dict_index(),将索引添加到表中。其大致的函数调用关系如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
|-open_tables_for_query ()
  |-open_tables ()
    |-open_and_process_table ()
	    |-open_table ()
	      |-open_table_from_share ()
		      |-handler::ha_open ()
		        |-ha_innobase::open ()
			        |-dd_open_table<dd::Table> ()
			          |-dd_open_table_one<dd::Table> ()
				          |-dd_fill_dict_index ()
				            |-dd_fill_one_dict_index () //创建二级索引
				              |-dict_index_add_to_cache ()
                        |-...	// 和建表时创建索引的流程一致		

综上所述,其实建表时创建索引和重启后创建索引的本质过程是一样的,只是在前期步骤有所区别,到了真正为某张表添加索引的时候,所走的路径可以说是完全一样的,不同情况下创建索引的步骤是殊途同归。

How to create index Clustered and Secondary Indexes

封面图片:Marcin Wichary, used under a Creative Commons license

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
1 条评论
热度
最新
感谢分享经验。
感谢分享经验。
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
好险!一入职,就遇到MySQL这么大Bug!差点背锅走人~
今年,这种情况,有时候不找好下家还真不敢跳,这不,前段时间刚跳到新东家,刚办入职那天,就遇上事了,真的是吓出一身冷汗(老大一直盯着我,说要快速解决这个问题),差点被(背)开(锅)了....
用户6543014
2020/11/09
6710
好险!一入职,就遇到MySQL这么大Bug!差点背锅走人~
Data dictionary header(2) --系统表空间结构(三十四)
前面说了系统表空间的整体结构,与独立表空间大致类似,多了五个特有的系统属性页,因为整个表空间只有一个系统表空间,所以他的重要性不言而喻,space id为0。
用户9919783
2022/07/26
2590
MySQL InnoDB表和索引之聚簇索引与第二索引
每个InnoDB表都有一个称之为聚簇索引(clustered index)的特殊索引,存储记录行数据。通常,聚簇索引和主索引是近义的。
授客
2019/09/10
1.1K0
从一个案例深入剖析InnoDB隐式锁和可见性判断
出现这个问题的时候只存在一个读写事务,那就是本事务。对这里的红色部分比较感兴趣,但是这里不是所有的内容都和这个问题相关,主要还是围绕可见性判断和隐式锁判定进行,算是我的思考过程。但是对Innodb认知水平有限,如有误导请谅解。使用的源码版本5.7.29。
老叶茶馆
2020/11/11
8060
从一个案例深入剖析InnoDB隐式锁和可见性判断
MySQL Innodb和Myisam
InnoDB是一种兼顾高可靠性和高性能的通用存储引擎,架构分为两块:内存中的结构和磁盘上的结构。InnoDB 使用日志先行策略,将数据修改先在内存中完成,并且将事务记录成重做日志(Redo Log),转换为顺序IO高效的提交事务。
默存
2022/06/24
1.9K0
MySQL Innodb和Myisam
Mysql索引简明教程
既然我们已经建立了B+树,那么就要好好利用它来加速查询,而不是傻傻的去遍历整张表。
Java3y
2019/11/21
5630
MySQL的InnoDB、MyISAM存储引擎B+tree索引实现原理
官方定义:索引(Index)是帮助MySQL高效获取数据的数据结构,即索引是数据结构。 其出现就是为了提高数据查询效率,就像书的目录。
JavaEdge
2022/11/30
6790
MySQL的InnoDB、MyISAM存储引擎B+tree索引实现原理
MySQL-8.0 | 数据字典最强解读
数据字典(Data Dictionary)中存储了诸多数据库的元数据信息如图1所示,包括基本Database, table, index, column, function, trigger, procedure,privilege等;以及与存储引擎相关的元数据,如InnoDB的tablespace, table_id, index_id等。MySQL-8.0在数据字典上进行了诸多优化,本文将对其进行逐一介绍。
数据和云
2019/05/13
4K0
MySQL InnoDB索引的存储结构
InnoDB索引采用了B-Tree的数据结构,数据存储在叶子节点上,每个叶子节点默认的大小是16KB。
zhanyd
2022/05/16
9340
MySQL InnoDB索引的存储结构
MySQL的这个bug,坑了多少人?
近期,线上有个重要Mysql客户的表在从5.6升级到5.7后,master上插入过程中出现"Duplicate key"的错误,而且是在主备及RO实例上都出现。
终码一生
2022/04/15
5680
MySQL的这个bug,坑了多少人?
老大问我:“建表为啥还设置个自增 id ?用流水号当主键不正好么?”
" 又要开始新项目了,一顿操作猛如虎,梳理流程加画图。这不,开始对流程及表结构了。
why技术
2020/11/02
1.9K0
老大问我:“建表为啥还设置个自增 id ?用流水号当主键不正好么?”
MySQL InnoDB Architecture 简要介绍
buffer pool 是主内存中的一块儿存储区域,用于存储访问的表及索引数据。这样从内存中直接访问获取使用的数据可以极大的提升访问效率。在一些特殊专用的服务里,几乎 80% 的内存区域都被赋于 buffer pool。
WindWant
2023/04/28
4980
MySQL InnoDB Architecture 简要介绍
MySQL笔记-索引
简单来说,索引的出现是为了提高查询效率,就像书的目录一样。MySQL 的索引是在「存储引擎」层实现的,因此没有统一的标准,同一种类型的索引,在不同存储引擎之间实现可能也不同。本文主要分析 InnoDB 存储引擎的索引结构。
WriteOnRead
2019/09/19
5380
MySQL笔记-索引
独家揭秘丨GreatSQL 没开Binlog时多线程插入数据性能劣化之谜
GreatSQL参数配置如下(为降低 I/O 因素影响,关闭 Binlog): #**********************Performance********************* #******connect max_connections=10000 max_connect_errors=1000000 open_files_limit=65535 back_log=1500 table_definition_cache=10000 thread_stack=256K thread_cache_size=3000 #******session sort_buffer_size=4M join_buffer_size=4M read_buffer_size=4M read_rnd_buffer_size=4M bulk_insert_buffer_size=64M tmp_table_size=64M max_heap_table_size=64M net_buffer_length=16K max_allowed_packet=1G #******timeout lock_wait_timeout=600 connect_timeout=10 interactive_timeout=31536000 wait_timeout=31536000 net_read_timeout=86400 net_write_timeout=86400 net_retry_count=10 #**********************InnoDB************************** transaction_isolation=READ-COMMITTED innodb_buffer_pool_size=200G innodb_buffer_pool_instances=16 innodb_max_dirty_pages_pct=90 innodb_flush_log_at_trx_commit=0 innodb_log_buffer_size=1G innodb_page_cleaners=8 innodb_buffer_pool_dump_at_shutdown=ON innodb_buffer_pool_load_at_startup=ON innodb_buffer_pool_dump_pct=100 innodb_checksum_algorithm=NONE innodb_log_checksums=NO innodb_undo_log_truncate=OFF innodb_change_buffering = none innodb_spin_wait_delay=6 innodb_spin_wait_pause_multiplier=50 innodb_sync_spin_loops=30 #******feature innodb_open_files=65535 innodb_flush_method=O_DIRECT innodb_flush_neighbors=0 innodb_flush_sync=ON innodb_io_capacity=20000 innodb_io_capacity_max=40000 innodb_lru_scan_depth=9000 innodb_lock_wait_timeout=30 innodb_print_all_deadlocks=ON innodb_online_alter_log_max_size=4G innodb_thread_concurrency=0 innodb_read_io_threads=32 innodb_write_io_threads=32 innodb_doublewrite=ON innodb_doublewrite_pages=64 innodb_adaptive_hash_index=OFF innodb_status_file=OFF 1、窄表 + 有自增主键 greatsql> CREATE TABLE t1 ( c1 int invisible auto_increment primary key, c2 int, str1 int DEFAULT(100) NOT NULL, str2 int DEFAULT(100) NOT NULL, str3 int DEFAULT(100) NOT NULL, str4 int DEFAULT(100) NOT NULL ) engine=InnoDB; greatsql> CREATE TABLE t2 LIKE t1; 行平均长度约 30 字节 行数插入sql线程数总用时解释1000万行insert into t2 sel
GreatSQL社区
2024/07/26
1150
独家揭秘丨GreatSQL 没开Binlog时多线程插入数据性能劣化之谜
原创|MySQL一个非预期锁等待分析
提示:公众号展示代码会自动折行,建议横屏阅读 背景 客户发现一个非预期内的锁等待现象,线上频繁出现锁告警,出现问题的case可以简化成以下SQL: # 表结构和表数据CREATE TABLE `tab1` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT, `value` int NOT NULL, `status` tinyint unsigned NOT NULL DEFAULT '1', PRIMARY KEY
腾讯数据库技术
2022/10/28
7820
原创|MySQL一个非预期锁等待分析
InnoDB 外存数据结构浅析
| 作者:陈俊熹,腾讯云数据库研发工程师,主要负责腾讯云MySQL数据库研发工作。 ---- 外存数据结构,或者说磁盘数据结构 ( On-Disk Structures ),记录的是需要进行持久化存储的元数据和数据。在存储体系中,访问外存数据带来的系统问题很多,比如如何快速找到数据,如何加速对元数据的频繁访问,如何进行数据一致性存储和灾难恢复等。本文介绍了 InnoDB 主要的外存数据结构,包括表和表空间 ( Table & TableSpace ),索引 ( Index ) 和恢复日志等。理解这些外存数
腾讯云数据库 TencentDB
2019/12/30
5950
InnoDB 外存数据结构浅析
MySQL 聚集索引和二级索引
Every InnoDB table has a special index called the clustered index where the data for the rows is stored. Typically, the clustered index is synonymous with the primary key. To get the best performance from queries, inserts, and other database operations, you must understand how InnoDB uses the clustered index to optimize the most common lookup and DML operations for each table.
JMCui
2020/03/18
1K0
MySQL进阶 1:存储引擎、索引
最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
寻求出路的程序媛
2024/05/16
2000
MySQL进阶 1:存储引擎、索引
InnoDB 层系统字典表 | 全方位认识 information_schema(IFS)
在《Server 层混杂信息字典表 | 全方位认识 information_schema》中,我们详细介绍了information_schema下的状态变量、系统变量、进程状态、字符集和校对规则等字典表,本期我们将为大家带来系列第五篇《InnoDB 层系统字典表 | 全方位认识 information_schema》,下面请跟随我们一起开始information_schema 系统库的系统学习之旅吧。
老叶茶馆
2020/11/26
9770
【MySQL性能调优】-关于索引的那些事儿(一)
数据库和索引的关系就像新华字典和目录的关系一样,索引存在的目的就是为了提高数据查询效率。索引其实就是一种数据结构,存储引擎能通过索引能快速找到你想要的数据。尤其是当下海量数据存储的情况下,索引的使用显得尤为重要。索引能大大减少磁盘扫描的数量,可以将随机IO变为顺序IO,避免排序,高效的索引能将查询性能提升N多倍,今天我们就说一说关于”索引”的那些事。
MySQL数据库技术栈
2020/08/05
4910
【MySQL性能调优】-关于索引的那些事儿(一)
相关推荐
好险!一入职,就遇到MySQL这么大Bug!差点背锅走人~
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验