MySQL 索引优化实践(单表)

目录

    • 一、前言
    • 二、表数据准备
    • 三、常见业务无索引查询耗时测试
      • 3.1、通过订单ID / 订单编号 查询指定订单
      • 3.2、查询订单列表
    • 四、订单常见业务索引优化实践
      • 4.1、通过唯一索引和普通索引优化通过订单编号查询订单信息
      • 4.2、通过普通联合索引优化订单列表查询
        • 4.2.1、分析查询字段的查询场景
        • 4.2.2、优化各场景查询和原因分析
          • 4.2.2.1、需要根据订单编号查询
          • 4.2.2.2、需要根据客户编号查询
          • 4.2.2.3、需要根据创建时间查询 和 需要根据订单状态查询
    • 五、索引优化实践
      • 4.1 联合索引第一个字段用范围查询可能不会走索引
      • 4.2 强制走索引(联合索引第一个字段用范围查询不会走索引这里强制使用索引)
      • 4.3 使用覆盖索引优化查询
      • 4.4 in和or在表数据量比较大的情况会走索引,在表记录不多的情况下会选择全表扫描
      • 4.5 like KK% 一般情况也是可以走索引的
      • 4.6 分页查询索引使用和优化
      • 4.7 order by查询索引使用和优化
        • 4.7 总结
    • 六、索引设计原则

一、前言

      索引是为了高效查询排好序的数据结构,当表数据量到达一个量级没有对应索引帮助查询耗时会很长,MySQL资源开销也会非常大,当然索引也不能随意创建,要做到尽量少的索引解决尽量多的问题,这里会对一些业务场景做索引优化演示,这篇文中只介绍单表索引优化,如果单表问题能解决多表关联查询优化就简单多了。

如果对MySQL索引原理还有explain SQL分析工具不是很熟悉的可以看看几篇文章:

  • MySQL 索引底层 B+Tree 原理解析
  • MySQL explain SQL分析工具详解与最佳实践
  • MySQL 索引介绍和最佳实践

二、表数据准备

这里要准备100w数据左右的表,表数据尽量多一些或者列多一些,如果数据太少,测试的时候可能看不到效果。

创建订单信息表

DROP TABLE IF EXISTS `order_info`;
CREATE TABLE `order_info` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单ID',`order_no` varchar(100)  NOT NULL COMMENT '订单编号',`customer_id` bigint(20) NOT NULL COMMENT '客户编号',`goods_id` bigint(20) NOT NULL COMMENT '商品ID',`goods_title` varchar(100) DEFAULT NULL COMMENT '商品标题',`order_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '订单状态 1:待支付 2:已支付 3:已发货 4、已收货',`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='订单信息表';

使用存储过程插入100w条数据

## 创建一个插入数据的存储过程
DROP PROCEDURE IF EXISTS insert_procedure;
delimiter;;
CREATE PROCEDURE insert_procedure () 
BEGINDECLARE i INT DEFAULT 1;DECLARE goods_id BIGINT DEFAULT CEIL(RAND() * 100);DECLARE t_error INTEGER DEFAULT 0;DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1;START TRANSACTION;WHILE ( i <= 1000000 ) DOINSERT INTO `order_info`(`order_no`,`customer_id`, `goods_id`, `goods_title`, `order_status`, `create_time`) VALUES (CONCAT('ON00000',i), CEIL(RAND() * 100000), goods_id, CONCAT('笔记本电脑',goods_id), MOD(i, 4)+1, NOW());SET i = i + 1;SET goods_id = CEIL(RAND() * 100);END WHILE;IF t_error=1 THENROLLBACK;ELSECOMMIT;END IF;
END;;
delimiter;# 调用存储过程插入数据 我本地插入100w条数据耗时200s
CALL insert_procedure ();

三、常见业务无索引查询耗时测试

我电脑的配置32G内存500G固态,MySQL配置全用默认,自己测试先看看自己MySQL配置的innodb_buffer_pool_size设置的是多少,默认是128MB,查看命令SHOW VARIABLES LIKE 'innodb_buffer_pool_size';配置里的单位是字节,InnoDB使用一个缓冲池来保存索引和原始数据,innodb_buffer_pool_size就是控制这个缓冲池的大小,这个缓冲池在一些情况下对查询性能影响非常大,线上建议设置成MySQL能使用内存的80%,这里不深入。

3.1、通过订单ID / 订单编号 查询指定订单

  • 通过订单ID查询订单
SELECT * FROM order_info WHERE id = 955;

在这里插入图片描述

  • 通过订单编号查询订单
SELECT * FROM order_info WHERE order_no = 'ON000009999';

在这里插入图片描述
这里已经可以看到查询耗时明显的差距,我们这里的ID是主键,MySQL InnoDB存储引擎会自动将表中的主键设置为主键索引,同时也是一个聚簇索引叶子节点携带数据,而订单编号是没有索引的会进行全表扫描,会将ON000009999和这个表中每行数据的订单编号都进行比对然后取出满足条件的数据行,100w数据查询一个订单信息耗时已经到了0.6秒左右。

3.2、查询订单列表

查询订单列表一般查询条件比较多,如订单编号、客户编号、订单状态、创建时间、创建时间倒序、是否分页做几个演示,查询条件的内容自己看看存储过程插入的数据长什么样。

  • 1、查询客户编号为111的订单列表不分页,不根据创建时间倒序
SELECT * FROM order_info WHERE customer_id = 111 AND create_time >= '2023-10-02 09:57:24' AND create_time <= '2023-10-02 10:00:46';

在这里插入图片描述

  • 2、查询客户编号为111订单列表分页,不根据创建时间倒序
SELECT * FROM order_info WHERE customer_id = 111 AND create_time >= '2023-10-02 09:57:24' AND create_time <= '2023-10-02 10:00:46' LIMIT 3;

在这里插入图片描述

  • 3、查询客户编号为111订单列表分页,根据创建时间倒序
SELECT * FROM order_info WHERE customer_id = 111 AND create_time >= '2023-10-02 09:57:24' AND create_time <= '2023-10-02 10:00:46' ORDER BY create_time DESC LIMIT 3;

在这里插入图片描述

这里三个查询只有第2个查询相对较快一点,耗时110毫秒,其它两个查询耗时基本上都接近500毫秒,从我们给定的条件来看区别就在分页或者不分页,排序或者不排序,一般认为分页肯定比不分页查询要快,但是我们看1和2查询分页比不分页耗时相差接近5倍相差可以说是巨大,然后在查询3中分页但是根据创建时间倒序,这里耗时和查询1相近和查询2耗时相差接近5倍,这其中原理挺有趣的会在下面索引优化实践中举例说明这一些问题。

四、订单常见业务索引优化实践

这里会对一些业务场景举例说明,也会对索引的一些特性做讲解。

4.1、通过唯一索引和普通索引优化通过订单编号查询订单信息

类似通过订单编号查询订单信息的业务有很多,都是通过一个编号信息如客户编号配送员编号查询一个一对一的详情数据,这一类查询都有一个特性编号唯一,并且编号类的数据大多都是字符串类型,这里优化可以考虑唯一索引和普通索引,一般我们会给这一类编号数据设置一个唯一索引,既保证了数据的唯一性也保证了通过编号查询的性能问题。

  • 1、添加唯一索引
ALTER TABLE `order_info` ADD UNIQUE INDEX `idx_orderNo`(`order_no`);
  • 2、添加索引后查询
SELECT * FROM order_info WHERE order_no = 'ON000009999';

在这里插入图片描述
无索引测试的时候耗时0.538s,添加索引后查询性能提升十几倍,数据量越大提升比例越高。

4.2、通过普通联合索引优化订单列表查询

      在上面无索引查询我们列举了查询订单列表的三个例子,查询耗时除了第2个都差不多耗时0.5s,不算太慢但是对MySQL性能开销其实是很大的,如果数据量在大一些到500w 1000w,查询时间也会增加到接受不了数值,所以必须要优化。

4.2.1、分析查询字段的查询场景

      优化前第一要考虑的就是需要一些什么字段,如我们例子中会使用订单编号、客户编号、订单状态、创建时间。

分析通过这四个字段查询的场景:

  • 1、需要根据订单编号查询
  • 2、需要根据客户编号查询
  • 3、需要根据创建时间查询
  • 4、需要根据订单状态查询

这里我给这四个字段分了四个查询场景,为什么这么分我在下面会详细说明。

4.2.2、优化各场景查询和原因分析

对于这种列表查询使用索引一定要知道索引的一个特性就是最左前缀原则,索引的匹配一定是从最左边第一个字段开始匹配的,不能跳过中间字段匹配,在索引优化实践中会详细说明。

4.2.2.1、需要根据订单编号查询

      在一个订单列表如果需要根据订单编号查询,那么一定是要查询一个唯一的订单,如果我们有索引那么我们可以通过一个订单编号快速定位到一条数据不用进行全表扫描,竟然能快速定位到一条数据那么就算还携带别的条件那直接回表取出行数据再去判断即可。
      所以这里只需要创建一个订单编号的索引来适配所有带订单编号的查询,我们在本文的4.1的优化通过订单编号查询订单信息中创建过一个订单编号的唯一索引,我们这里就用这个唯一索引就行。

  • 1、需要根据订单编号查询测试
SELECT * FROM order_info WHERE order_no = 'ON000009999' AND order_status=4;

在这里插入图片描述
执行计划 EXPLAIN
在这里插入图片描述

这里可以看到查询耗时为0.037s,执行计划中使用到了订单编号的索引,扫描估计行数为1。

4.2.2.2、需要根据客户编号查询

      在需要根据客户编号查询的业务中一定是以客户编号为主要条件的,还有可能会携带订单状态,创建时间等,一个客户可能会下很多单,想想自己这些年网购和点外面应该也有个100单以上了把,那么这里就不能像订单编号只用一个单字段索引了,我们需要把订单状态和创建时间也加上,其实就算不加性能也不会差太多因为一个客户订单本来也不会太多,单表几十条数据和几百条数据查询差距不会很大。

  • 1、创建以客户编号起头的普通联合索引
ALTER TABLE `order_info` ADD INDEX `idx_customerId_orderStatus_createTime`(`customer_id`, `order_status`, `create_time`);

我这里会把订单状态和创建时间也带上,某购物APP查询自己订单是不是都有状态选择,时间字段可以用作排序和检索。

  • 2、需要根据客户编号查询测试
SELECT * FROM order_info WHERE customer_id = 111 AND order_status=4 AND create_time >= '2023-10-02 09:57:24' AND create_time <= '2023-10-02 10:00:46';

在这里插入图片描述
执行计划 EXPLAIN
在这里插入图片描述
这里可以看到使用到了我们创建的联合索引,并且三个字段全用到了,客户编号bigint类型不能为空占用8字节,订单状态tinyint不能为空占用1字节,创建时间datetime类型占用5个字节因为创建时间可为空所以多加一个字节,创建时间占用6个字节,合集15个字节和key_len相等。

4.2.2.3、需要根据创建时间查询 和 需要根据订单状态查询

      在查询订单列表时经常会查询某个状态某个时间有多少订单,状态值只有4个如果要通过状态值建立索引的话显然是不可行的,通过状态索引查找某个类型数据可能得到的是几十万行数据,然后还需要回表获取聚簇索引数据,所以对于这种状态值创建单独索引时还需要带上时间字段,在单独查询某个时间内全部订单时也可以使用这个索引,通过in查询将状态值全部包含满足最左前缀原则就能使用该索引查询指定时间段的全部订单。

  • 1、添加索引前查询某个时间段内全部订单
SELECT * FROM order_info WHERE order_status IN (1,2,3,4) AND create_time >= '2023-10-02 09:57:30' AND create_time <= '2023-10-02 09:57:31';

在这里插入图片描述
因为我们是批量插入的时间间隔比较相近1秒有好几千条数据,自己查询测试的时候最好控制区间在2s的样子。

  • 2、创建订单状态和创建时间的普通索引
ALTER TABLE `order_info` ADD INDEX `idx_orderStatus_createTime`(`order_status`,`create_time`);
  • 3、查询某个时间段内全部状态订单
SELECT * FROM order_info WHERE order_status IN (1,2,3,4) AND create_time >= '2023-10-02 09:57:30' AND create_time <= '2023-10-02 09:57:40' ;

在这里插入图片描述
执行计划 EXPLAIN

在这里插入图片描述
我们这里数据是批量插入的,每秒会插入几千条数据,查询时间间隔不能太大了最好在2s的样子,不然索引可能是会失效的,要查询某个状态的订单只有把订单状态的的IN查询换成=查询效果是一样的,满足最左前缀原则即可。

五、索引优化实践

在订单常见业务索引优化实践中简单的介绍了一下在一些场景下创建一些什么索引能提升查询效率,但是还有很多可变因素会影响到索引的使用,也有很多场景可以使用更好的索引,以及索引中很重要的左前缀原则,这里会对一些场景做举例说明。

删除之前创建的索引,创建新的测试联合索引

# 删除上面创建的三个索引,避免测试时被其它索引干扰,要是没有创建则不用删除
ALTER TABLE `order_info` DROP INDEX `idx_orderNo`;
ALTER TABLE `order_info` DROP INDEX `idx_customerId_orderStatus_createTime`;
ALTER TABLE `order_info` DROP INDEX `idx_orderStatus_createTime`;
# 创建新的测试联合索引
ALTER TABLE `order_info` ADD INDEX `idx_goodsTitle_customerId_orderStatus`(`goods_title`, `customer_id`, `order_status`);

4.1 联合索引第一个字段用范围查询可能不会走索引

EXPLAIN SELECT * FROM order_info WHERE goods_title > '笔记本电脑9' AND customer_id = 9 AND order_status = 4;

在这里插入图片描述

  • 给一个区间值
EXPLAIN SELECT * FROM order_info  WHERE goods_title > '笔记本电脑9' AND goods_title < '笔记本电脑99' AND customer_id = 9 AND order_status = 4;

MySQL5.7
在这里插入图片描述

MySQL8.0
在这里插入图片描述

联合索引第一个字段就用范围查找可能不会走索引,对于MySQL5.7来说只要第一个字段用范围查找不会走索引,但是对于MySQL8.0来说给个查询区间还是可能会走索引的,前提是区间也不能太大不然也不会走索引,MySQL内部可能觉得第一个字段用范围,结果集应该很大,回表效率不高,还不如就全表扫描,创建联合索引时千万别把时间这类型字段放第一个了。

4.2 强制走索引(联合索引第一个字段用范围查询不会走索引这里强制使用索引)

EXPLAIN SELECT * FROM order_info FORCE INDEX(idx_goodsTitle_customerId_orderStatus) WHERE goods_title > '笔记本电脑9' AND customer_id = 9 AND order_status = 4;

在这里插入图片描述
这里确认是使用了我们指定的索引,然后再来看看查询性能怎么样

  • 不指定强制走索引
    在这里插入图片描述

  • 指定强制走索引
    在这里插入图片描述

经过对比发现强制走索引查询时间能缩短近10倍,所以有时候MySQL自身并不一定能选择到性能最高的索引使用方式,需要自己不断的尝试对比出最好的方式。

4.3 使用覆盖索引优化查询

EXPLAIN SELECT goods_title,customer_id,order_status FROM order_info WHERE goods_title > '笔记本电脑9' AND customer_id = 9 AND order_status = 4;

在这里插入图片描述
查询结果字段和条件字段都在同一个索引中,查询可以完全使用索引中字段不用回表则称为覆盖索引,覆盖索引因为能避免回表就算联合索引第一个字段范围查询也能走索引。

4.4 in和or在表数据量比较大的情况会走索引,在表记录不多的情况下会选择全表扫描

  • 100w数据表测试
EXPLAIN SELECT * FROM order_info  WHERE goods_title IN('笔记本电脑8','笔记本电脑9') AND customer_id = 9 AND order_status = 4;

在这里插入图片描述

EXPLAIN SELECT * FROM order_info  WHERE (goods_title = '笔记本电脑8' OR goods_title = '笔记本电脑9') AND customer_id = 9 AND order_status = 4;

在这里插入图片描述

  • 根据order_info创建一个只有3条数据order_info_copy表进行测试
    MySQL5.7
    在这里插入图片描述
    在这里插入图片描述
    MySQL8.0
    在这里插入图片描述
    在这里插入图片描述

这里可以看到MySQL5.7中会进行全表扫描,但是MySQL8.0还是会走索引,现在MySQL8.0市场上用的已经比较多了,它执意要走索引肯定有它的道理,而且要通过索引优化查询肯定是要测试比较查询效率的,在实际业务中多测试再看看执行计划,只要实践才知道加的索引是否好用。

4.5 like KK% 一般情况也是可以走索引的

  • like 笔记本电脑999
EXPLAIN SELECT * FROM order_info WHERE goods_title LIKE '笔记本电脑999%' AND customer_id = 9 AND order_status = 4;

在这里插入图片描述

  • like 笔记本电脑9
EXPLAIN SELECT * FROM order_info WHERE goods_title LIKE '笔记本电脑9%' AND customer_id = 9 AND order_status = 4;

在这里插入图片描述

使用like前缀查询在结果集较少的时候是会走索引的,如果MySQL认为结果集较大还是不会走索引,结合以上几个例子可以看出,如果通过索引查询响应结果集过大并且没有满足覆盖索引也很有可能不会走索引,这点MySQL5.0 8.0都是一样的。

4.6 分页查询索引使用和优化

  • 例1:在没有索引且不分页的请求下查询指定客户订单列表数据
EXPLAIN SELECT * FROM order_info WHERE customer_id = 9 ORDER BY goods_title;

-

  • 例2:在没有索引分页查询指定客户订单列表数据
SELECT * FROM order_info WHERE customer_id = 9 LIMIT 0,3;

在这里插入图片描述

SELECT * FROM order_info WHERE customer_id = 9 LIMIT 80,3;

在这里插入图片描述
通过这两个分页查询可以看到查询从第0条开始往后查3条数据执行耗时很短,查询从第80条开始往后查3条数据耗时和不分页差不多,因为MySQL分页查询的时候会根据我们的分页条件找出对应结果集的数据,比如我们分页条件时customer_id = 9 LIMIT 0,3,MySQL会先用customer_id = 9去一条条对比数据,因为我们的分页参数时0,3也就是说找出3条数据即可,只要找到了3条数据就不会往后找了,同理LIMIT 80,3的时候需要找到83条数据就不会往后找了,所以这里我们LIMIT 80,3的时候和不分页耗时差不了多少,不加分页会扫描全表拿出全表的数据。

  • 例3:在没有索引分页查询指定客户订单列表数据并且根据创建时间排序
SELECT * FROM order_info WHERE customer_id = 9 ORDER BY create_time LIMIT 0,3;

在这里插入图片描述
这里加了一个排序条件分页查询后耗时也和不分页差不多,因为如果加了排序字段是需要先扫全表获取全部符合结果的数据才能进行分页。

  • 例4:创建索引分页查询指定客户订单列表数据并且根据创建时间排序(正序)
# 创建索引
ALTER TABLE `order_info` ADD INDEX `idx_customerId_createTime`(`customer_id`, `create_time`);
# 删除索引
ALTER TABLE `order_info` DROP INDEX `idx_customerId_createTime`;
SELECT * FROM order_info WHERE customer_id = 9 ORDER BY create_time LIMIT 0,3;

在这里插入图片描述
执行计划 EXPLAIN
在这里插入图片描述
创建索引后查询快了很多,因为这里是正序的索引默认也是正序的根本不用在进行排序,下面再试试倒序。

  • 例4:创建索引分页查询指定客户订单列表数据并且根据创建时间排序(倒序)
SELECT * FROM order_info WHERE customer_id = 9 ORDER BY create_time DESC LIMIT 0,3;

MySQL 5.7
在这里插入图片描述
MySQL8.0
在这里插入图片描述
查询时间和正序差不多,但是这里MySQL5.7和MySQL8.0的Extra有点区别,MySQL8.0可以反向索引扫描,MySQL5.7应该是将获取到的数据放入内存中排序,也可以创建倒序索引这里不深入。

4.7 order by查询索引使用和优化

  • 例1:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '笔记本电脑9' AND order_status = 4 ORDER BY customer_id;

在这里插入图片描述

利用最左前缀原则:中间字段不能断,因此查询用到了goods_title索引,从key_len=403也能看出,customer_id索引列用在排序过程中,因为Extra字段里没有using filesort,而且索引本来就是正序的无需在排。

  • 列2:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '笔记本电脑9' ORDER BY order_status;

在这里插入图片描述

从explain的执行结果来看:key_len=403,查询使用了goods_title 索引,由于用了order_status进行排序,跳过了
customer_id,出现了Using filesort。

  • 列3:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '笔记本电脑9' ORDER BY customer_id,order_status;

在这里插入图片描述

查找只用到索引goods_title 字段,customer_id和order_status用于排序,无Using filesort。

  • 列4:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '笔记本电脑9' ORDER BY order_status,customer_id;

在这里插入图片描述

和例3中explain的执行结果一样,但是出现了Using filesort,因为索引的创建顺序为goods_title,customer_id,order_status,但是排序的时候customer_id和order_status颠倒位置了。

  • 列5:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '笔记本电脑9' AND customer_id = 9 ORDER BY order_status,customer_id;

在这里插入图片描述

与例4对比,在Extra中并未出现Using filesort,因为customer_id 为常量,在排序中被优化,所以索引未颠倒,不会出现Using filesort。

  • 列6:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '笔记本电脑9' ORDER BY customer_id ASC,order_status DESC;

在这里插入图片描述

虽然排序的字段列与索引顺序一样,且order by默认升序,这里position desc变成了降序,导致与索引的排序方式不同,从而产生Using filesort。

  • 列7:
EXPLAIN SELECT * FROM order_info WHERE goods_title IN ('笔记本电脑9','笔记本电脑10') ORDER BY customer_id,order_status;

在这里插入图片描述
对于排序来说,IN查询也是范围查询,如果排序查询中使用范围查询则索引中只能用到goods_title,后面的字段无法使用。

  • 列8:
EXPLAIN SELECT * FROM order_info WHERE goods_title > '笔记本电脑9' ORDER BY goods_title;

MySQL5.7
在这里插入图片描述

MySQL8.0
在这里插入图片描述
MySQL5.7只要是联合索引第一个字段要走范围查询,那么索引就没法使用,除非覆盖索引,但是在MySQL8.0时却是会去使用索引的,还可以对比一下查询性能,我这里MySQL5.7全表扫描耗时1.3s,MySQL8.0走索引耗时0.8s,两个版本MySQL第一次执行可能时间都需要2s的样子,会将磁盘中的聚簇索引叶子节点数据加载到内存中,多次执行后回表可以直接查内存不用再次读取磁盘。

4.7 总结
  • 1、MySQL支持两种方式的排序filesort和index,Using index是指MySQL扫描索引本身完成排序。index
    效率高,filesort效率低。
  • 2、order by满足两种情况会使用Using index。
    • order by语句使用索引最左前列。
    • 使用where子句与order by子句条件列组合满足索引最左前列。
  • 3、尽量在索引列上完成排序,遵循索引建立(索引创建的顺序)时的最左前缀法则。
  • 4、如果order by的条件不在索引列上,就会产生Using filesort。
  • 5、能用覆盖索引尽量用覆盖索引
  • 6、group by与order by很类似,其实质是先排序后分组,遵照索引创建顺序的最左前缀法则。对于group
    by的优化如果不需要排序的可以加上order by null禁止排序。注意,where高于having,能写在where中
    的限定条件就不要去having限定了。

Using filesort文件排序原理详解

  • filesort文件排序方式
    • 单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序;用trace工具可
      以看到sort_mode信息里显示< sort_key, additional_fields >或者< sort_key,
      packed_additional_fields >
    • 双路排序(又叫回表排序模式):是首先根据相应的条件取出相应的排序字段和可以直接定位行
      数据的行 ID,然后在 sort buffer 中进行排序,排序完后需要再次取回其它需要的字段;用trace工具
      可以看到sort_mode信息里显示< sort_key, rowid >
  • MySQL 通过比较系统变量 max_length_for_sort_data(默认1024字节) 的大小和需要查询的字段总大小来
    判断使用哪种排序模式。
    • 如果 字段的总长度小于max_length_for_sort_data ,那么使用 单路排序模式;
    • 如果 字段的总长度大于max_length_for_sort_data ,那么使用 双路排序模式。

六、索引设计原则

  • 1、代码先行,索引后上
    不知大家一般是怎么给数据表建立索引的,是建完表马上就建立索引吗?
    这其实是不对的,一般应该等到主体业务功能开发完毕,把涉及到该表相关sql都要拿出来分析之后再建立
    索引。
  • 2、联合索引尽量覆盖条件
    比如可以设计一个或者两三个联合索引(尽量少建单值索引),让每一个联合索引都尽量去包含sql语句里的
    where、order by、group by的字段,还要确保这些联合索引的字段顺序尽量满足sql查询的最左前缀原
    则。
  • 3、不要在小基数字段上建立索引
    索引基数是指这个字段在表里总共有多少个不同的值,比如一张表总共100万行记录,其中有个性别字段,
    其值不是男就是女,那么该字段的基数就是2。
    如果对这种小基数字段建立索引的话,还不如全表扫描了,因为你的索引树里就包含男和女两种值,根本没
    法进行快速的二分查找,那用索引就没有太大的意义了。
    一般建立索引,尽量使用那些基数比较大的字段,就是值比较多的字段,那么才能发挥出B+树快速二分查
    找的优势来。
  • 4、长字符串我们可以采用前缀索引
    尽量对字段类型较小的列设计索引,比如说什么tinyint之类的,因为字段类型较小的话,占用磁盘空间也会
    比较小,此时你在搜索的时候性能也会比较好一点。
    当然,这个所谓的字段类型小一点的列,也不是绝对的,很多时候你就是要针对varchar(255)这种字段建立
    索引,哪怕多占用一些磁盘空间也是有必要的。
    对于这种varchar(255)的大字段可能会比较占用磁盘空间,可以稍微优化下,比如针对这个字段的前20个
    字符建立索引,就是说,对这个字段里的每个值的前20个字符放在索引树里,类似于 KEY
    index(name(20),age,position)。
    此时你在where条件里搜索的时候,如果是根据name字段来搜索,那么此时就会先到索引树里根据name
    字段的前20个字符去搜索,定位到之后前20个字符的前缀匹配的部分数据之后,再回到聚簇索引提取出来
    完整的name字段值进行比对。
    但是假如你要是order by name,那么此时你的name因为在索引树里仅仅包含了前20个字符,所以这个排
    序是没法用上索引的, group by也是同理。所以这里大家要对前缀索引有一个了解。
  • 5、where与order by冲突时优先where
    在where和order by出现索引设计冲突时,到底是针对where去设计索引,还是针对order by设计索引?到
    底是让where去用上索引,还是让order by用上索引?
    一般这种时候往往都是让where条件去使用索引来快速筛选出来一部分指定的数据,接着再进行排序。
    因为大多数情况基于索引进行where筛选往往可以最快速度筛选出你要的少部分数据,然后做排序的成本可
    能会小很多。
  • 6、基于慢sql查询做优化
    可以根据监控后台的一些慢sql,针对这些慢sql查询做特定的索引优化。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/147189.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YAMLException : java.nio.charset.MalformedInputException : Input length = 1

场景还原 有小伙伴反应SpringBoot项目启动异常&#xff0c;但是同组其他伙伴的无问题&#xff01; ERROR org.springframework.boot.SpringApplication - Application run failedorg.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException : Inpu…

决策树C4.5算法的技术深度剖析、实战解读

目录 一、简介决策树&#xff08;Decision Tree&#xff09;例子&#xff1a; 信息熵&#xff08;Information Entropy&#xff09;与信息增益&#xff08;Information Gain&#xff09;例子&#xff1a; 信息增益比&#xff08;Gain Ratio&#xff09;例子&#xff1a; 二、算…

【初识Linux】上

初识Linux上 一、Linux背景1.1 UNIX发展的历史1.2 UNIX发展的历史 二、开源三、官网Linux官网 四、企业应用现状五、发行版本六、 os概念&#xff0c;定位 本博客简介 初始Linux操作系统初识shell命令 ,了解若干背景知识。使用常用Linux命令了解Linux权限概念与思想,能深度理解…

调用gethostbyname实现域名解析(附源码)

VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门到精通系列教程&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&a…

世界前沿技术发展报告2023《世界信息技术发展报告》(七)网络与信息安全技术

&#xff08;七&#xff09;网络与信息安全技术 1. 概述2. 网络安全关键技术2.1 美国特种作战司令部举办网络挑战赛以寻找边缘安全技术2.2 英国卡迪夫大学开发出在1秒内阻止网络攻击的方法2.3 国研究人员开发出检测恶意网页的新方法2.4 韩国仁川大学研发出一种基于5G的人工智能…

管道-有名管道

一、有名管道 有名管道与匿名管道的不同&#xff1a; 有名管道提供了一个路径名&#xff0c;并以FIFO的文件形式存在于文件系统中。与匿名管道不同&#xff0c;有名管道可以被不相关的进程使用&#xff0c;只要它们可以访问该路径&#xff0c;就能够通过有名管道进行通信。 FI…

IDEA中的神仙插件——Smart Input (自动切换输入法)

推荐专栏&#xff1a;开发环境配置攻略 致力于记录学习过程中各种软件的安装及环境配置操作&#xff0c;并提供详细的步骤说明和丰富的配图。涵盖了 Java、Python、IntelliJ IDEA、Tomcat、MySQL 等常见开发工具和服务器组件的配置&#xff0c;为初学者提供一个实用、全面的配置…

使用python脚本的时间盲注完整步骤

文章目录 一、获取数据库名称长度二、获取数据库名称三、获取表名总长度四、获取表名五、获取指定表列名总长度六、获取指定表列名七、获取指定表指定列的表内数据总长度八、获取指定表指定列的表内数据 一、获取数据库名称长度 测试环境是bwapp靶场 SQL Injection - Blind - …

RocketMQ Dashboard说解

RocketMQ Dashboard 是 RocketMQ 的管控利器&#xff0c;为用户提供客户端和应用程序的各种事件、性能的统计信息&#xff0c;支持以可视化工具代替 Topic 配置、Broker 管理等命令行操作。 介绍​ 功能概览​ 面板功能运维修改nameserver 地址; 选用 VIPChannel驾驶舱查看 …

树莓集团涉足直播产业园区运营,成都直播产业园区再添黑马

树莓集团涉足成都直播产业园运营领域&#xff0c;这一消息引起了业界的广泛关注。在这个无限可能的直播领域中&#xff0c;树莓集团将与上市公司德商产投紧密合作&#xff0c;立志为成都直播行业的发展注入新的活力。成都天府蜂巢直播产业园推行着一系列创新的政策措施&#xf…

凉鞋的 Godot 笔记 102. 场景与节点的增删改查

在上一篇&#xff0c;我们完成了 Godot 引擎的 Hello World 输出&#xff0c;并且完成了第一个基本循环: 通过这次基本循环的完成&#xff0c;我们获得了一点点的 Godot 使用经验&#xff0c;这非常重要。 有实践经验后再去补充理论 和 先学习理论后去实践相比&#xff0c;前者…

2023年中国纯棉纱行业现状及发展前景分析[图]

棉纱是棉纤维经纺纱工艺加工而成的纱&#xff0c;经合股加工后称为棉线。根据纺纱的不同工艺&#xff0c;可分为普梳纱和精梳纱。精梳纱选用优质原料&#xff0c;成纱中纤维伸直平行、结杂少、光泽好、条干匀、强力高&#xff0c;这类棉纱多用于织造高档。 棉纱分类 资料来源&…

什么样的枕头可以让睡眠更舒适——四个月的反复试验结果

如何提高睡眠质量&#xff0c;我们先从睡眠中的呼吸质量谈起&#xff0c;这里面有大量的数据和记录&#xff0c;我后续会整理我这七八年来积累的所有睡眠质量数据进行分析汇总和处理。 几个月前我在看我的华为手表监控的睡眠数据时看到了关于睡眠中呼吸质量的数据&#xff0c;最…

vue重修004上部

文章目录 版权声明组件的三大组成部分scoped解决样式冲突scoped原理2.代码演示 组件data函数说明演示 组件通信组件关系分类通信解决方案父子通信流程子向父通信代 props详解props校验props&data、单向数据流 小黑记事本&#xff08;组件版&#xff09;基础组件结构需求和实…

【Java每日一题】— —第十九题:用二维数组存放九九乘法表,并将其输出。(2023.10.03)

&#x1f578;️Hollow&#xff0c;各位小伙伴&#xff0c;今天我们要做的是第十九题。 &#x1f3af;问题&#xff1a; 用二维数组存放九九乘法表&#xff0c;并将其输出。 测试结果如下&#xff1a; &#x1f3af; 答案&#xff1a; System.out.println("九九乘法表如…

为什么炒股人更爱融资?融券交易背后的风险与获利机会

炒股过程中&#xff0c;融资和融券交易是常见的操作方式。然而&#xff0c;据观察&#xff0c;炒股的人更倾向于选择融资交易&#xff0c;而融券交易相对较少。那么&#xff0c;是什么导致了这种偏好呢&#xff1f;本文将解析融资和融券交易的运作机制&#xff0c;以及投资者为…

jira流转issue条目状态transitions的rest实用脚本,issue状态改变调整

官方文档链接地址&#xff1a; POST Transition issue Performs an issue transition and, if the transition has a screen, updates the fields from the transition screen. sortByCategory To update the fields on the transition screen, specify the fields in the fiel…

1.3 互联网的组成

思维导图&#xff1a; 前言&#xff1a; 我的笔记&#xff1a; #### 一、总览 - **互联网的结构**&#xff1a; - 具有全球覆盖和复杂的拓扑结构。 - 即便结构复杂&#xff0c;还是可以从工作方式上简化为两大部分&#xff1a;边缘部分和核心部分。 #### 二、边缘部分 -…

基于R的linkET包qcorrplot可视化Mantel test相关性网络热图分析correlation heatmap

写在前面 需求是对瘤胃宏基因组结果鉴定到的差异菌株与表观指标、瘤胃代谢组、血清代谢组、牛奶代谢组中有差异的部分进行关联分析&#xff0c;效果图如下&#xff1a; 数据准备 逗号分隔的csv格式文件&#xff0c;两个表格&#xff0c;一个是每个样本对应的表观指标数据&…

PyQt5+Qt设计师初探

在上一篇文章中我们搭建好了PyQt5的开发环境&#xff0c;打铁到趁热我们基于搭建好的环境来简单实战一把 一&#xff1a;PyQt5包模块简介 PyQt5包括的主要模块如下。 QtCore模块——涵盖了包的核心的非GUI功能&#xff0c;此模块被用于处理程序中涉及的时间、文件、目录、数…