mysql 索引笔记

MyISAM引擎的B+Tree的索引

myisam

通过上图可以直接的看出,在MyISAM对B+树的运用中明显的特点如下:

  • 所有的非叶子节点中存储的全部是索引信息
  • 在叶子节点中存储的 value值其实是 数据库中某行数据的index

**MyISAM引擎 索引文件的查看: **

在 /var/lib/mysql目录中

.myd 即 my data,数据库中表的数据文件

.myi 即 my index,数据库中 索引文件

.log 即 mysql的日志文件

**InnoDB引擎 索引文件的查看: **

同样在 /var/lib/mysql 目录下面

InnoDB引擎的B+Tree的索引

InnoDB

InnoDB的实现方式业内也称其为聚簇索引,什么是聚簇索引呢? 就是相邻的行的键值被存储到一起,对比上面的两幅图片就会发现,在InnDB中,B+树的叶子节点中存储的是数据行中的一行行记录,缺点: 因为索引文件被存放在硬盘上,所以很占硬盘的空间

一般我们会在每一个表中添加一列 取名 id,设置它为primary key,即将他设置成主键,如果使用的存储引擎也是InnoDB的话,底层就会建立起主键索引,也是聚簇索引,并且会自动按照id的大小为我们排好序,(因为它的一个有序的树)

点击查看 参考博文1

局部性原理

局部性原理是指CPU访问存储器时,无论是存取指令还是存取数据,所访问的存储单元都趋于聚集在一个较小的连续区域中。 更进一步说,当我们通过程序向操作系统发送指令让它读取我们指定的数据时,操作系统会一次性读取一页(centos 每页4kb大小,InnoDB存储引擎中每一页16kb)的数据,它遵循局部性理论,猜测当用户需要使用某个数据时,用户很可能会使用这个数据周围的数据,故而进行一次读取

InnoDB的页格式

什么是页呢? 简单说,就是一条条数据被的存储在磁盘上,使用数据时需要先将数据从磁盘上读取到内存中,InnoDB每次读出数据时同样会遵循 局部性原理,而不是一条条读取,于是InnoDB将数据划分成一个一个的页,以页作为和磁盘之间交互的基本单位

通过如下sql,可以看到,InnoDB中每一页的大小是16kb

show global status like 'Innodb_page_size';

数据页图片

名称 简述
File Header 文件头部,存储页的一些通用信息
Page Header 页面头部,存储数据页专有的信息
Infinum + supremum 最大记录和最小记录,这是两个虚拟的行记录
User Records 用户记录,用来实际存储行记录中的内容
Free Space 空闲空间,页中尚位使用的空间
Page Directory 页面目录,存储页中某些记录的位置
File Tailer 文件尾部,用来校验页是否完整

InnoDB的行格式 compact

每一页中存储的行数据越多. 整体的性能就会越强

compact的行格式如下图所示

compact

可以看到在行格式中在存储真正的数据的前面会存储一些其他信息,这些信息是为了描述这条记录而不得不添加的一些信息,这些额外的信息就是上图中的前三行

  • 变长字段的长度列表

在mysql中char是固定长度的类型,同时mysql还支持诸如像 varchar这样可变长度的类型,不止varchar,想 varbinary text blob这样的变长数据类型,因为 变长的数据类型的列存储的数据的长度是不固定的,所以说我们在存储真正的数据时,也得将这些数据到底占用了多大的长度也给保存起来

  • NULL标志位

compact行格式会将值可以为NULL的列统一标记在 NULL标志位中,如果数据表中所有的字段都被标记上not null,那么就没有NULL值列表

  • 记录头信息

记录头

记录头信息,顾名思义就是用来描述记录头中的信息,记录头信息由固定的5个字节组成,一共40位,不同位代表的意思也不同,如下表

名称 单位 bit 简介
预留位1 1 未使用
预留位2 1 未使用
delete_mark 1 标记改行记录是否被删除了
min_rec_mark 1 标记在 B+树中每层的非叶子节点中最小的node
n_owned 4 表示当前记录拥有的记录数
heap_no 13 表示当前记录在堆中的位置
record_type 3 表示当前记录的类型 , 0表示普通记录, 1表示B+树中非叶子节点记录, 2表示最小记录 ,3表示最大记录
next_record 16 表示下一条记录的相对位置

点击查看 参考博文2

行溢出

在mysql中每一行,能存储的最大的字节数是65535个字节数,此时我们使用下面的sql执行时就会出现行溢出现象

CREATE TABLE test ( c VARCHAR(65535) ) CHARSET=ascii ROW_FORMAT=Compact;

给varchar申请最大65535,再加上compact行格式中还有前面三个非数据列占用内存,所以一准溢出,如果不想溢出,可以适当的将 65535 - 3

页溢出

前面说了,InnoDB中数据的读取按照页为单位,每一页的大小是 16kb,换算成字节就是16384个字节,但是每行最多存储 65535个字节啊,也就是说一行数据可能需要好几个页来存储

怎么办呢?

  • compact行格式会在存储真实数据的列中多存储一部分数据,这部分数据中存储的就是下一页的地址
  • dynamic行格式 中直接存储数据所在的地址,换句话说就是数据都被存储在了其他页上
  • compressed行格式会使用压缩算法对行格式进行压缩处理

**一般我们都是将表中的id列设置为主键,这就会形成主键索引,于是我们需要注意了: **

主键的占用的空间越小,整体的检索效率就会越高

为什么这么说呢? 这就可以结合页的概念来解析,在B+树这种数据结果中,叶子节点中用来存储数据,存储数据的格式类似Key-value key就是索引值,value就是数据内容,如果索引占用的空间太大的话,单页16kb能存储的索引就越小,这就导致数据被分散在更多的页上,致使查询的效率降低

建立索引的技巧

为某一列建立索引

给text表中的title列创建索引,索引名字 my_index
alter table text add index my_index (title);

虽然建立索引能提升查询的效率,根据前人的经验看,这并不是一定的,建立索引本身会直接消耗内存空间,同时索,插入,删除,这种写操作就会打破B+树的平衡面临索引的重建,一般出现如下两种情况时,是不推荐建立索引的

  1. 表中的数据本身就很少
  2. 我们计算一下索引的选择性很低

兼顾 - 索引的选择性与前缀索引

所谓选择性,其实就是说不重复出现的索引值(基数,Cardinality) 与 表中的记录数的比值

即: 选择性= 基数 / 记录数

选择性的取值范围在(0,1]之间,选择性越接近1,说明建立索引的必要性就越强,比如对sex列进行建立索引,这里面非男即女,如果对它建立索引的话,其实是没意义的,还不如直接进行全表扫描来的快

如何使用sql计算选择性呢? 严格遵循上面的公式

SELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles;
count(基数/记录数)
DISTINCT(title) / /count(*)

更详细的例子看下面的连接

参考博文

索引失效问题

注意事项

  • 索引无法存储null值

  • 如果条件中有or,即使条件中存在索引也不会使用索引,如果既想使用or,又想使用索引,就给所有or条件控制的列加上索引

  • 使用like查询时,如果以%开头,肯定是进行全表扫描

  • 使用like查询时,如果%在条件后面

    • 对于主键索引,索引失效
    • 对于普通索引,索引不失效
  • 如果列的类型是字符串类型,那么一定要在条件中将数据用引号引起来,不然也会是索引失效

  • 如果mysql认为全表扫描比用索引块,同样不会使用索引

联合索引

什么是联合索引

联合索引,也叫复合索引,说白了就是多个字段一起组合成一个索引

像下面这样使用 id + title 组合在一起构成一个联合索引

CREATE TABLE `text` (
  `id` int(11) NOT NULL AUTO_INCREMENT,`title` varchar(255) NOT NULL,`content` text NOT NULL,PRIMARY KEY (`id`,`title`)
) ENGINE=InnoDB AUTO_INCREMENT=3691 DEFAULT CHARSET=utf8
  • 如果我们像上图那样创建了索引,我们只要保证我们的 id+title 两者结合起来全局唯一就ok
  • 建立联合索引同样是需要进行排序的,排序的规则就是按照联合索引所有列组成的字符串的之间的先后顺序进行排序,如a比b优先

左前缀原则

使用联合索引进行查询时一定要遵循左前缀原则,什么是左前缀原则呢? 就是说想让索引生效的话,一定要添加上第一个索引,只使用第二个索引进行查询的话会导致索引失效

比如上面创建的联合索引,假如我们的查询条件是 where id = '1' 或者 where id = '1' and title = '唐诗宋词' 索引都会不失效

但是如果我们不使用第一个索引id,像这样 where title = '唐诗',结果就是导致索引失效

联合索引的分组&排序

还是使用这个例子:

CREATE TABLE `text` (
  `id` int(11) NOT NULL AUTO_INCREMENT,`title`)
) ENGINE=InnoDB AUTO_INCREMENT=3691 DEFAULT CHARSET=utf8

demo1: 当我们像下面这样写sql时,就会先按照id进行排序,当id相同时,再按照title进行排序

select * form text order by id,title;

demo2: 当我们像下面这样写sql时,就会先将id相同的划分为一组,再将title相同的划分为一组

select id,title form text group by id,title;

demo3: ASC和DESC混用,其实大家都知道底层使用B+树,本身就是有序的,要是不加限制的话,默认就是ASC,反而是混着使用就使得索引失效

select * form text order by id ASC,title DESC;

如何定位慢查询

相关参数

名称 简介
slow_query_log 慢查询的开启状态
slow_query_log_file 慢查询日志存储的位置
long_query_time 查询超过多少秒才记录下来

常用sql

# 查看mysql是否开启了慢查询
show variables like 'slow_query_log';   
# 将全局变量设置为ON
set global slow_query_log ='on';
# 查看慢查询日志存储的位置
show variables like 'slow_query_log_file';
# 查看规定的超过多少秒才被算作慢查询记录下来
show variables like 'long_query_time';
show variables like 'long_query%';
# 超过一秒就记录,每次修改这个配置都重新建立一次链接
set global long_query_time=1; 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


在正式开始之前,我们先来看下 MySQL 服务器的配置和版本号信息,如下图所示: “兵马未动粮草先行”,看完了相关的配置之后,我们先来创建一张测试表和一些测试数据。 -- 如果存在 person 表先删除 DROP TABLE IF EXISTS person; -- 创建 person 表,其中
> [合辑地址:MySQL全面瓦解](https://www.cnblogs.com/wzh2010/category/1859594.html "合辑地址:MySQL全面瓦解") # 1 为什么需要数据库备份 - 灾难恢复:当发生数据灾难的时候,需要对损坏的数据进行恢复和
物理服务机的CPU、内存、存储设备、连接数等资源有限,某个时段大量连接同时执行操作,会导致数据库在处理上遇到性能瓶颈。为了解决这个问题,行业先驱门充分发扬了分而治之的思想,对大库表进行分割,
然后实施更好的控制和管理,同时使用多台机器的CPU、内存、存储,提供更好的性能。而分治有两种实现方式:垂直拆
1 回顾 上一节我们详细讲解了如何对数据库进行分区操作,包括了 垂直拆分(Scale Up 纵向扩展)和 水平拆分(Scale Out 横向扩展) ,同时简要整理了水平分区的几种策略,现在来回顾一下。 2 水平分区的5种策略 2.1 Hash(哈希) 这种策略是通过对表的一个或多个列的Ha
navicat查看某个表的所有字段的详细信息 navicat设计表只能一次查看一个字段的备注信息,那怎么才能做到一次性查询表的信息呢?SELECT COLUMN_NAME,COLUMN_COMMENT,COLUMN_TYPE,COLUMN_KEY FROM information_schema.CO
文章浏览阅读4.3k次。转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52768613前言:数据库每天的数据不断增多,自动删除机制总体风险太大,想保留更多历史性的数据供查询,于是从小的hbase换到大的hbase上,势在必行。今天记录下这次数据仓库迁移。看下Agenda:彻底卸载MySQL安装MySQL_linux服务器进行数据迁移
文章浏览阅读488次。恢复步骤概要备份frm、ibd文件如果mysql版本发生变化,安装回原本的mysql版本创建和原本库名一致新库,字符集都要保持一样通过frm获取到原先的表结构,通过的得到的表结构创建一个和原先结构一样的空表。使用“ALTER TABLE DISCARD TABLESPACE;”命令卸载掉表空间将原先的ibd拷贝到mysql的仓库下添加用户权限 “chown . .ibd”,如果是操作和mysql的使用权限一致可以跳过通过“ALTER TABLE IMPORT TABLESPACE;”命令恢_alter table discard tablespace
文章浏览阅读225次。当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化:单表优化除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑、部署、运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的。而事实上很多时候MySQL单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量:字段尽量使用TINYINT、SMALLINT、MEDIUM_INT作为整数类型而非INT,如果非负则加上UNSIGNEDVARCHAR的长度只分配_开发项目 浏览记录表 过大怎么办
文章浏览阅读1.5k次。Mysql创建、删除用户MySql中添加用户,新建数据库,用户授权,删除用户,修改密码(注意每行后边都跟个;表示一个命令语句结束):1.新建用户登录MYSQL:@>mysql -u root -p@>密码创建用户:mysql> insert into mysql.user(Host,User,Password) values("localhost_删除mysql用户组
MySQL是一种开源的关系型数据库管理系统,被广泛应用于各类应用程序的开发中。对于MySQL中的字段,我们需要进行数据类型以及默认值的设置,这对于数据的存储和使用至关重要。其中,有一个非常重要的概念就是MySQL字段默认字符串。 CREATE TABLE `my_...
MySQL是一个流行的开源关系型数据库管理系统,广泛应用于Web应用程序开发、数据存储和管理。在使用MySQL时,正确设置字符集非常重要,以确保数据的正确性和可靠性。 在MySQL中,字符集表示为一系列字符和字母的集合。MySQL支持多种字符集,包括ASCII、UTF...
MySQL存储函数 n以内偶数 MySQL存储函数能够帮助用户简化操作,提高效率,常常被用于计算和处理数据。下面我们就来了解一下如何使用MySQL存储函数计算n以内的偶数。 定义存储函数 首先,我们需要定义一个MySQL存储函数,以计算n以内的偶数。下...
MySQL是一个流行的关系型数据库管理系统,基于客户机-服务器模式,可在各种操作系统上运行。 MySQL支持多种字符集,不同的字符集包括不同的字符,如字母、数字、符号等,并提供不同的排序规则,以满足不同语言环境的需求。 //查看MySQL支持的字符集与校对规...
在MySQL数据库中,我们有时需要对特定的字符串进行截取并进行分组统计。这种操作对于数据分析和报表制作有着重要的应用。下面我们将讲解一些基本的字符串截取和分组统计的方法。 首先,我们可以使用substring函数对字段中的字符串进行截取。假设我们有一张表stude...
MySQL提供了多种字符串的查找函数。下面我们就一一介绍。 1. LIKE函数 SELECT * FROM mytable WHERE mycolumn LIKE 'apple%'; 其中"apple%"表示以apple开头的字符串,%表示任意多个字符...
MySQL 是一种关系型数据库管理系统,广泛应用于各种不同规模和类型的应用程序中。在 MySQL 中,处理字符串数据是很常见的任务。有时候,我们需要在字符串的开头添加一定数量的 0 ,以达到一定的位数。比如,我们可能需要将一个数字转换为 4 位或 5 位的字符串,不足的...
MySQL是一种流行的关系型数据库管理系统,支持多种数据类型。以下是MySQL所支持的数据类型: 1. 数值型数据类型: - TINYINT 保存-128到127范围内的整数 - SMALLINT 保存-32768到32767范围内的整数 - MEDIU...
MySQL中存储Emoji表情字段类型 在现代互联网生态中,表情符号已经成为人们展示情感和思想的重要方式之一,因此将表情符号存储到数据库中是一个经常出现的问题。MySQL作为最流行的开源关系型数据库管理系统之一,也需要能够存储和管理这些表情符号的字段类型。 UT...
MySQL是一种关系型数据库管理系统。在MySQL数据库中,有多种不同的数据类型。而其中,最常见的数据类型之一就是字符串类型。在MySQL中,字符串类型的数据通常会被存储为TEXT或VARCHAR类型。 首先,让我们来看一下VARCHAR类型。VARCHAR是My...
MySQL字符串取整知识详解 MySQL是一种开源的关系型数据库管理系统,广泛应用于各个领域。在使用MySQL过程当中,我们经常需要对数据进行取整操作。本文将介绍如何使用MySQL字符串取整来处理数据取整问题。 什么是MySQL字符串取整? MySQL...