mysql 主键索引,联合索引,单列索引使用场景

mysql 主键索引,联合索引,单列索引使用场景,第1张

表button 

CREATE TABLE `button` (

  `id` bigint(20) NOT NULL AUTO_INCREMENT,  --主键索引

  `button_name` varchar(45) NOT NULL COMMENT '功能名称',

  `app_id` bigint(20) NOT NULL,

  `permission_id` bigint(20) DEFAULT NULL,  -- permission_id 和 app_id 联合索引。

  `api_id` bigint(20) NOT NULL, --api_id单独索引

  PRIMARY KEY (`id`),

  KEY `index_app_permission_lianhe` (`permission_id`,`app_id`) USING BTREE,

  KEY `index_api_id_dange` (`api_id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8

主键索引,单独索引,组合索引使用场景及优化

表button 有3个索引,分别是:id主键,联合索引(permission_id,app_id),api_id(单列索引)

button_name 无索引

查询where条件中:

主键索引:

1、主键索引与联合索引同时存在,使用主键索引

2、主键索引与单个索引同时存在,使用主键索引

结论:只要主键索引在,使用主键索引。

联合索引 :

1、联合索引与单列索引列 同时存在,使用单列索引

2、联合索引中列顺序颠倒无影响。

3、联合索引实行最左侧原则,即:单独查询条件中只有permission_id可以使用联合索引,单独查询条件中只有app_id不实用联合索引。

4、如果查询条件中只有app_id,但是select 条件中有 permission_id,则也使用联合索引。

5、select id,app_id from button where app_id=1001使用联合索引

6、explain select id,app_id,button_name from button where app_id=1001不使用联合索引

结论:索引优先级:主键索引,单列索引,组合索引

    联合索引中遵从最左侧列原则。

    当查询条件和返回结果中仅仅包含联合索引中索引项,也使用联合索引。如第4条。

    当查询条件中出现联合索引中非最左侧索引列,返回结果中含义联合索引中的列或者主键则也使用联合索引。

单个索引:

1、查询条件中有单列索引,则使用,无不使用。

事例:

索引就是为特定的mysql字段进行一些特定的算法排序,比如二叉树的算法和哈希算法,哈希算法是通过建立特征值,然后根据特征值来快速查找。

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个字段,一般需要考虑拆分成多个单列索引或更为简单的组合索引;

不要滥用索引。因为过多的索引不仅仅会增加物理存储的开销,对于插入、删除、更新 *** 作也会增加处理上的开销,而且会增加优化器在选择索引时的计算代价。

因此太多的索引与不充分、不正确的索引对性能都是毫无益处的。一言以蔽之,索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。

一、普通索引

这是最基本的索引,它没有任何限制。有以下几种创建方式:

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的效率,就要考虑建立组合索引。

二:使用索引的注意事项

使用索引时,有以下一些技巧和注意事项:

1.索引不会包含有NULL值的列

只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。

2.使用短索引

对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O *** 作。

3.索引列排序

MySQL查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序 *** 作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

4.like语句 *** 作

一般情况下不鼓励使用like *** 作,如果非使用不可,如何使用也是一个问题。like “%aaa%” 不会使用索引而like “aaa%”可以使用索引。

5.不要在列上进行运算

select * from users where YEAR(adddate)<2007

将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成:

select * from users where adddate<‘2007-01-01'

6.不使用NOT IN和<> *** 作。

三:sql优化原则

常见的简化规则如下:

1.不要有超过5个以上的表连接(JOIN)

2.考虑使用临时表或表变量存放中间结果。

3.少用子查询

4.视图嵌套不要过深,一般视图嵌套不要超过2个为宜。

5.连接的表越多,其编译的时间和连接的开销也越大,性能越不好控制。

6.最好是把连接拆开成较小的几个部分逐个顺序执行。

7.优先执行那些能够大量减少结果的连接。

8.拆分的好处不仅仅是减少SQL Server优化的时间,更使得SQL语句能够以你可以预测的方式和顺序执行。

如果一定需要连接很多表才能得到数据,那么很可能意味着设计上的缺陷。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/8547680.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-17
下一篇2023-04-17

发表评论

登录后才能评论

评论列表(0条)

    保存