索引相关疑问

[TOC]

img

创立索引的语句

1.添加PRIMARY KEY(主键索引)
mysql>ALTER TABLE table_name ADD PRIMARY KEY ( column )
2.添加UNIQUE(唯一索引)
mysql>ALTER TABLE table_name ADD UNIQUE (
column
)
3.添加INDEX(普通索引)
mysql>ALTER TABLE table_name ADD INDEX index_name ( column )
4.添加FULLTEXT(全文索引)
mysql>ALTER TABLE table_name ADD FULLTEXT ( column)
5.添加多列索引
mysql>ALTER TABLE table_name ADD INDEX index_name ( column1, column2, column3 )

索引为abc且查询条件为a=xxx order by b时能用上哪个索引?

order by 和group by 类似,字段顺序与索引一致时,会使用索引排序;字段顺序与索引不一致时,不使用索引。

为什么是最左匹配

img

1.简单说下什么是最左匹配原则
顾名思义:最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。
例如:b = 2 如果建立(a,b)顺序的索引,是匹配不到(a,b)索引的;但是如果查询条件是a = 1 and b = 2或者a=1(又或者是b = 2 and b = 1)就可以,因为优化器会自动调整a,b的顺序。再比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,因为c字段是一个范围查询,它之后的字段会停止匹配。

2.最左匹配原则的原理
最左匹配原则都是针对联合索引来说的,所以我们有必要了解一下联合索引的原理。了解了联合索引,那么为什么会有最左匹配原则这种说法也就理解了。

我们都知道索引的底层是一颗B+树,那么联合索引当然还是一颗B+树,只不过联合索引的健值数量不是一个,而是多个。构建一颗B+树只能根据一个值来构建,因此数据库依据联合索引最左的字段来构建B+树。
例子:假如创建一个(a,b)的联合索引,那么它的索引树是这样的

img
可以看到a的值是有顺序的,1,1,2,2,3,3,而b的值是没有顺序的1,2,1,4,1,2。所以b = 2这种查询条件没有办法利用索引,因为联合索引首先是按a排序的,b是无序的。

同时我们还可以发现在a值相等的情况下,b值又是按顺序排列的,但是这种顺序是相对的。所以最左匹配原则遇上范围查询就会停止,剩下的字段都无法使用索引。例如a = 1 and b = 2 a,b字段都可以使用索引,因为在a值确定的情况下b是相对有序的,而a>1and b=2,a字段可以匹配上索引,但b值不可以,因为a的值是一个范围,在这个范围中b是无序的。

查询在什么时候不走(预期中的)索引?

order by原理?

索引失效的情况

1.有or必全有索引;
2.复合索引未用左列字段;
3.like以%开头;
4.where中索引列有运算;
5.where中索引列使用了函数;
6.如果mysql觉得全表扫描更快时(数据少)

索引有哪几种

  1. B+Tree 索引

  2. 哈希索引

    对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码(hash code),哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。

    image-20201218201538017

    image-20201218201739098

    image-20201218201753370

  3. 全文索引

    只有字段的数据类型为 char、varchar、text 及其系列才可以建全文索引

    查找条件使用 MATCH AGAINST,而不是普通的 WHERE。全文索引使用倒排索引实现,它记录着关键词到其所在文档的映射。

1
2
create fulltext index content_tag_fulltext
on fulltext_test(content,tag);
1
2
select * from fulltext_test 
where match(content,tag) against('xxx xxx');
1
https://blog.csdn.net/starzhou/article/details/87519973?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160829400716780274055349%252522%25252C%252522scm%252522%25253A%25252220140713.130102334..%252522%25257D&request_id=160829400716780274055349&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_click~default-1-87519973.nonecase&utm_term=%E5%80%92%E6%8E%92%E7%B4%A2%E5%BC%95
  1. 空间数据索引

联合索引

联合索引是指对表上的多个列进行索引,联合索引也是一棵B+树,不同的是联合索引的键值数量不是1,而是大于等于2.

img

最左前缀匹配

顾名思义是最左优先,以最左边的为起点任何连续的索引都能匹配上.(A,B,C) 这样3列,mysql会首先匹配A,然后再B,C.

如果用(B,C)这样的数据来检索的话,就会找不到A使得索引失效。

覆盖索引

索引包含所有需要查询的字段的值,不需要回表操作。
具有以下优点:
索引通常远小于数据行的大小,只读取索引能大大减少数据访问量。
一些存储引擎(例如 MyISAM)在内存中只缓存索引,而数据依赖于操作系统来缓存。因此,只访问索引可以
不使用系统调用(通常比较费时)。
对于 InnoDB 引擎,若辅助索引能够覆盖查询,则无需访问主索引。

什么情况下不应该用索引?

1.被频繁更新的字段应该慎重建立索引

虽然索引能带来查询上的效率,但是维护索引的成本也是不小的。 如果一个字段不被经常查询,反而被经常修改,那么就更不应该在这种字段上建立索引了。

2.不被经常查询的字段没有必要建立索引

3.数据量不大

4.注意避免冗余索引

冗余索引指的是索引的功能相同,能够命中 就肯定能命中 ,那么 就是冗余索引如(name,city )和(name )这两个索引就是冗余索引,能够命中后者的查询肯定是能够命中前者的 在大多数情况下,都应该尽量扩展已有的索引而不是创建新索引。.尽可能的考虑建立联合索引而不是单列索引

因为索引是需要占用磁盘空间的,可以简单理解为每个索引都对应着一颗B+树。如果一个表的字段过多,索引过多,那么当这个表的数据达到一个体量后,索引占用的空间也是很多的,且修改索引时,耗费的时间也是较多的。如果是联合索引,多个字段在一个索引上,那么将会节约很大磁盘空间,且修改数据的操作效率也会提升。

5.考虑在字符串类型的字段上使用前缀索引代替普通索引

前缀索引仅限于字符串类型,较普通索引会占用更小的空间,所以可以考虑使用前缀索引带替普通索引。

适合创建索引条件

1.不为NULL的字段

索引字段的数据应该尽量不为NULL,因为对于数据为NULL的字段,数据库较难优化。如果字段频繁被查询,但又避免不了为NULL,建议使用0,1,true,false这样语义较为清晰的短值或短字符作为替代。

2.被频繁查询的字段

我们创建索引的字段应该是查询操作非常频繁的字段。

3.被作为条件查询的字段

被作为WHERE条件查询的字段,应该被考虑建立索引。

4.被经常频繁用于连接的字段

经常用于连接的字段可能是一些外键列,对于外键列并不一定要建立外键,只是说该列涉及到表与表的关系。对于频繁被连接查询的字段,可以考虑建立索引,提高多表连接查询的效率。

创建联合索引应该注意什么?

1.最左匹配

2.选择性最大的

3.频繁查询

索引为NULL

a.单列索引无法储null值,复合索引无法储全为null的值。

b.查询时,采用is null条件时,不能利用到索引,只能全表扫描。

为什么索引列无法存储Null值?

​ a.索引是有序的。NULL值进入索引时,无法确定其应该放在哪里。(将索引列值进行建树,其中必然涉及到诸多的比较操作,null 值是不确定值无法比较,无法确定null出现在索引树的叶子节点位置。) 

死锁

死是指两个或多个事务在同一资源上相互占用,并请求锁定对方资源,从而导致恶性循环的现象。
解决方法:
如果不同事务并发存取多个表,尽量约定相同的顺序来访问表,可以降低死锁的机会
在同一个事务中,尽量做到一次锁定所需要的所有资源,减少死锁的概率
对于容易产生死锁的业务,可以用表级锁来减少死锁的概率

主键索引和唯一索引

  • 唯一索引则表示该索引值唯一,可以由一个或几个字段组成,一个表可以有多个唯一索引。

场景提

mysql场景题,userid order time(时间戳)

(1)查询某一用户某一天的订单

(2)查询某一天的订单

(3)查询 某一用户某几天的订单

(3)查询某几天的订单

怎么建立索引,sql语句

前缀索引

TEXT,或者很长的VARCHAR

1
2
3
4
5
6
7
8
9
10
-- 计算出完整字符串的选择性(图4)
SELECT COUNT(DISTINCT city)/COUNT(*) FROM city_demo;
-- 计算各个前缀的选择性(图5),然后找出选择性与图4相近的
SELECT
COUNT(DISTINCT LEFT(city,3))/COUNT(*) pref3,
COUNT(DISTINCT LEFT(city,4))/COUNT(*) pref4,
COUNT(DISTINCT LEFT(city,5))/COUNT(*) pref5,
COUNT(DISTINCT LEFT(city,6))/COUNT(*) pref6,
COUNT(DISTINCT LEFT(city,7))/COUNT(*) pref7
FROM city_demo;
1
ALTER TABLE `city_demo` ADD KEY `idx_city` (`city`(7))