目录
一、mysql存储引擎
二、索引
1.索引的优缺点
2.索引的分类
3.索引的语法
4.索引原理
1)BTree
2)B-树
3)B+树
4)B*树
5)位图索引
6)hash索引
5.索引优化
1)注意事项
2)使用技巧
一、mysql存储引擎
功能 | MYISAM | Memory | InnoDB |
存储限制 | 256TB | RAM | 64TB |
支持事务 | No | No | Yes |
支持全文索引 | Yes | No | No(5.6版本以上支持) |
支持树索引 | Yes | Yes | Yes |
支持哈希索引 | No | Yes | No |
支持数据缓存 | No |
| Yes |
支持外键 | No | No | Yes |
文件结尾 | frm(表结构定义)、myd(数据库数据文件)、myi(索引文件) | .frm(表结构定义) | .frm(表结构定义)、.ibd(存储数据和索引) |
锁 | 表锁,不适合高并发 | 表锁 | 行级锁,适合高并发 |
缓存 | 缓存索引,不缓存真实对象 | | 缓存索引和真实数据,对内存要求高 |
表空间 | 小 | | 大 |
适用场景 | 非事务的类型 只读类应用,读取速度快 | 系统使用临时表的时候,超过限制会使用Myisam,未超过使用Memory。 mysql后台服务使用Memory | 事务性存储引擎,支持事务 并发度高 大多数的OLTP应用 |
1)mysql5.5版本之前的版本默认存储引擎是myisam,之后的默认引擎是innodb
2)mysql5.6之前是系统表空间,之后是独立表空间
3)临时表:在同一个session(会话)里面,才能使用。重启服务会丢失数据
二、索引
1.索引的优缺点
优点:可以快速检索,减少I/O次数,加快检索速度;根据索引分组和排序,可以加快分组和排序。
缺点:索引本身也是表,因此会占用存储空间,一般来说,索引表占用的空间的数据表的1.5倍;索引表的维护和创建需要时间成本,这个成本随着数据量增大而增大;构建索引会降低数据表的修改操作(删除,添加,修改)的效率,因为在修改数据表的同时还需要修改索引表。
使用原则:1)对经常更新的表避免对其加过多的索引,对经常查询的字段添加索引;2)数据量小的表最好不加索引,遍历全表的时间可能比遍历索引的时间还要短,加索引就没有意义了;3)在值种类少的字段上不建议加索引,如性别字段只有男女两种,添加索引没意义;4)经常作为查询条件或者需要排序的列建立索引;5)与其他表建立关联字段的外键建议建立索引;6)高并发条件下倾向组合索引;7)用于聚合函数的列可以建立索引,如max(col1)或count(col1),建议对col1建立索引。
2.索引的分类
1)主键索引:主索引,不允许重复,不允许空值,是一种比较特殊的唯一索引
2)唯一索引:不允许重复,允许空值
3)普通索引:普通字段添加索引,没太多限制,允许重复,允许空值,只是为了增加查询速度
4)全文索引:对大文本添加的索引,mysql5.6版本之前,只有myisam引擎才支持,5.6之后,innodb也支持了,只在char,varchar,text上添加
5)组合索引:多个列组合创建的索引,多个列不允许有空值,遵循最左前缀原则
6)空间索引:空间索引是对空间数据类型的字段建立的索引,MySQL中的空间数据类型有四种,GEOMETRY、POINT、LINESTRING、POLYGON。在创建空间索引时,使用SPATIAL关键字。要求,引擎为MyISAM,创建空间索引的列,必须将其声明为NOT NULL
3.索引的语法
1)创建表时创建索引
create table 表名(
id int not null auto_increment,
name varchar(64) default null,
primary key (id),
index 索引名(字段名)
);
或者
create table 表名(
id int not null auto_increment,
name varchar(64) default null,
primary key (id),
key 索引名(字段名)
);
2)创建表后添加索引
alter table 表名 add index 索引名(字段名);
或者
create index 索引名 on 表名(字段名);
以上创建的为普通索引,如果创建其他类型索引,sql如下
alter table 表名 add [类型] index 索引名(字段名);
或者create [索引类型] index 索引名 on 表名 (字段名);
主键索引:alter table 表名 add primary index 索引名(字段名);或者
create unique index 索引名 on 表名 (字段名);
唯一索引:alter table 表名 add unique index 索引名(字段名);
全文索引:alter table 表名 add fulltext index 索引名(字段名);
组合索引:alter table 表名 add index 索引名(字段1名,字段2名字,字段3名);
组合索引还可以只对某个字段的前N位建立索引,
ALTER TABLE USER_DEMO ADD INDEX name_city_age (LOGIN_NAME(16),CITY,AGE);
建表时,LOGIN_NAME长度为100,这里用16,是因为一般情况下名字的长度不会超过16,这样会加快索引查询速度,还会减少索引文件的大小,提高INSERT,UPDATE的更新速度。
如果分别给LOGIN_NAME,CITY,AGE建立单列索引,让该表有3个单列索引,查询时和组合索引的效率是大不一样的,甚至远远低于我们的组合索引。虽然此时有三个索引,但mysql只能用到其中的那个它认为似乎是最有效率的单列索引,另外两个是用不到的,也就是说还是一个全表扫描的过程。
建立这样的组合索引,就相当于分别建立如下三种组合索引:
LOGIN_NAME,CITY,AGE
LOGIN_NAME,CITY
LOGIN_NAME
3)删除索引
drop index 索引名 on 表名;
或者
alter table 表名 drop index 索引名;
对于非组合索引,删除该列,则该列对应的索引相应删除。如果删除组合索引中的某一列,组合索引仍然存在,只是没有该列的了。
4)查询表中的索引
show index from 表名;
5)查询语句中是否使用索引
explain 查询语句;
如
explain select * from user where name='小明';
4.索引原理
//TODO 数据结构总结完,再补充
1)BTree
即二叉搜索树:
1.所有非叶子结点至多拥有两个儿子(Left和Right);
2.所有结点存储一个关键字;
3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树;
如:
B树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中;否则,如果查询关键字比结点关键字小,就进入左儿子;如果比结点关键字大,就进入右儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键字;
如果B树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么B树的搜索性能逼近二分查找;但它比连续内存空间的二分查找的优点是,改变B树结构(插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销;
如:
但B树在经过多次插入与删除后,有可能导致不同的结构:
右边也是一个B树,但它的搜索性能已经是线性的了;同样的关键字集合有可能导致不同的树结构索引;所以,使用B树还要考虑尽可能让B树保持左图的结构,和避免右图的结构,也就是所谓的“平衡”问题;
实际使用的B树都是在原B树的基础上加上平衡算法,即“平衡二叉树”;如何保持B树结点分布均匀的平衡算法是平衡二叉树的关键;平衡算法是一种在B树中插入和删除结点的策略。常见的平衡二叉树有:AVL,RBT,Treap,Splay Tree。
2)B-树
是一种多路搜索树(并不是二叉的):
1.定义任意非叶子结点最多只有M个儿子;且M>2;
2.根结点的儿子数为[2, M];
3.除根结点以外的非叶子结点的儿子数为[M/2,M];
4.每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)
5.非叶子结点的关键字个数=指向儿子的指针个数-1;
6.非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
7.非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
8.所有叶子结点位于同一层;
如:(M=3)
B-树的搜索,从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空,或已经是叶子结点;
B-树的特性:
1.关键字集合分布在整颗树中;
2.任何一个关键字出现且只出现在一个结点中;
3.搜索有可能在非叶子结点结束;
4.其搜索性能等价于在关键字全集内做一次二分查找;
5.自动层次控制;
由于限制了除根结点以外的非叶子结点,至少含有M/2个儿子,确保了结点的至少利用率,其最底搜索性能为:
其中,M为设定的非叶子结点最多子树个数,N为关键字总数;
所以B-树的性能总是等价于二分查找(与M值无关),也就没有B树平衡的问题;
由于M/2的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占M/2的结点;删除结点时,需将两个不足M/2的兄弟结点合并;
3)B+树
B+树是B-树的变体,也是一种多路搜索树:
1.其定义基本与B-树同,除了:
2.非叶子结点的子树指针与关键字个数相同;
3.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B-树是开区间);
5.为所有叶子结点增加一个链指针;
6.所有关键字都在叶子结点出现;
如:(M=3)
B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树可以在非叶子结点命中),其性能也等价于在关键字全集做一次二分查找;
B+的特性:
1.所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
2.不可能在非叶子结点命中;
3.非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;
4.更适合文件索引系统;
4)B*树
是B+树的变体,在B+树的非根和非叶子结点再增加指向兄弟的指针;
B*树定义了非叶子结点关键字个数至少为(2/3)*M,即块的最低使用率为2/3(代替B+树的1/2);
B+树的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父结点,而不会影响兄弟结点,所以它不需要指向兄弟的指针;
B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,最后修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针;
所以,B*树分配新结点的概率比B+树要低,空间使用率更高;
小结
B树:二叉树,每个结点只存储一个关键字,等于则命中,小于走左结点,大于走右结点;
B-树:多路搜索树,每个结点存储M/2到M个关键字,非叶子结点存储指向关键字范围的子结点;
所有关键字在整颗树中出现,且只出现一次,非叶子结点可以命中;
B+树:在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中;
B*树:在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3
5)位图索引
a.案例
有张表名为table的表,由三列组成,分别是姓名、性别和婚姻状况,其中性别只有男和女两项,婚姻状况由已婚、未婚、离婚这三项,该表共有100w个记录。现在有这样的查询: select * from table where Gender=‘男’ and Marital=“未婚”;
姓名(Name) | 性别(Gender) | 婚姻状况(Marital) |
张三 | 男 | 已婚 |
李四 | 女 | 已婚 |
王五 | 男 | 未婚 |
赵六 | 女 | 离婚 |
孙七 | 女 | 未婚 |
... | ... | ... |
1)不使用索引
不使用索引时,数据库只能一行行扫描所有记录,然后判断该记录是否满足查询条件。
2)B树索引
对于性别,可取值的范围只有'男','女',并且男和女可能各站该表的50%的数据,这时添加B树索引还是需要取出一半的数据, 因此完全没有必要。相反,如果某个字段的取值范围很广,几乎没有重复,比如身份证号,此时使用B树索引较为合适。事实上,当取出的行数据占用表中大部分的数据时,即使添加了B树索引,数据库如oracle、MySQL也不会使用B树索引,很有可能还是一行行全部扫描。
b.位图索引出马
如果用户查询的列的基数非常的小, 即只有的几个固定值,如性别、婚姻状况、行政区等等。要为这些基数值比较小的列建索引,就需要建立位图索引。
对于性别这个列,位图索引形成两个向量,男向量为10100...,向量的每一位表示该行是否是男,如果是则位1,否为0,同理,女向量位01011。
RowId | 1 | 2 | 3 | 4 | 5 | ... |
男 | 1 | 0 | 1 | 0 | 0 |
|
女 | 0 | 1 | 0 | 1 | 1 | ... |
对于婚姻状况这一列,位图索引生成三个向量,已婚为11000...,未婚为00100...,离婚为00010...。
RowId | 1 | 2 | 3 | 4 | 5 | ... |
已婚 | 1 | 1 | 0 | 0 | 0 |
|
未婚 | 0 | 0 | 1 | 0 | 1 |
|
离婚 | 0 | 0 | 0 | 1 | 0 |
|
当我们使用查询语句“select * from table where Gender=‘男’ andMarital=“未婚”;”的时候 首先取出男向量10100...,然后取出未婚向量00100...,将两个向量做and操作,这时生成新向量00100...,可以发现第三位为1,表示该表的第三行数据就是我们需要查询的结果。
RowId | 1 | 2 | 3 | 4 | 5 |
男 | 1 | 0 | 1 | 0 | 0 |
and |
|
|
|
|
|
未婚 | 0 | 0 | 1 | 0 | 1 |
结果 | 0 | 0 | 1 | 0 | 0 |
c.位图索引适应场景
上面讲了,位图索引适合只有几个固定值的列,如性别、婚姻状况、行政区等等,而身份证号这种类型不适合用位图索引。
此外,位图索引适合静态数据,而不适合索引频繁更新的列。举个例子,有这样一个字段busy,记录各个机器的繁忙与否,当机器忙碌时,busy为1,当机器不忙碌时,busy为0。
这个时候有人会说使用位图索引,因为busy只有两个值。好,我们使用位图索引索引busy字段!假设用户A使用update更新某个机器的busy值,比如update table set table.busy=1 where rowid=100;,但还没有commit,而用户B也使用update更新另一个机器的busy值,update table set table.busy=1 where rowid=12; 这个时候用户B怎么也更新不了,需要等待用户A commit。
原因:用户A更新了某个机器的busy值为1,会导致所有busy为1的机器的位图向量发生改变,因此数据库会将busy=1的所有行锁定,只有commit之后才解锁。
6)hash索引
索引列会被存储在匹配到的hash bucket里面的表里,这个表里会有实际的数据行指针,再根据实际的数据行指针查找对应的数据行。
概括来说,要查找一行数据或者处理一个where子句,SQL Server引擎需要做下面几件事
1、根据where条件里面的参数生成合适的哈希函数
2、索引列进行匹配,匹配到对应hash bucket,找到对应hash bucket意味着也找到了对应的数据行指针(row pointer)
3、读取数据
哈希索引比起B树索引简单,因为它不需要遍历B树,所以访问速度会更快
Hash索引的缺点:
1、因为Hash索引比较的是经过Hash计算的值,所以只能进行等式比较,不能用于范围查询
2、由于哈希值是按照顺序排列的,但是哈希值映射的真正数据在哈希表中就不一定按照顺序排列,所以无法利用Hash索引来加速任何排序操作
3、不能用部分索引键来搜索,因为组合索引在计算哈希值的时候是一起计算的。
4、当哈希值大量重复且数据量非常大时,其检索效率并没有Btree索引高的。
7)全文索引
全文索引可以支持各种字符内容的搜索,也支持自然语言搜索和布尔搜索。当前只有MyISAM引擎支持全文索引。但是MyISAM对全文索引的支持右很多限制,例如表级别锁对性能的影响、数据文件的崩溃、崩溃后的恢复等,这使得MyISAM的全文索引对于很多应用场景并不合适。
MyISAM的全文索引作用对象是一个“全文集合”,这可能是某个数据表的一列,也可能是多个列。具体的,对数据表的某一条记录,mysql会将需要索引的列全部拼接成一个字符串,然后进行索引。
MyISAM的全文索引是一类特殊的b-tree索引,共有两层。第一层是所有关键字,然后对于每一个关键字的第二层,包含的是一组相关的“文档指针”。全文索引不会索引文档对象中的所有词语,他会根据如下规则过滤一些词语:
- 停用列表中的词语都不会被索引。默认的停用词根据通用英语的使用来设置,可以使用参数ft_stopword_file指定一组外部文件来使用自定义的停用词。
- 对于长度大于ft_min_word_len的词语和长度小于ft_max_word_len的词语,都不会被索引。
全文索引并不会存储关键字具体匹配在哪一列,如果需要根据不同的列来进行组合查询,那么不需要针对每一列来建立多个这类索引。
这意味着不能在match against子句中指定那个列的相关性更重要。通常构建一个网站的搜索引擎是需要这样的功能,例如,你可能希望优先搜索出那些在标题中出现过的文档对象。如果需要这样的功能,则需要编写更复杂的查询语句。
1、自然语言的全文索引
自然语言所有引擎将计算每一个文档对象和查询的相关度。这里,相关度是基于匹配的关键词个数,以及关键词在文档中出现的次数。在整个索引中出现次数越少的词语,匹配时的相关度就越高。相反,非常常见的单词就不会搜索,即使不在停用词列表中出现,如果一个词语在超过50%的记录中都出现了,那么自然语言搜索将不会搜索这类词语。
全文索引的语法和普通词查询略有不同。可以根据where子句中的match against来区分查询是否使用全文索引。函数match将返回关键词匹配的相关度,是一个浮点数字。在一个查询中使用两次match函数并不会有额外的消耗,mysql会自动识别并只进行一次搜索。不过,如果将match函数放到order by子句中,mysql将会使用文件排序。
在match函数中指定的列必须和在全文索引中指定的列完全相同,否则就无法使用全文索引。这是因为全文索引不会记录关键词是来自那一列的。这也意味着无法使用全文索引来查询某个关键词是否在某一列中存在。
2、布尔全文索引
在布尔搜索中,用户可以在查询中自定义某个被搜索的词语的相关性。布尔搜索通过停用词列表过滤掉那些“噪声”词,除此之外,布尔搜索还要求搜索关键词长度必须大于ft_min_word_len,同时小于ft_max_word_len。搜索返回的结果是未经排序的。例如:select film_id,title from film_text where match(title,description) against('+factory +casualties' in boolean mode);
只有MyISAM引擎才能使用布尔全文索引,但并不是一定有全文索引才能使用布尔全文搜索。当没有全文索引的时候,mysql就通过全表扫描来实现。所以,你甚至还可以在多表上使用布尔全文索引,例如在一个关联结果上进行。只不过,因为全表扫描,速度可能会很慢。
3、全文索引的限制和替代方案
mysql的全文索引实现有很多的设计本身带来的限制。例如:mysql全文索引中只有一种判断相关性的方法--词频。索引也不会记录索引词在字符串中的位置,所以位置也就无法用在相关性上。虽然大多数情况下,数据量很小的时候,这些限制不会影响使用,但也可能不是你所想要的。而且mysql的全文索引也没有提供其他可选的相关性排序算法。
数据量的大小也是一个问题。mysql的全文索引只有全部在内存中的时候,性能才非常好。如果内存无法装载全部索引,那么搜索速度会非常慢。当你使用精确短语搜索时,想要好的性能,数据和索引都需要在内存中。相比于其他的索引类型,当insert、update和delete操作进行时,全文索引的操作代价非常大:
- 修改一段文本中的100个单词,需要100词索引操作,而不是一次;
- 一般来说列长度并不会太影响其他的索引类型,但是如果是全文索引,三个单词的文本和10 000个单词的文本,性能可能会相差几个数量级。
- 全文索引会有更多的碎片,可能需要做更多的optimize table操作。
全文索引还会影响查询优化器的工作。索引选择、where子句、oeder by都有可能不是按照你所预想的方式工作:
- 如果查询中使用了match against子句,而对应列上又有可用的全文索引,那么mysql就一定会使用这个全文索引。这时,即使其他的索引可以使用,mysql也不会去比较到底哪个索引的性能更好。所以,即使这时有更合适的索引可以使用,mysql仍然会置之不理。
- 全文索引只能用作全文搜索匹配。任何其他操作,如where条件比较,都必须在mysql完成全文搜索返回记录后才能进行。这和其他普通索引不同。
- 全文索引不存储索引列的实际值。也就不可能用作索引覆盖扫描。
- 除了相关性排序,全文索引不能用作其他的排序。如果查询需要做相关性以外的排序操作,都需要使用文件排序。
全文索引的一个常用技巧是缓存全文索引返回的主键值,这在分页显示的时候经常使用。当应用程序真的需要输出结果时,才通过主键值将所有需要的数据返回。这个查询就可以自由的使用其他索引、或者自由的关联其他表。
虽然只有MyISAM表支持全文索引。但是如果仍然希望使用InnoDB或其他引擎,可以将原表复制到一个备库,再将备库上的表修改成MyISAM并建上相应的全文索引。如果不希望在一个服务器上完成查询,还可以对表进行垂直拆分,将需要索引的列放到一个单独的MyISAM表中。
将需要索引的列额外的冗余在另外一个MyISAM表中也是一个方法。通常可以使用触发器来维护这个表的数据。
因为使用全文索引的时候,通常会返回大量结果并产生大量随机I/O,如果group by一起使用的话,还需要通过临时表或者文件排序进行分组,性能会非常非常糟糕。这类查询通常只是希望查询分组后的前几名结果,所以一个有效的优化方法是对结果进行抽样而不是精确计算。
4、全文索引的优化
全文索引的日常维护通常能够大大提升性能。“双b-tree”的特殊结构、在某些文档中比其他文档要包含多得多的关键字,这都使的全文索引比起普通索引有更多的碎片问题。所以需要经常使用optimize table来减少碎片。如果应用是i/o密集型的,那么定期的进行全文索引重建可以让性能提升很多。
如果希望全文索引能够高效的工作,还需要保证索引缓存足够大,从而保证所有的全文索引都能够缓存在内存中。通常,可以为全文索引设置单独的键缓存,保证不会被其他的缓存挤出内存。
提供一个好的停用词表也很重要。默认的停用词表对常用的英语来说可能还不错,但是如果其他语言或某些专业文档就不合适了。忽略一些太短的单词也可以提升全文索引的效率。索引单词的最小长度可以通过参数ft_min_word_len配置。修改该参数可以过滤更多的单词,让查询速度更快,但是也会降低精确度。
停用词表和允许最小词长都可以通过减少索引词语来提升全文索引的效率,但是同时也会降低搜索的精确度。这需要根据应用场景找到合适的平衡点。如果希望同时获得好的性能和搜索质量,那么需要自己定制这些参数。一个好的办法是通过日志系统来研究用户的搜索行为,看看一些异常的查询,包括没有结果返回的查询或者返回过多结果的用户查询。通过这些用户行为和搜索的内容来判断应该如何调整索引策略。
当向一个有全文索引的表中导入大量数据的时候,最好先通过disable keys来禁用全文索引,然后在导入结束后使用Enable keys来建立全文索引。因为全文索引的更新是一个消耗很大的操作,所以上面的细节会帮助你节省大量时间。另外,这样还顺便为全文索引做了一次碎片整理工作。
如果数据量特别大,需要对数据进行分区,然后将数据分不到不同的节点,在做并行的搜索。这是一个复杂的工作,最好通过一些外部搜索引擎来实现,如Lucene。
5.索引优化
1)注意事项
1)SELECT `sname` FROM `stu` WHERE `age`+10=30;-- 不会使用索引,因为所有索引列参与了计算
2)SELECT `sname` FROM `stu` WHERE LEFT(`date`,4) <1990; -- 不会使用索引,因为使用了函数运算,原理与上面相同
3)SELECT * FROM `houdunwang` WHERE `uname` LIKE'后盾%' -- 走索引
4)SELECT * FROM `houdunwang` WHERE `uname` LIKE "%后盾%" -- 不走索引
-- 正则表达式不使用索引,这应该很好理解,所以为什么在SQL中很难看到regexp关键字的原因
-- 字符串与数字比较不使用;
5)CREATE TABLE `a` (`a` char(10));
EXPLAIN SELECT * FROM `a` WHERE `a`="1" -- 走索引
EXPLAIN SELECT * FROM `a` WHERE `a`=1 -- 不走索引
6)select * from dept where dname='xxx' or loc='xx' or deptno=45
--如果条件中有or,即使其中有条件带索引也不会使用。换言之,就是要求使用的所有字段,都必须建立索引, 我们建议大家尽量避免使用or 关键字
-- 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
2)使用技巧
使用索引时,有一些技巧:
1.索引不会包含有NULL的列
只要列中包含有NULL值,都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此符合索引就是无效的。
2.使用短索引
对串列进行索引,如果可以就应该指定一个前缀长度。例如,如果有一个char(255)的列,如果在前10个或20个字符内,多数值是唯一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。
3.索引列排序
mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作,尽量不要包含多个列的排序,如果需要最好给这些列建复合索引。
4.like语句操作
一般情况下不鼓励使用like操作,如果非使用不可,注意正确的使用方式。like ‘%aaa%’不会使用索引,而like ‘aaa%’可以使用索引。
5.不要在列上进行运算
6.不使用NOT IN 、<>、!=操作,但<,<=,=,>,>=,BETWEEN,IN是可以用到索引的
7.索引要建立在经常进行select操作的字段上。
这是因为,如果这些列很少用到,那么有无索引并不能明显改变查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
8.索引要建立在值比较唯一的字段上。
9.对于那些定义为text、image和bit数据类型的列不应该增加索引。因为这些列的数据量要么相当大,要么取值很少。
10.在where和join中出现的列需要建立索引。
11.where的查询条件里有不等号(where column != …),mysql将无法使用索引。
12.如果where字句的查询条件里使用了函数(如:where DAY(column)=…),mysql将无法使用索引。
13.在join操作中(需要从多个数据表提取数据时),mysql只有在主键和外键的数据类型相同时才能使用索引,否则及时建立了索引也不会使用。
14.=和in可以乱序,如a=1 and b=2 and c=3建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮助优化成索引可以识别的形式。
15.尽量选择区分度高的列作为索引,区分度的公式是count(distinct col)/count(*),一般需要join的字段我们都要求是0.1以上,即平均1条扫描10条记录。
16.索引列不能参与计算,保持列干净,如from_unixtime(create_time)='2020-06-14'不能使用索引。这是因为B+树种存的都是数据表中的字段值,但进行索引时,需要把所有元素都应用函数才能比较,成本太大。
17.尽量扩展索引,不要新建索引,比如表中已经有a的索引,现在要加(a,b)的索引,只需要修改原来的索引即可。