第10章 索引优化与查询优化【2.索引及调优篇】【MySQL高级】3

本文涉及的产品
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDSClaw,2核4GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
简介: 第10章 索引优化与查询优化【2.索引及调优篇】【MySQL高级】3

5.4 filesort算法:双路排序和单路排序

排序的字段若如果不在索引列上,则filesort会有两种算法:双路排序单路排序

双路排序 (慢)
MySQL 4.1之前是使用双路排序 ,字面意思就是两次扫描磁盘,最终得到数据, 读取行指针和order by列对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出

从磁盘取排序字段,在buffer进行排序,再从磁盘取其他字段

取一批数据,要对磁盘进行两次扫描,众所周知,IO是很耗时的,所以在mysql4.1之后,出现了第二种改进的算法,就是单路排序

单路排序 (快)

从磁盘读取查询需要的 所有列 ,按照order by列在buffer对它们进行排序,然后扫描排序后的列表进行输出, 它的效率更快一些,避免了第二次读取数据。并且把随机IO变成了顺序IO,但是它会使用更多的空间, 因为它把每一行都保存在内存中了。
结论及引申出的问题

  • 由于单路是后出的,总体而言好过双路
  • 但是用单路有问题
  • 在sort_buffer中,单路比多路要多占用很多空间,因为单路是把所有字段都取出,所以有可能取出的数据的总大小超出了sort_buffer的容量,导致每次只能取sort_buffer容量大小的数据,进行排序(创建tmp文件,多路合并),排完再取sort_buffer容量大小,再排…从而多次I/O。

单路本来想省一次l/o操作,反而导致了大量的I/O操作,反而得不偿失。

order by 优化:

  • 根据排序字段建立合适的索引,多字段排序时,也遵循最左前缀法则
  • 尽量使用覆盖索引
    多字段排序,一个升序一个降序,此时需要注意联合索引在创建时的规则(ASC/DESC)
  • 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小 sort_buffer_size(默认256k)

优化策略

1.尝试提高 sort_buffer_size

  • 不管用哪种算法。提高这个参数都会提高效率,要根据系统的能力去提高,因为这个参数是针对每个进程(connection)的1M-8M之间调整。MySQL5.7,InnoDB存储引擎默认值是1048576字节,1MB,
SHOW VARIABLES LIKE '%sort_buffer_size%';
/*
+-------------------------+---------+
| Variable_name           | Value   |
+-------------------------+---------+
| innodb_sort_buffer_size | 1048576 |
| myisam_sort_buffer_size | 8388608 |
| sort_buffer_size        | 262144  |
+-------------------------+---------+
*/

2.尝试提高 max_length_for_sort_data

  • 提高这个参数,会增加用改进算法的概率。
SHOW VARIABLES LIKE '%max_length_for_sort_data%';#默认1024字节
/*
SHOW VARIABLES LIKE '%max_length_for_sort_data%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| max_length_for_sort_data | 4096  |
+--------------------------+-------+
*/
  • 但是如果设的太高,数据总容量超出sort_buffer_size的概率就增大,明显症状是高的磁盘I/O活动和低的处理器使用率。如果需要返回的列的总长度大于max_length_for_sort_data,使用双路算法,否则使用单路算法。1024-8192字节之间调整
    3.Order by 时select * 是一个大忌。最好只Query需要的字段
    当Query的字段大小总和小于max_length_for_sort_data,而且排序字段不是TEXT|BLOB类型时,会用改进后的算法―-单路排序,否则用老算法――多路排序

两种算法的数据都有可能超出sort_buffer_size的容量,超出之后,会创建tmp文件进行合并排序,导致多次I/O,但是用单路排序算法的风险会更大一些,所以要提高sort_buffer_size。

6.GROUP BY优化

  • group by 使用索引的原则几乎跟order by一致 ,group by 即使没有过滤条件用到索引,也可以直接使用索引。
  • group by 先排序再分组,遵照索引建的最佳左前缀法则
  • 当无法使用索引列,增大 max_length_for_sort_data 和 sort_buffer_size 参数的设置
  • where效率高于having,能写在where限定的条件就不要写在having中了
  • 减少使用order by,和业务沟通能不排序就不排序,或将排序放到程序端去做。Order by、group by、distinct这些语句较为耗费CPU,数据库的CPU资源是极其宝贵的。
  • 包含了order by、group by、distinct这些查询的语句,where条件过滤出来的结果集请保持在1000行以内,否则SQL会很慢

7.分页查询优化(limit优化)

一般分页查询时,通过创建覆盖索引能够比较好地提高性能。一个常见又非常头疼的问题就是limit 2000000,10,此时需要MySQL排序前2000010记录,仅仅返回2000000-2000010的记录,其他记录丢弃,查询排序的代价非常大。

在大数据量的分页查询时,limit后的起始位置越靠后,耗时越长

EXPLAIN select * from student limit 2000000,10;
/*
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------+
|  1 | SIMPLE      | student | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 498858 |   100.00 | NULL  |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------+
*/

优化思路一

在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容。

EXPLAIN SELECT * FROM student t,(SELECT id FROM student ORDER BY id LIMIT 2000000,10) a WHERE t.id = a.id;
/*
+----+-------------+------------+------------+--------+---------------+---------+---------+------+--------+----------+-------------+
| id | select_type | table      | partitions | type   | possible_keys | key     | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+------------+------------+--------+---------------+---------+---------+------+--------+----------+-------------+
|  1 | PRIMARY     | <derived2> | NULL       | ALL    | NULL          | NULL    | NULL    | NULL | 498858 |   100.00 | NULL        |
|  1 | PRIMARY     | t          | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | a.id |      1 |   100.00 | NULL        |
|  2 | DERIVED     | student    | NULL       | index  | NULL          | PRIMARY | 4       | NULL | 498858 |   100.00 | Using index |
+----+-------------+------------+------------+--------+---------------+---------+---------+------+--------+----------+-------------+
*/

优化思路二

该方案适用于主键自增的表,可以把Limit查询转换成某个位置的查询

EXPLAIN SELECT * FROM student WHERE id > 2000000 LIMIT 10;
/*
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table   | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | student | NULL       | range | PRIMARY       | PRIMARY | 4       | NULL |    1 |   100.00 | Using where |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
*/

limit优化思路:通过覆盖索引+子查询的方式来优化

8.优先考虑覆盖索引

尽量使用覆盖索引(覆盖索引:查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到),减少使用selecl *.

8.1 什么是覆盖索引?

覆盖索引: SQL只需要通过索引就可以返回查询所需要的数据,而不必通过二级索引查到主键之后再去查询数据理解方式一: 索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了。一个索引包含了满足查询结果的数据就叫做覆盖索引
理解方式二: 非聚簇复合索引的一种形式,它包括在查询里的SELECT、JOIN和WHERE子句用到的所有列(即建索引的字段正好是覆盖查询条件中所涉及的字段)。
简单说就是, 索引列+主键 包含 SELECT 到 FROM之间查询的列

覆盖索引演示

#6. 覆盖索引
#删除之前的索引
#举例1:
DROP INDEX idx_age_stuno ON student;
CREATE INDEX idx_age_name ON student (age,NAME);
EXPLAIN SELECT * FROM student WHERE age <> 20;
/*
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | student | NULL       | ALL  | idx_age_name  | NULL | NULL    | NULL | 498858 |   100.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
*/
EXPLAIN SELECT age,NAME FROM student WHERE age <> 20;
/*使用了索引,打破了前面说的“不等于”的查询索引会失效的原则
原因:查询优化器发现使用索引时,不会回表,开销更小,故使用了索引
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+--------+----------+--------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key          | key_len | ref  | rows   | filtered | Extra                    |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+--------+----------+--------------------------+
|  1 | SIMPLE      | student | NULL       | index | idx_age_name  | idx_age_name | 68      | NULL | 498858 |   100.00 | Using where; Using index |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+--------+----------+--------------------------+
*/
#举例2:
EXPLAIN SELECT * FROM student WHERE NAME LIKE '%abc';
/*
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table   | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | student | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 498858 |    11.11 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
*/
EXPLAIN SELECT id,age FROM student WHERE NAME LIKE '%abc';
/*
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+--------+----------+--------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key          | key_len | ref  | rows   | filtered | Extra                    |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+--------+----------+--------------------------+
|  1 | SIMPLE      | student | NULL       | index | NULL          | idx_age_name | 68      | NULL | 498858 |    11.11 | Using where; Using index |
+----+-------------+---------+------------+-------+---------------+--------------+---------+------+--------+----------+--------------------------+
*/

8.2 覆盖索引的利弊

好处:

1. 避免Innodb表进行索引的二次查询(回表)

lnnodb是以聚集索引的顺序来存储的,对于Innodb来说,二级索引在叶子节点中所保存的是行的主键信息,如果是用二级索引查询数据,在查找到相应的键值后,还需通过主键进行二次查询才能获取我们真实所需要的数据。


在覆盖索引中,二级索引的键值中可以获取所要的据,避免了对主键的二次查询,减少了IO操作,提升了查询效率。

2. 可以把随机IO变成顺序IO加快查询效率

由于覆盖索引是按键值的顺序存储的,对于IO密集型的范围查找来说,对比随机从磁盘读取每一行的数据IO要少的多,因此利用覆盖索引在访问时也可以把磁盘的随机读取的IO转变成索引查找的顺序IO

由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段

弊端:

索引字段的维护总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这是业务DBA,或者称为业务数据架构师的工作

9. 如何给字符串添加索引

有一张教师表,表定义如下:

create table teacher(
ID bigint unsigned primary key,
email varchar(64),
...
)engine=innodb;

讲师要使用邮箱登录,所以业务代码中一定会出现类似于这样的语句:

select col1, col2 from teacher where email='xxx';

如果email这个字段上没有索引,那么这个语句就只能做 全表扫描 。

9.1 前缀索引

MySQL是支持前缀索引的。默认地,如果你创建索引的语句不指定前缀长度,那么索引就会包含整个字符串

alter table teacher add index index1(email);
#或
 alter table teacher add index index2(email(6))

这两种不同的定义在数据结构和存储上有什么区别呢?下图就是这两个索引的示意图



如果使用的是index1(即email整个字符串的索引结构),执行顺序是这样的:


1.从index1索引树找到满足索引值是’ zhangssxyz@xxx.com ’的这条记录,取得ID2的值;

2.到主键上查到主键值是ID2的行,判断email的值是正确的,将这行记录加入结果集;

3.取index1索引树上刚刚查到的位置的下一条记录,发现已经不满足email=’ zhangssxyz@xxx.com ’的条件了,循环结束。这个过程中,只需要回主键索引取一次数据,所以系统认为只扫描了一行

如果使用的是index2(即email(6)索引结构),执行顺序是这样的:


1.从index2索引树找到满足索引值是’zhangs’的记录,找到的第一个是ID1;

2.到主键上查到主键值是ID1的行,判断出email的值不是’ zhangssxyz@xxx.com ’,这行记录丢弃;

3.取index2上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出ID2,再到ID索引上取整行然后判断,这次值对了,将这行记录加入结果集;

4.重复上一步,直到在idxe2上取到的值不是’zhangs’时,循环结束。

也就是说使用前缀索引,定义好长度,就可以做到既节省空间,又不用额外增加太多的查询成本。前面已经讲过区分度,区分度越高越好。因为区分度越高,意味着重复的键值越少

9.2 前缀索引对覆盖索引的影响

结论:

使用前缀索引就用不上覆盖索引对查询性能的优化了,这也是你在选择是否使用前缀索引时需要考虑的一个因素。

9.3 拓展内容

从查询效率上看,使用hash字段方式的查询性能相对更稳定一些。因为crc32算出来的值虽然有冲突的概率,但是概率非常小,可以认为每次查询的平均扫描行数接近1。而倒序存储方式毕竟还是用的前缀索引的方式,也就是说还是会增加扫描行数。

10. 索引下推

10.1 使用前后的对比

Index Condition Pushdown(ICP)是MySQL 5.6中新特性,是一种在存储引擎层使用索引过滤数据的一种优化方式。

ICP可以减少存储引擎访问基表的次数以及MySQL服务器访问存储引擎的次数。


如果没有ICP,存储引擎会遍历索引以定位基表中的行,并将它们返回给MySQL服务器,由MySQL服务器评估WHERE后面的条件是否保留行

启用ICP后,如果部分WHERE 条件可以仅使用索引中的列进行筛选,则

MySQL服务器会把这部分WHERE条件放到存储引擎筛选。然后,存储引擎通过使用索引条目来筛选数据,并且只有在满足这一条件时才从表中读取行。

好处:ICP可以减少存储引擎必须访问基表的次数和MySQL服务器必须访问存储引擎的次数

但是:ICP的加速效果取决于在存储引擎内通过ICP筛选掉的数据的比例

10.2 ICP的开启/关闭

默认情况下启用索引条件下推。可以通过设置系统变量optimizer_switch 控制:index_condition_pushdown

#关闭索引下推
SET optimizer_switch = 'index_condition_pushdown=off' ;
#打开索引下推
SET optimizer_switch = 'index_condition_pushdown=on' ;
  • 当使用索引条件下推时,EXPLAIN语句输出结果中Extra列内容显示为Using index condition
SET optimizer_switch = 'index_condition_pushdown=off';
#Using where
EXPLAIN SELECT * FROM people
WHERE zipcode= '000001'
AND lastname LIKE '%张%'
AND address LIKE '%北京市%';
SET optimizer_switch = 'index_condition_pushdown=on' ;
#Using index condition; Using where

10.3 ICP使用案例

#7.索引条件下推(ICP)
#举例一:
USE atguigudb1;
#Using index condition   
#先key1 > 'z' 再  key1 LIKE '%a' 最后回表  
#优于 先key1 > 'z' 再 回表   最后 key1 LIKE '%a'
EXPLAIN SELECT * FROM s1 WHERE key1 > 'z' AND key1 LIKE '%a';

建表

CREATE TABLE `people`(
  `id ` int NOT NULL AUTO_INCREMENT,
  `zipcode` varchar (20)COLLATE utf8_bin DEFAULT NULL,
  `firstname`  varchar(20)COLLATE utf8_bin DEFAULT NULL,
  `lastname` varchar(2) COLLATE utf8_bin DEFAULT NULL,
  `address` varchar(50) cOLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `zip_last_first`( `zipcode ', 'lastname ` , `firstname `)
)ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin;

插入数据

INSERT INTO `people` VALUES
INSERT INTO `people` VALUES
( '1', '000001','三','张','北京市'),
( '2', '000002','四','李','南京市'),
( '3', '000003','五','王','上海市'),
( '4', '000001','六','赵','天津市');

为该表定义联合索引zip_last_first (zipcode,lastname,firstname)。如果我们知道了一个人的邮编,但是不确定这个人的姓氏,我们可以进行如下检索:

SELECT * FROM people
WHERE zipcode= '008881'
AND lastname LIKE '%张%'
AND address LIKE '%北京市%';
#Using index condition; Using where

执行查看SQL的查询计划,Extra中显示了Using index condition,这表示使用了索引下推。另外,Using where表示条件中包含需要过滤的非索引列的数据,即address LIKE '%北京市%'这个条件并不是索引列,需要在服务端过滤掉。


如果不想出现Using where,把address LlKE’%北京市%'去掉即可

EXPLAIN SELECT * FROM people
WHERE zipcode= '000001'
AND lastname LIKE '%张%';
#Using index condition


这个表中存在两个索引,分别是:

  • 主键索引(简图)

    二级索引zip_last_first(简图,这里省略了数据页等信息)

    下面我们关闭ICP查看执行计划
mysql> SET optimizer_switch = 'index_condition_pushdown=off ';
Query oK, rows affected (0.02秒)

查看执行计划,已经没有了Using index condition,表示没有使ICP

mysql> explain SELECT * FROM people
WHERE zipcode='080801 '
AND lastname LIKE'%张%'AND address LIKE '%北京市%';

10.4 开启和关闭ICP的性能对比

创建存储过程,主要目的就是插入很多0000001的数据,这样查询的时候为了在存储引擎层做过滤,减少IO,也为了减少缓冲池(缓存数据页,没有lO)的作用。

#创建存储过程,向people表中添加1000000条数据,测试ICP开启和关闭状态下的性能
DELIMITER //
CREATE PROCEDURE insert_people( max_num INT )
BEGIN
DECLARE i INT DEFAULT 0;
  SET autocommit = 0;
  REPEAT
  SET i = i + 1;
  INSERT INTO people ( zipcode , firstname, lastname, address ) VALUES ( '000001', '六','赵','天津市');
  UNTIL i = max_num
  END REPEAT;
  COMMIT;
END //
DELIMITER ;

调用存储过程

call insert_people(1000000);
SELECT COUNT(*) FROM people;#1000004

首先打开profiling。

set profiling=1;

执行sQL语句,此时默认打开索引下推。

SELECT * FROM people WHERE zipcode='000001' AND lastname LIKE '%张%'; 

再次执行sQL语句,不使用索引下推

SELECT /*+ no_icp (people)*/ * FROM people WHERE zipcode='000001' AND lastname LIKE '%张%';

查看当前会话所产生的所有profiles

show profiles \G;

结果如下。


这个是SET optimizer_switch = 'index_condition_pushdown=off' 条件下执行的;


多次测试效率对比来看,使用ICP优化的查询效率会好一些。这里建议多存储一些数据效果更明显。

10.5 ICP的使用条件

1.如果表访问的类型为rapge、ref、eq_ref和ref_or_null可以使用ICP

2.ICP可以用于InnoDB和MyISAM表,包括分区表InnoDB和MyISAM表

3.对于InnoDB表,ICP仅用于二级索引。ICP的目标是减少全行读取次数,从而减少I/o操作。

4.当sQL使用覆盖索引时,不支持lCP。因为这种情况下使用ICP不会减少I/O。

5.相关子查询的条件不能使用ICP

ICP的使用条件:

① 只能用于二级索引(secondary index)

② explain显示的执行计划中type值(join 类型)为 range 、 ref 、 eq_ref 或者 ref_or_null

③ 并非全部where条件都可以用ICP筛选,如果where条件的字段不在索引列中,还是要读取整表的记录到server端做where过滤。

④ ICP可以用于MyISAM和InnnoDB存储引擎

⑤ MySQL 5.6版本的不支持分区表的ICP功能,5.7版本的开始支持。

⑥ 当SQL使用覆盖索引时,不支持ICP优化方法


11. 普通索引 vs 唯一索引

从性能的角度考虑,你选择唯一索引还是普通索引呢?选择的依据是什么呢?

假设,我们有一个主键列为ID的表,表中有字段k,并且在k上有索引,假设字段 k 上的值都不重复。

这个表的建表语句是:

create table test(
id int primary key,
k int not null,
name varchar(16),
index (k)
)engine=InnoDB;

表中R1~R5的(ID,k)值分别为(100,1)、(200,2)、(300,3)、(500,5)和(600,6)

11.1 查询过程

假设,执行查询的语句是 select id from test where k=5。

  • 对于普通索引来说,查找到满足条件的第一个记录(5,500)后,需要查找下一个记录,直到碰到第一个不满足k=5条件的记录
  • 对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索

那么,这个不同带来的性能差距会有多少呢?答案是, 微乎其微

11.2 更新过程

为了说明普通索引和唯一索引对更新语句性能的影响这个问题,介绍一下change buffer。
当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下, InooDB会将这些更新操作缓存在change buffer中 ,这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候,将数据页读入内存,然后执行change buffer中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性

将change buffer中的操作应用到原数据页,得到最新结果的过程称为 merge 。除了 访问这个数据页 会触发merge外,系统有后台线程会定期merge。在 数据库正常关闭(shutdown) 的过程中,也会执行merge操作。


如果能够将更新操作先记录在change buffer, 减少读磁盘 ,语句的执行速度会得到明显的提升。而且,数据读入内存是需要占用 buffer pool 的,所以这种方式还能够 避免占用内存 ,提高内存利用率。

唯一索引的更新就不能使用change buffer ,实际上也只有普通索引可以使用


如果要在这张表中插入一个新记录(4,400)的话,InnoDB的处理流程是怎样的?


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
9月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
9月前
|
存储 关系型数据库 MySQL
MySQL数据库索引的数据结构?
MySQL中默认使用B+tree索引,它是一种多路平衡搜索树,具有树高较低、检索速度快的特点。所有数据存储在叶子节点,非叶子节点仅作索引,且叶子节点形成双向链表,便于区间查询。
250 4
|
9月前
|
存储 SQL 关系型数据库
MySQL 核心知识与索引优化全解析
本文系统梳理了 MySQL 的核心知识与索引优化策略。在基础概念部分,阐述了 char 与 varchar 在存储方式和性能上的差异,以及事务的 ACID 特性、并发事务问题及对应的隔离级别(MySQL 默认 REPEATABLE READ)。 索引基础部分,详解了 InnoDB 默认的 B+tree 索引结构(多路平衡树、叶子节点存数据、双向链表支持区间查询),区分了聚簇索引(数据与索引共存,唯一)和二级索引(数据与索引分离,多个),解释了回表查询的概念及优化方法,并分析了 B+tree 作为索引结构的优势(树高低、效率稳、支持区间查询)。 索引优化部分,列出了索引创建的六大原则
234 2
|
10月前
|
存储 关系型数据库 MySQL
MySQL覆盖索引解释
总之,覆盖索引就像是图书馆中那些使得搜索变得极为迅速和简单的工具,一旦正确使用,就会让你的数据库查询飞快而轻便。让数据检索就像是读者在图书目录中以最快速度找到所需信息一样简便。这样的效率和速度,让覆盖索引成为数据库优化师傅们手中的尚方宝剑,既能够提升性能,又能够保持系统的整洁高效。
318 9
|
11月前
|
机器学习/深度学习 关系型数据库 MySQL
对比MySQL全文索引与常规索引的互异性
现在,你或许明白了这两种索引的差异,但任何技术决策都不应仅仅基于理论之上。你可以创建你的数据库实验环境,尝试不同类型的索引,看看它们如何影响性能,感受它们真实的力量。只有这样,你才能熟悉它们,掌握什么时候使用全文索引,什么时候使用常规索引,以适应复杂多变的业务需求。
288 12
|
7月前
|
缓存 关系型数据库 BI
使用MYSQL Report分析数据库性能(下)
使用MYSQL Report分析数据库性能
508 158
|
7月前
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
7月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS费用价格:MySQL、SQL Server、PostgreSQL和MariaDB引擎收费标准
阿里云RDS数据库支持MySQL、SQL Server、PostgreSQL、MariaDB,多种引擎优惠上线!MySQL倚天版88元/年,SQL Server 2核4G仅299元/年,PostgreSQL 227元/年起。高可用、可弹性伸缩,安全稳定。详情见官网活动页。
1277 152
|
7月前
|
关系型数据库 MySQL 数据库
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎
阿里云数据库RDS支持MySQL、SQL Server、PostgreSQL和MariaDB引擎,提供高性价比、稳定安全的云数据库服务,适用于多种行业与业务场景。
947 156
|
7月前
|
缓存 监控 关系型数据库
使用MYSQL Report分析数据库性能(中)
使用MYSQL Report分析数据库性能
533 156

推荐镜像

更多