深入探索MySQL索引策略

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
日志服务 SLS,月写入数据量 50GB 1个月
简介: 本文旨在深入探讨MySQL(8.0.26)数据库中索引的设计与优化方法。

引言


有一张表user(无索引):


假如要执行的sql语句为:select * from user where age = 45;


需要从第一行开始,一直扫描到最后一行,称为全表扫描,性能很低;有没有提升性能,减少搜索时间的方法呢?


索引介绍


1. B+tree 结构介绍


在Mysql中,索引就是帮助搜索数据的一种有序的数据结构,它以某种方式引用(指向)数据。


Mysql中的索引是在存储引擎层实现的,因此不同的存储引擎又有着不同的索引结构,主要包含以下几种:


image.png

简单介绍下经典的B+tree 的结构:

image.png

可以看出:


  • 所有的数据都会出现在叶子节点,叶子节点形成一个单向链表;
  • 非叶子节点仅仅索引数据,具体的数据都是在叶子节点存放的;


Mysql索引数据结构对经典的B+tree进行了优化,在原有B+tree的基础上,增加了一个指向相邻叶子节点的链表指针,形成了带有顺序指针的B+tree,提高区间访问的性能,利于排序;

image.png


2. 索引分类


在mysql数据库,将索引的具体类型主要分为以下几类:

image.png

在Innodb 存储引擎中,根据索引的存储形式,分为两种:

image.png

执行一条查询语句,我们分析一下具体的查找过程:

image.png

具体过程如下:


1. 因为是根据name字段查询,所以先根据 name='Arm' 到name字段的二级索引中进行匹配查找。但是在二级索引中只能查找到 Arm 对应的主键值 10;


2. 由于查询返回的数据是*,所以此时,还需要根据主键值10,到聚集索引中查找10对应的记录,最终找到10对应的行row;


3. 最终拿到这一行的数据,直接返回即可。


3. 索引语法


创建索引:


create  [unique|fulltext]  index 索引名 on 表名 (字段名1,字段名2,……);


查看索引:


show index from 表名;


删除索引:


drop index 索引名 on 表名;


SQL性能分析


1. sql执行频率


Mysql客户端链接成功后,通过以下命令可以查看当前数据库的  insert/update/delete/select  的访问频次:


show [session|global]  status like ‘com_____’;

session: 查看当前会话;

global: 查看全局数据;

com insert: 插入次数;

com select: 查询次数;

com delete: 删除次数;

com updat: 更新次数;

image.png

通过查看当前数据库是以查询为主,还是以增删改为主,从而为数据库优化提供参考依据,如果以增删改为主,可以考虑不对其进行索引的优化;如果以查询为主,就要考虑对数据库的索引进行优化。


2. 慢查询日志


慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位秒,默认10秒)的所有sql日志:


开启慢查询日志前,需要在mysql的配置文件中(/etc/my.cnf)配置如下信息:


# 1. 开启mysql慢日志查询开关:slow_query_log = 1#

2. 设置慢日志的时间,假设为2秒,超过2秒就会被视为慢查询,记录慢查询日志:long_query_time=2#

3.  配置完毕后,重新启动mysql服务器进行测试:systemctl restarmysqld#

4. 查看慢查询日志的系统变量,是否打开:show variables like “slow_query_log”;#

5.  查看慢日志文件中(/var/lib/mysql/localhost-slow.log)记录的信息:

Tail -f localhost-slow.log


最终发现,在慢查询日志中,只会记录执行时间超过我们预设时间(2秒)的sql,执行较快的sql不会被记录。

image.png 


3. Profile 详情


show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了。



#1. 通过 have_profiling 参数,可以看到mysql是否支持profile 操作:select @@have_profiling;#

2.  通过set 语句在session/global 级别开启profiling:

set profiling =1;


开关打开后,后续执行的sql语句都会被mysql记录,并记录执行时间消耗到哪儿去了。比如执行以下几条sql语句:



select * from tb_user;

select * from tb_user where id = 1;

select * from tb_user where name = '白起';

select count(*) from tb_sku;


#3. 查看每一条sql的耗时基本情况:

show profiles;

image.png

#4. 查看指定的字段的sql 语句各个阶段的耗时情况:

show profile for query Query_ID;

image.png

#5. 查看指定字段的sql语句cpu 的使用情况:

show profile cpu for query Query_ID;


4. explain 详情


EXPLAIN 或者 DESC命令获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中,表如何连接和连接的顺序。



语法 :直接在 select 语句之前加上关键字 explain/desc;


# explain select 字段 from 表名 where 条件;

image.png

索引使用


1. 索引失效的情况


1.1 最左前缀法则

如果存在联合索引,要遵守最左前缀法则。即查询从索引的最左列开始,并且不跳过索引中的列,如果跳跃其中某一列,索引将会部分失效(后面的字段索引失效)。


假设在 tb_user 表中


联合索引,涉及三个字段,顺序为:profession(索引长度为47), age(索引长度为2), status(索引长度为5)。


a)explain select * from tb_user where profession = '软件工程 ' and age = 31 and status='0';

image.png

b)explain select * from tb_user where profession = '软件工程 ' and age = 31 ;

image.png

c)explain select * from tb_user where profession = '软件工程‘;

image.png

以上的这三组测试中,我们发现只要联合索引最左边的字段profession存在,索引就会生效;

a)explain select * from tb_user where age = 31 and status='0';

image.png

b)explain select * from tb_user where status='0';

image.png

以上的这两组测试中,我们发现只要联合索引最左边的字段  profession不存在,索引并未生效;

explain select * from tb_user where profession = '软件工程 ' and status='0';

image.png 

上述的一条SQL查询时,联合索引最左边的列profession字段是存在的,索引满足最左前缀法则的基本条件。但是查询时,跳过了age这个列,所以后面的列索引是不会使用的,也就是索引部分生效,所以索引的长度为47;



explain select * from tb_user where age = 31 and status='0'  and profession = '软件工程’;

image.png

可以看到,索引长度54,完全满足最左前缀法则,联合索引生效。


⚠️ 最左前缀法则中是指查询时,联合索引的最左边的字段(即第一个字段)必须存在,与编写sql时,条件编写的先后顺序无关。


1.2 范围查询

联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效。



explain select * from tb_user where profession = '软件工程 ' and age >31 and status='0';

image.png

上述可以看到,当范围查询使用>或<时,查询走联合索引了,但是索引长度为49,说明范围查询右边的status字段没有走索引;



explain select * from tb_user where profession = '软件工程 ' and age >= 31 and status='0';

image.png

上述可以看到,当范围查询使用>=或<=时,查询走联合索引了,但是索引长度为54,说明所有字段都是走索引的;


⚠️ 所以,在业务允许的情况下,尽可能使用类似于>=或<=这类的范围查询,避免使用>或<。


1.3 索引列运算


在索引列上进行运算操作,索引将失效。


假设在 tb_user 表中,存在单列索引:phone


explain select * from tb_user where phone = '17799990015';


image.png

上述看到,当根据phone字段进行等值匹配查询时,索引生效。


explain select * from tb_user where substring(phone,10,2)=’15’;

image.png

上述看到,当根据phone字段进行函数运算操作之后,索引失效。


1.4 字符串不加引号


字符串类型字段使用时,不加引号,索引将失效。


explain select * from tb_user where profession = '软件工程 ' and age = 31 and status = '0 ';


explain select * from tb_user where profession = '软件工程 ' and age = 31 and status = 0;

image.png

explain select * from tb_user where phone = ‘1779990015’;

explain select * from tb_user where phone = 1779990015;

image.png

上述看到,字符串不加单引号时,对于查询结果没有影响,但是由于数据库存在隐式类型转换,索引将失效。


1.5 模糊查询


尾部模糊匹配,索引不会失效;头部模糊匹配,索引失效。


explain select * from tb_user where profession like ‘软件%’

;explain select * from tb_user where profession like ‘%工程’;

explain select * from tb_user where profession like ‘%工%’;

image.png

上述看到,在like模糊查询中,在关键字后面加%,索引可以生效;在关键字前面加%,索引将会失效。

1.6 or 连接条件


or 前的条件中的列有索引,后面的列中没有索引,则涉及的所有索引都不会被用到。



步骤一:存在单列索引:phone


explain select * from tb_user where id=10 or age=23;

explain select * from tb_user where phone=’1779990017’ or age=23;

image.png

上述看到,由于age 没有索引,所以即使id, phone有索引,索引也会失效。


步骤二:对age字段 建立索引


create index idx_user on tb_user(age);

 image.png

步骤三:再次执行上述的sql语句

image.png

可以看到,当or 连接的条件,左右两侧字段都有索引时,索引才会生效。

1.7 数据分布影响


Mysql评估使用索引会比全表更慢,则不会使用索引。



explain * from tb_user where phone >= ‘1779999005’;

explain * from tb_user where phone >= ‘1779999015’;

image.png

上述看到,相同的sql语句,传入字段值不同时,所执行的计划也不同,这是因为:


mysql在查询时,会评估使用索引的效率与走全表扫描的效率,哪种效率高使用哪种。因为索引是用来索引少量数据的,如果通过索引查询返回大批量的数据,则不如走全表扫描来的快,此时索引就会失效。


再来看下,is null & is not null 的操作是否会走索引:


步骤一:


explain select * from tb_user where profession is null;

explain select * from tb_user where profession is not null;

image.png 

步骤二:把profession 字段全部更新为null:


update tb_user set profession = null;

image.png

步骤三:再次执行上述语句

image.png

最终看到,相同的sql语句,先后执行两次,查询的计划不同。


这是因为和数据库的数据分布有关系,查询是mysql会评估,走索引还是全表扫描,如果全表扫描块,则放弃索引走全表扫描,因此,is null & is not null 是否走索引,得具体情况具体分析,不是固定的。



2. SQL提示


字段profession 存在联合索引(idx_user_pro_sta) & 单列索引(idx_user_pro)。


explain select * from tb_user where profession=’软件工程’;

image.png

可以看出,mysql 最终选择了idx_user_pro_age_sta 联合索引,这是mysql自动选择的结果。


那么,我们在查询时,可以使用mysql的sql提示,加入一些人为的提示来达到优化操作的目的:


  • user index:建议mysql使用哪一个索引完成此次查询(仅仅是建议,mysql内部还会再次进行评估);
  • ignore index:忽略指定的索引;
  • force index:强制使用索引。


演示:


1)explain select * from tb_user use index(idx_user_pro) where profession=’软件工程’;

image.png

2)explain select * from tb_user ignore index(idx_user_pro) where profession=’软件工程’;

image.png

3)explain select * from tb_user force index(idx_user_pro) where profession=’软件工程’;

image.png


3. 覆盖索引


覆盖索引是指查询使用了索引且返回需要的列,在该索引列中已经全部能够找到。


在查询时,尽量使用覆盖索引,减少select *。


表中存在联合索引 idx_user_pro_age_sta (关联了三个字段profession, age, status),该索引也是一个二级索引,该叶子节点下面的是这一行的主键id。当查询返回的数据在id, profession, age, status 中,则直接走二级索引返回数据,如果查询字段超出这个范围,就需要拿到主键id, 再去扫描聚集索引获取额外的数据,这个过程就是回表。


当我们一直使用 select * 查询返回所有字段值,很容易造成回表查询(除非根据主键查询,此时只会扫描聚集索引)。


演示如下:


  • explain select id, profession, from tb_user where profession=’软件工程’ and age=31 and status=’0’;
  • explain select id, profession, age, status from tb_user where profession=’软件工程’ and age=31 and status=’0’;
  • explain select id, profession, age, status, name from tb_user where profession=’软件工程’ and age=31 and status=’0’;
  • explain select * from tb_user where profession=’软件工程’ and age=31 and status=’0’;

image.png

为了让大家更清楚地理解,什么是覆盖索引和回表查询,我们一起来看下一组sql的执行过程:


A. 表结构及索引示意图:


id是主键,是一个聚集索引。name字段建立了普通索引,是一个二级索引(辅助索引)。

image.png


B. 执行SQL:  select * from tb_user where id = 2;


根据id查询,直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。

image.png

C. 执行SQL:  selet id,name from tb_user where name = 'Arm';


虽然是根据name字段查询,查询二级索引,但是由于查询返回在字段为 id,name,在name的二级索 引中,这两个值都是可以直接获取到的,因为覆盖索引,所以不需要回表查询,性能高。

image.png

D. 执行SQL: selet id,name,gender from tb_user where name = 'Arm';


由于在name的二级索引中,不包含gender,所以,需要两次索引扫描,也就是需要回表查询,性能相对较差一点。

image.png

🤔思考一下:一张表四个字段(id, username, password, status),如何对sql优化最优?


select id, username, password from tb_user where username=’itcast’;


答案:针对username, password 建立联合索引,避免回表查询。


4. 前缀索引


当字段类型为字符串(varchar, text, longtext等)时,有时候需要索引很长的字符串,导致索引较大,查询是浪费大量的磁盘IO,影响查询效率。此时可以只对字符串的一部分前缀建立索引,节约索引空间,提高索引效率。


1)语法:create index idx_xxx on 表名(column(n));


create index idx_email on tb_user(email(5));      # 为表tb_user的 email 字段建立长度为5的前缀索引。

image.png

2)前缀长度


可以根据索引的选择性来决定,选择性=不重复的索引值(基数)/数据表的记录总数。


索引选择性越高则查询效率最高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的。


select count(distinct email)/count(*) from tb_user;

select count(distinct substring(email, 1, 5)/count(*) from tb_user;



3)前缀索引的查询流程

image.png


5. 单列索引&联合索引


单列索引:一个索引只包含单个列


联合索引:一个索引包含了多个列


当and 连接的两个字段 phone、name上都有单列索引,mysql最终只会选择一个索引,也就是说只能走一个字段的索引,此时会进行回表查询的。

image.png

此时,我们创建一个phone和name字段的联合索引。


create unique index_user_phone_name on tb_user(phone, name);


查询以下执行计划:

image.png

此时查询时,走了联合索引,在联合索引中包含phone, name的信息,在叶子节点下挂的是对应的主键id,所以查询不需要回表查询。


⚠️ 所以在业务场景中,若存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,而非单列索引。



查询使用联合索引时,具体的结构示意图如下:

image.png


6. 索引设计原则

1)针对数据量较大,且查询比较繁琐的表建立索引;

2)针对于常作为查询条件(where),排序(order by),分组(group by)操作的字段,建立索引;

3)尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高;

4)如果是字符串类型的字段,字段的长度过长,可以针对字段的特点,建立前缀索引;

5)尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率;

6)要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率;

7)如果索引列不能存储null值,在创建表时使用not null约束它。当优化器知道每列是否包含null值时,它可以更好地确定哪个索引最有效地用于查询。


SQL优化


1. 主键优化


1.1 主键顺序插入

1. 从磁盘中申请页, 主键顺序插入;

image.png

2. 第一个页没有满,继续往第一页插入;

image.png

3. 当第一个也写满之后,再写入第二个页,页与页之间会通过指针连接;

image.png

4. 当第二页写满了,再往第三页写入;

image.png

1.2 主键乱序插入

1.2.1 页分裂

1.假如1#,2#页都已经写满了,存放了如图所示的数据;

image.png

2.此时再插入id为50的记录,我们来看看会发生什么现象 会再次开启一个页,写入新的页中吗?

image.png

不会。因为,索引结构的叶子节点是有顺序的。按照顺序,应该存储在47之后。

image.png

3.但是47所在的1#页,已经写满了,存储不了50对应的数据了。 那么此时会开辟一个新的页 3#。

image.png

4.但是并不会直接将50存入3#页,而是会将1#页后一半的数据,移动到3#页,然后在3#页,插入50。

image.png 

5.移动数据,并插入id为50的数据之后,那么此时,这三个页之间的数据顺序是有问题的。 1#的下一个页,应该是3#, 3#的下一个页是2#。 所以,此时,需要重新设置链表指针。 这种现象,称之为 "页分裂",是比较耗费性能的操作。

image.png

1.2.2 页合并

1.目前表中已有数据的索引结构(叶子节点)如下:

image.png

2.当删除一行记录时,实际上记录并没有被物理删除,只是记录被标记(flaged)为删除并且它的空间变得允许被其他记录声明使用。

image.png 

3.继续删除2#数据,当页中删除的记录达到 MERGE_THRESHOLD(默认为页的50%),InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。

image.png

这个里面所发生的合并页的这个现象,就称之为 "页合并"。

1.2.3 索引设计原则

  • 满足业务需求的情况下,尽量降低主键的长度;
  • 插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键;
  • 尽量不要使用UUID做主键或者是其他自然主键,如身份证号;
  • 业务操作时,避免对主键的修改。


2.  order by优化


MySQL的排序,有两种方式:

image.png

对于以上的两种排序方式,Using index的性能高,而Using filesort的性能低,我们在优化排序操作时,尽量要优化为 Using index。


接下来,我们来做一个测试:  


A. tb_user表中所建立的部分索引删除掉

image.png

B. 执行排序SQL

explain select id,age,phone from tb_user order by age ;

image.png

explain select id,age,phone from tb_user order by age, phone ;

image.png

由于 age, phone 都没有索引,所以此时再排序时,出现Using filesort,排序性能较低。


C. 创建索引


create index idx_user_age_phone_aa on tb_user(age, phone);


D. 创建索引后,根据age, phone进行升序排序


explain select id,age,phone from tb_user order by age;

image.png

explain select id,age,phone from tb_user order by age , phone;

image.png

建立索引之后,再次进行排序查询,就由原来的Using filesort, 变为了 Using index,性能 就是比较高的了。


E. 创建索引后,根据age, phone进行降序排序


explain select id,age,phone from tb_user order by age desc , phone desc ;

image.png

也出现 Using index, 但是此时Extra中出现了 Backward index scan,这个代表反向扫描索引。因为在Mysql中我们创建的索引,默认索引的叶子节点是从小到大排序的,而此时我们查询排序时,是从大到小,所以,在扫描时,就是反向扫描,就会出现 Backward index scan。在 MySQL8版本中,支持降序索引,我们也可以创建降序索引。


F. 根据phone,age进行升序排序,phone在前,age在后


explain select id,age,phone from tb_user order by phone , age;

image.png

排序时,也需要满足最左前缀法则,否则也会出现 filesort。因为在创建索引的时候, age是第一个字段,phone是第二个字段,所以排序时,也就该按照这个顺序来,否则就会出现 Using filesort。



G. 根据age, phone进行降序一个升序,一个降序


explain select id,age,phone from tb_user order by age asc, phone desc ;

image.png

因为创建索引时,未指定顺序,所以默认都是按照升序排序的,

image.png

而查询时,一个升序,一个降序,此时就会出现Using filesort。为了解决上述的问题,我们可以创建一个索引,这个联合索引中 age 升序排序,phone 倒序排序。



H. 创建联合索引(age 升序排序,phone 倒序排序)


create index idx_user_age_phone_ad on tb_user(age asc ,phone desc);

image.png

I. 然后再次执行如下SQL


explain select id,age,phone from tb_user order by age asc , phone desc ;

image.png

升序/降序联合索引结构图示:

image.png

由上述的测试,我们得出order by优化原则:


1)根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则;2)尽量使用覆盖索引;3)多字段排序, 一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC);

4)如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小sort_buffer_size(默认256k)。


3. group by优化


分组操作,我们主要来看看索引对于分组操作的影响。


步骤一:在没有索引的情况下,执行如下SQL,查询执行计划:


explain select profession , count(*) from tb_user group by profession ;

image.png

步骤二:针对 profession ,age,status 创建一个联合索引。


create index idx_user_pro_age_sta on tb_user(profession , age , status);


步骤三:再次执行前面相同的SQL查看执行计划。


explain select profession , count(*) from tb_user group by profession ;

image.png

步骤四:执行如下的分组查询SQL,查看执行计划:


explain select profession , count(*) from tb_user group by profession, age ;

explain select profession , count(*) from tb_user group by age ;

image.png

我们发现,如果仅仅根据age分组,就会出现 Using temporary ;而如果是根据 profession,age两个字段同时分组,则不会出现Using temporary。原因是对于分组操作, 在联合索引中,也是符合最左前缀法则的。



⚠️ 所以,在分组操作中,我们需要通过以下两点进行优化,以提升性能:


1)在分组操作时,可以通过索引来提高效率;

2)分组操作时,索引的使用也是满足最左前缀法则的。


4. limit优化


在数据量比较大时,如果进行limit分页查询,在查询时,越往后,分页查询效率越低。



我们一起来看看执行limit分页查询耗时对比:

image.png

通过测试我们会看到,越往后,分页查询效率越低,这就是分页查询的问题所在:


因为,当在进行分页查询时,如果执行 limit 2000000,10 ,此时需要MySQL排序前2000010 记录,仅仅返回 2000000 - 2000010 的记录,其他记录丢弃,查询排序的代价非常大 。


优化思路: 一般分页查询时,通过创建覆盖索引能够比较好地提高性能,可以通过覆盖索引加子查询形式进行优化。


explain select * from tb_sku t , (select id from tb_sku order by id limit 2000000,10) a where t.id = a.id;


5. count优化

5.1 概述

在之前的测试中,我们发现,如果数据量很大,在执行count操作时,是非常耗时的。InnoDB 引擎中,它执行 count(*) 的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数。


如果说要大幅度提升InnoDB表的count效率,主要的优化思路: 自己计数(可以借助于redis这样的数据库进行,但是如果是带条件的count又比较麻烦了)。

5.2 count用法

count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加,最后返回累计值。

用法:count(*)、count(主键)、count(字段)、count(数字)

image.png

按照效率排序的话,count(字段) < count(主键 id) < count(1) ≈ count(*),所以尽量使用count(*)。


6. update优化


我们主要需要注意一下update语句执行时的注意事项。


update course set name = 'javaEE' where id = 1 ;


当我们在执行删除的SQL语句时,会锁定id为1这一行的数据,然后事务提交之后,行锁释放。



当我们开启多个事务,再执行如下SQL时:


update course set name = 'SpringBoot' where name = 'PHP' ;


我们发现行锁升级为了表锁。导致该update语句的性能大大降低。


Innodb的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效,否则会从行锁升级成表锁。


参考文档:

https://blog.csdn.net/weixin_42802447/article/details/124267211

https://blog.csdn.net/kybabcde/article/details/128680998




来源  |  阿里云开发者公众号
作者  |  
木佳

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
5天前
|
缓存 关系型数据库 MySQL
MySQL慢查询优化策略
MySQL慢查询优化是一个复杂的过程,需要根据具体的应用场景和数据特点进行。以上策略是提升数据库查询性能的有效途径,但最关键的是对系统进行持续的监控和分析,及时发现并解决性能瓶颈。通过实践这些策略,你可以显著提高MySQL数据库的性能,为用户提供更快的响应时间和更好的体验。
31 10
|
9天前
|
存储 关系型数据库 MySQL
MySQL基础:索引
MySQL中的索引是一种数据结构,能大幅提升数据库查询效率和减少I/O成本,类似于书的目录帮助快速定位内容。其优势包括提高检索效率和降低排序成本,但会占用空间并影响更新表的效率。鉴于查询远多于更新,索引仍被推荐使用。索引分为多种类型,如B+树和哈希索引,其中B+树因其较低的高度和稳定的查询开销成为常用选择。创建和删除索引需谨慎,以免影响性能。
38 4
MySQL基础:索引
|
24天前
|
缓存 关系型数据库 MySQL
在Linux中,如何优化MySQL性能,包括索引优化和查询分析?
在Linux中,如何优化MySQL性能,包括索引优化和查询分析?
|
25天前
|
SQL 关系型数据库 MySQL
MySQL索引你用对了吗?
本文从遇到的问题出发,分析了tddl优化器、MySQL索引、分表拆分键的选择相关知识。
|
26天前
|
存储 关系型数据库 MySQL
MySQL bit类型增加索引后查询结果不正确案例浅析
【8月更文挑战第17天】在MySQL中,`BIT`类型字段在添加索引后可能出现查询结果异常。表现为查询结果与预期不符,如返回错误记录或遗漏部分数据。原因包括索引使用不当、数据存储及比较问题,以及索引创建时未充分考虑`BIT`特性。解决方法涉及正确运用索引、理解`BIT`的存储和比较机制,以及合理创建索引以覆盖各种查询条件。通过`EXPLAIN`分析执行计划可帮助诊断和优化查询。
|
29天前
|
SQL 存储 关系型数据库
mysql加索引真的会锁表吗?揭秘背后的技术细节与规避策略
【8月更文挑战第16天】在数据库管理中,添加索引能大幅提升查询效率。MySQL执行此操作时的锁定行为常引起关注。文章详细解析MySQL中索引添加时的锁定机制及其原理。不同存储引擎及SQL语句影响锁定策略:MyISAM需全表锁定;InnoDB提供更灵活选项,如使用`ALTER TABLE... LOCK=NONE`可在加索引时允许读写访问,尽管可能延长索引构建时间。自MySQL 5.6起,在线DDL技术可进一步减少锁定时间,通过`ALGORITHM=INPLACE`和`LOCK=NONE`实现近乎无锁的表结构变更。合理配置这些选项有助于最小化对业务的影响并保持数据库高效运行。
89 4
|
29天前
|
SQL JavaScript 关系型数据库
Mysql索引不当引发死锁问题
本文通过真实案例解析了MySQL在高并发环境下出现死锁的问题。数据库表`t_award`包含多个索引,但在执行特定SQL语句时遭遇索引失效,导致更新操作变慢并引发死锁。分析发现,联合索引`(pool_id, identifier, status, is_redeemed)`因`identifier`允许为空值而导致索引部分失效。此外,`pool_id`上的普通索引产生的间隙锁在高并发下加剧了死锁风险。为解决此问题,文中提出了调整索引顺序至`(pool_id, status, is_redeemed, identifier)`等方案来优化索引使用,进而减轻死锁现象。
|
14天前
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
81 0
|
22天前
|
SQL 算法 关系型数据库
MySQL索引看这篇就行
MySQL索引看这篇就行
24 0
|
23天前
|
SQL 关系型数据库 MySQL
【揭秘】MySQL binlog日志与GTID:如何让数据库备份恢复变得轻松简单?
【8月更文挑战第22天】MySQL的binlog日志记录数据变更,用于恢复、复制和点恢复;GTID为每笔事务分配唯一ID,简化复制和恢复流程。开启binlog和GTID后,可通过`mysqldump`进行逻辑备份,包含binlog位置信息,或用`xtrabackup`做物理备份。恢复时,使用`mysql`命令执行备份文件,或通过`innobackupex`恢复物理备份。GTID模式下的主从复制配置更简便。
107 2