这是mysql系列的下篇,上篇文章地址我附在文末。mysql
索引是对数据库表中一列或多列的值进行排序的一种结构。一个很是恰当的比喻就是书的目录页与书的正文内容之间的关系,为了方便查找书中的内容,经过对内容创建索引造成目录。索引是一个文件,它是要占据物理空间的。面试
主键索引: 数据列不容许重复,不容许为NULL.一个表只能有一个主键。算法
惟一索引: 数据列不容许重复,容许为NULL值,一个表容许多个列建立惟一索引。sql
能够经过 ALTER TABLE table_name ADD UNIQUE (column);
建立惟一索引数据库
能够经过 ALTER TABLE table_name ADD UNIQUE (column1,column2);
建立惟一组合索引编程
普通索引: 基本的索引类型,没有惟一性的限制,容许为NULL值。bash
能够经过ALTER TABLE table_name ADD INDEX index_name (column);
建立普通索引服务器
能够经过ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);
建立组合索引并发
全文索引: 是目前搜索引擎使用的一种关键技术。分布式
能够经过ALTER TABLE table_name ADD FULLTEXT (column);
建立全文索引
最左前缀
index(a,b,c)
where a=3 只使用了a
where a=3 and b=5 使用了a,b
where a=3 and b=5 and c=4 使用了a,b,c
where b=3 or where c=4 没有使用索引
where a=3 and c=4 仅使用了a
where a=3 and b>10 and c=7 使用了a,b
where a=3 and b like 'xx%' and c=7 使用了a,b
复制代码
索引算法有 BTree Hash
BTree是最经常使用的mysql数据库索引算法,也是mysql默认的算法。由于它不只能够被用在=,>,>=,<,<=和between这些比较操做符上,并且还能够用于like操做符,只要它的查询条件是一个不以通配符开头的常量, 例如:
select * from user where name like 'jack%';
若是一通配符开头,或者没有使用常量,则不会使用索引,例如:
select * from user where name like '%jack';
复制代码
Hash Hash索引只能用于对等比较,例如=,<=>(至关于=)操做符。因为是一次定位数据,不像BTree索引须要从根节点到枝节点,最后才能访问到页节点这样屡次IO访问,因此检索效率远高于BTree索引。
BTree索引是最经常使用的mysql数据库索引算法,也是mysql默认的算法。由于它不只能够被用在=,>,>=,<,<=和between这些比较操做符上,并且还能够用于like操做符 例如:
只要它的查询条件是一个不以通配符开头的常量
select * from user where name like 'jack%';
若是一通配符开头,或者没有使用常量,则不会使用索引,例如:
select * from user where name like '%jack';
复制代码
Hash Hash索引只能用于对等比较,例如=,<=>(至关于=)操做符。因为是一次定位数据,不像BTree索引须要从根节点到枝节点,最后才能访问到页节点这样屡次IO访问,因此检索效率远高于BTree索引。
对于低性能的SQL语句的定位,最重要也是最有效的方法就是使用执行计划。 咱们知道,无论是哪一种数据库,或者是哪一种数据库引擎,在对一条SQL语句进行执行的过程当中都会作不少相关的优化,对于查询语句,最重要的优化方式就是使用索引。 而执行计划,就是显示数据库引擎对于SQL语句的执行的详细状况,其中包含了是否使用索引,使用什么索引,使用的索引的相关信息等。
select_type 每一个子查询的查询类型,一些常见的查询类型。
id | select_type | description |
---|---|---|
1 | SIMPLE | 不包含任何子查询或union等查询 |
2 | PRIMARY | 包含子查询最外层查询就显示为 PRIMARY |
3 | SUBQUERY | 在select或 where字句中包含的查询 |
4 | DERIVED | from字句中包含的查询 |
5 | UNION | 出如今union后的查询语句中 |
6 | UNION RESULT | 从UNION中获取结果集,例如上文的第三个例子 |
table 查询的数据表,当从衍生表中查数据时会显示 x 表示对应的执行计划id partitions 表分区、表建立的时候能够指定经过那个列进行表分区。 举个例子:
create table tmp (
id int unsigned not null AUTO_INCREMENT,
name varchar(255),
PRIMARY KEY (id)
) engine = innodb
partition by key (id) partitions 5;
复制代码
type(很是重要,能够看到有没有走索引) 访问类型
possible_keys 可能使用的索引,注意不必定会使用。查询涉及到的字段上若存在索引,则该索引将被列出来。当该列为 NULL时就要考虑当前的SQL是否须要优化了。
key 显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL。
TIPS:查询中若使用了覆盖索引(覆盖索引:索引的数据覆盖了须要查询的全部数据),则该索引仅出如今key列表中
key_length 索引长度
ref 表示上述表的链接匹配条件,即哪些列或常量被用于查找索引列上的值
rows 返回估算的结果集数目,并非一个准确的值。
extra 的信息很是丰富,常见的有:
数据千万级别之多,占用的存储空间也比较大,可想而知它不会存储在一块连续的物理空间上,而是链式存储在多个碎片的物理空间上。可能对于长字符串的比较,就用更多的时间查找与比较,这就致使用更多的时间。
主要两种拆分 垂直拆分,水平拆分。
垂直分表
也就是“大表拆小表”,基于列字段进行的。通常是表中的字段较多,将不经常使用的, 数据较大,长度较长(好比text类型字段)的拆分到“扩展表“。 通常是针对那种几百列的大表,也避免查询时,数据量太大形成的“跨页”问题。
垂直分库针对的是一个系统中的不一样业务进行拆分,好比用户User一个库,商品Producet一个库,订单Order一个库。 切分后,要放在多个服务器上,而不是一个服务器上。为何? 咱们想象一下,一个购物网站对外提供服务,会有用户,商品,订单等的CRUD。没拆分以前, 所有都是落到单一的库上的,这会让数据库的单库处理能力成为瓶颈。按垂直分库后,若是仍是放在一个数据库服务器上, 随着用户量增大,这会让单个数据库的处理能力成为瓶颈,还有单个服务器的磁盘空间,内存,tps等很是吃紧。 因此咱们要拆分到多个服务器上,这样上面的问题都解决了,之后也不会面对单机资源问题。
数据库业务层面的拆分,和服务的“治理”,“降级”机制相似,也能对不一样业务的数据分别的进行管理,维护,监控,扩展等。 数据库每每最容易成为应用系统的瓶颈,而数据库自己属于“有状态”的,相对于Web和应用服务器来说,是比较难实现“横向扩展”的。 数据库的链接资源比较宝贵且单机处理能力也有限,在高并发场景下,垂直分库必定程度上可以突破IO、链接数及单机硬件资源的瓶颈。
水平分表
针对数据量巨大的单张表(好比订单表),按照某种规则(RANGE,HASH取模等),切分到多张表里面去。 可是这些表仍是在同一个库中,因此库级别的数据库操做仍是有IO瓶颈。不建议采用。
水平分库分表
将单张表的数据切分到多个服务器上去,每一个服务器具备相应的库与表,只是表中数据集合不一样。 水平分库分表可以有效的缓解单机和单库的性能瓶颈和压力,突破IO、链接数、硬件资源等的瓶颈。
水平分库分表切分规则
分库分表后面临的问题
事务支持 分库分表后,就成了分布式事务了。若是依赖数据库自己的分布式事务管理功能去执行事务,将付出高昂的性能代价; 若是由应用程序去协助控制,造成程序逻辑上的事务,又会形成编程方面的负担。
跨库join
只要是进行切分,跨节点Join的问题是不可避免的。可是良好的设计和切分却能够减小此类状况的发生。解决这一问题的广泛作法是分两次查询实现。在第一次查询的结果集中找出关联数据的id,根据这些id发起第二次请求获得关联数据。 分库分表方案产品
跨节点的count,order by,group by以及聚合函数问题 这些是一类问题,由于它们都须要基于所有数据集合进行计算。多数的代理都不会自动处理合并工做。解决方案:与解决跨节点join问题的相似,分别在各个节点上获得结果后在应用程序端进行合并。和join不一样的是每一个结点的查询能够并行执行,所以不少时候它的速度要比单一大表快不少。但若是结果集很大,对应用程序内存的消耗是一个问题。
数据迁移,容量规划,扩容等问题 来自淘宝综合业务平台团队,它利用对2的倍数取余具备向前兼容的特性(如对4取余得1的数对2取余也是1)来分配数据,避免了行级别的数据迁移,可是依然须要进行表级别的迁移,同时对扩容规模和分表数量都有限制。总得来讲,这些方案都不是十分的理想,多多少少都存在一些缺点,这也从一个侧面反映出了Sharding扩容的难度。
ID问题
一旦数据库被切分到多个物理结点上,咱们将不能再依赖数据库自身的主键生成机制。一方面,某个分区数据库自生成的ID没法保证在全局上是惟一的;另外一方面,应用程序在插入数据以前须要先得到ID,以便进行SQL路由. 一些常见的主键生成策略
UUID 使用UUID做主键是最简单的方案,可是缺点也是很是明显的。因为UUID很是的长,除占用大量存储空间外,最主要的问题是在索引上,在创建索引和基于索引进行查询时都存在性能问题。 Twitter的分布式自增ID算法Snowflake 在分布式系统中,须要生成全局UID的场合仍是比较多的,twitter的snowflake解决了这种需求,实现也仍是很简单的,除去配置信息,核心代码就是毫秒级时间41位 机器ID 10位 毫秒内序列12位。
mysql中的in语句是把外表和内表做hash 链接,而exists语句是对外表做loop循环,每次loop循环再对内表进行查询。一直你们都认为exists比in语句的效率要高,这种说法实际上是不许确的。这个是要区分环境的。
推荐阅读
最近,我组建了个群聊。学习Java进阶技术干货、实践分享,职位内推,一块儿聊聊理想。志同道合的朋友,欢迎你的加入。
好了,祝你们面试顺利!欢迎长按关注~不按期送书