1.普通索引:(index)最基本的索引,没有任何限制 目的:加快数据的查询速度
2.唯一索引:(unique) 与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。
3.主键索引(primary key) 它 是一种特殊的唯一索引,不允许有空值。
4.复合索引:index(a,b,c) 为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。
5.全文索引:fulltext 仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时耗空间。
第一类是myisam存储引擎使用的叫做b-tree结构,
第二类是innodb存储引擎使用的叫做聚簇结构(也是一种 b-tree)。 如下图:
注意:
1.myisam不需要回行处理
2.innodb不需要回行处理,直接可以获取数据,因为innodb的储存引擎是包含了数据和索引文件的,其主键索引包含了数据,(唯一索引及普通索是没有直接包含数据的)
1、索引列不能参与计算
有索引列参与计算的查询条件对索引不友好(甚至无法使用索引),如from_unixtime(create_time) = '2014-05-29'。
原因很简单,如何在节点中查找到对应key?如果线性扫描,则每次都需要重新计算,成本太高;如果二分查找,则需要针对from_unixtime方法确定大小关系。
因此,索引列不能参与计算。上述from_unixtime(create_time) = '2014-05-29'语句应该写成create_time = unix_timestamp('2014-05-29')。
2、最左前缀匹配
如有索引(a, b, c, d),查询条件a = 1 and b = 2 and c >3 and d = 4,则会在每个节点依次命中a、b、c,无法命中d。也就是最左前缀匹配原则。
3、冗余和重复索引
冗余索引是指在相同的列上按照相同的顺序创建的相同类型的索引,应当尽量避免这种索引,发现后立即删除。比如有一个索引(A,B),再创建索引(A)就是冗余索引。冗余索引经常发生在为表添加新索引时,比如有人新建了索引(A,B),但这个索引不是扩展已有的索引(A)
4、避免多个范围条件
select user.* from user where login_time >'2017-04-01' and age between 18 and 30
比如想查询某个时间段内登录过的用户:它有两个范围条件,login_time列和age列,MySQL可以使用login_time列的索引或者age列的索引,但无法同时使用它们 .
5、覆盖索引 (能扩展就不新建)
如果一个索引包含或者说覆盖所有需要查询的字段的值,那么就没有必要再回表查询,这就称为覆盖索引。覆盖索引是非常有用的工具,可以极大的提高性能,因为查询只需要扫描索引会带来许多好处:
1.索引条目远小于数据行大小,如果只读取索引,极大减少数据访问量2.索引是有按照列值顺序存储的,对于I/O密集型的范围查询要比随机从磁盘读取每一行数据的IO要少的多
6、选择区分度高的列作索引
如,用性别作索引,那么索引仅能将1000w行数据划分为两部分(如500w男,500w女),索引几乎无效。
区分度的公式是count(distinct ) / count(*),表示字段不重复的比例,比例越大区分度越好。唯一键的区分度是1,而一些状态、性别字段可能在大数据面前的区分度趋近于0。
7、删除长期未使用的索引
场景一(覆盖索引 5)
索引应该建在选择性高的字段上(键值唯一的记录数/总记录条数),选择性越高索引的效果越好、价值越大,唯一索引的选择性最高;
组合索引中字段的顺序,选择性越高的字段排在最前面;
where条件中包含两个选择性高的字段时,可以考虑分别创建索引,引擎会同时使用两个索引(在OR条件下,应该说必须分开建索引);
不要重复创建彼此有包含关系的索引,如index1(a,b,c) 、index2(a,b)、index3(a);
组合索引的字段不要过多,如果超过4个字段,一般需要考虑拆分成多个单列索引或更为简单的组合索引;
不要滥用索引。因为过多的索引不仅仅会增加物理存储的开销,对于插入、删除、更新 *** 作也会增加处理上的开销,而且会增加优化器在选择索引时的计算代价。
因此太多的索引与不充分、不正确的索引对性能都是毫无益处的。一言以蔽之,索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。
https://blog.csdn.net/weixin_43935927/article/details/109491334建立索引,要使用离散度(选择度)更高的字段。
我们先来看一个重要的属性列的 离散度,
count(distinct(column_name)) : count(*) -- 列的全部不同值个数:所有数据行行数
数据行数相同的情况下,分子越大,列的离散度就越高。简单来说,如果列的重复值越多,离散度就越低,重复值越少,离散度就越高。
当字段值比较长的时候,建立索引会消耗很多的空间,搜索起来也会很慢。我们可以通过截取字段的前面一部分内容建立索引,这个就叫前缀索引。
创建一张商户表,因为地址字段比较长,在地址字段上建立前缀索引
create table shop(address varchar(120) not null)
alter table shop add key(address(12)) // 截取12个字符作为前缀索引是最优的吗?
问题是,截取多少呢?截取得多了,达不到节省索引存储空间的目的,截取得少了,重复内容太多,字段的散列度(选择性)会降低。怎么计算不同的长度的选择性呢?
先看一下字段在全部数据中的选择度计算公式:
select count(distinct address) / count(*) from shop
select count(distinct left(address, n)) / count(*) as subn from shop
count(distinct left(address,n)) / count(*) 的结果是会随着 n 的变大而变大。举个例子,现在有两个address(东大街长兴小区,东大街福乐小区),那么 distinct(address,2) <distinct(address,3)
==>所以,截取的长度越长就会越接近字段在全部数据中的选择度
==>所以,我们要权衡索引大小和查询速度。
举个例子,通过不同长度去计算,与全表的选择性对比:
SELECT COUNT(DISTINCT(address))/COUNT(*) sub, -- 字段在全部数据中的选择度
COUNT(DISTINCT(LEFT(address,5)))/COUNT(*) sub5, -- 截取前5个字符的选择度
COUNT(DISTINCT(LEFT(address,7)))/COUNT(*) sub7,
COUNT(DISTINCT(LEFT(address,9)))/COUNT(*) sub9,
COUNT(DISTINCT(LEFT(address,10)))/COUNT(*) sub10, -- 截取前10个字符的选择度
COUNT(DISTINCT(LEFT(address,11)))/COUNT(*) sub11,
COUNT(DISTINCT(LEFT(address,12)))/COUNT(*) sub12,
COUNT(DISTINCT(LEFT(address,13)))/COUNT(*) sub13,
COUNT(DISTINCT(LEFT(address,15)))/COUNT(*) sub15
FROM shop
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| sub | sub5 | sub7 | sub9 | sub10 | sub11 | sub12 | sub13 | sub15 |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
| 0.9993 | 0.0225 | 0.4663 | 0.8618 | 0.9734 | 0.9914 | 0.9943 | 0.9943 | 0.9958 |
+--------+--------+--------+--------+--------+--------+--------+--------+--------+
可以看到在截取 11 个字段时 sub11(0.9993) 就已经很接近字段在全部数据中的选择度 sub(0.9958)了,而且长度也相较后面更短一些, 综合考虑比较合适。
ALTER TABLE shop ADD KEY (address(11))
1.索引的个数不要过多(浪费空间,更新变慢)
2.在用于 where 判断 order 排序和 join 的(on)字段上创建索引
3.区分度低的字段,例如性别,不要建索引(离散度太低,导致扫描行数过多)
4.更新频繁的值,不要作为主键或者索引(页分裂)
5.不建议用无序的值作为索引,例如身份z、UUID(在索引比较时需要转为ASCII,并且插入时可能造成页分裂)
6.若在多个字段都要创建索引的情况下,联合索引优于单值索引
7.联合索引把散列性高(区分度高)的值放在前面
mysql的索引类型及使用索引时的注意事项有:
一、普通索引。这是最基本的索引,它没有任何限制。它有以下几种创建方式:
1、创建索引
代码如下:
CREATE INDEX indexName ON mytable(username(length))
如果是CHAR,VARCHAR类型,length可以小于字段实际长度;如果是BLOB和TEXT类型,必须指定 length,下同。
2、修改表结构
代码如下:
ALTER mytable ADD INDEX [indexName] ON (username(length)) -- 创建表的时候直接指定
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) )
-- 删除索引的语法:
DROP INDEX [indexName] ON mytable
二、唯一索引。它与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式:
代码如下:
CREATE UNIQUE INDEX indexName ON mytable(username(length))
-- 修改表结构
ALTER mytable ADD UNIQUE [indexName] ON (username(length))
-- 创建表的时候直接指定
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) )
三、主键索引。它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引:
代码如下:
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, PRIMARY KEY(ID) )
当然也可以用 ALTER 命令。记住:一个表只能有一个主键。
四、组合索引。为了形象地对比单列索引和组合索引,为表添加多个字段:
代码如下:
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, city VARCHAR(50) NOT NULL, age INT NOT NULL )
为了进一步榨取MySQL的效率,就要考虑建立组合索引。就是将 name, city, age建到一个索引里:
代码如下:
ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age)[code]
建表时,usernname长度为 16,这里用 10。这是因为一般情况下名字的长度不会超过10,这样会加速索引查询速度,还会减少索引文件的大小,提高INSERT的更新速度。
如果分别在 usernname,city,age上建立单列索引,让该表有3个单列索引,查询时和上述的组合索引效率也会大不一样,远远低于我们的组合索引。虽然此时有了三个索引,但MySQL只能用到其中的那个它认为似乎是最有效率的单列索引。
建立这样的组合索引,其实是相当于分别建立了下面三组组合索引:usernname,city,age usernname,city usernname 为什么没有 city,age这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这三列的查询都会用到该组合索引,下面的几个SQL就会用到这个组合索引:
[code]
SELECT * FROM mytable WHREE username="admin" AND city="郑州" SELECT * FROM mytable WHREE username="admin"
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)