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 >
- 单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序;用trace工具可
- 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查询做特定的索引优化。
相关文章:
MySQL 索引优化实践(单表)
目录 一、前言二、表数据准备三、常见业务无索引查询耗时测试3.1、通过订单ID / 订单编号 查询指定订单3.2、查询订单列表 四、订单常见业务索引优化实践4.1、通过唯一索引和普通索引优化通过订单编号查询订单信息4.2、通过普通联合索引优化订单列表查询4.2.1、分析查询字段的查…...
react create-react-app v5配置 px2rem (暴露 eject方式)
环境信息: create-react-app v5 “react”: “^18.2.0” “postcss-plugin-px2rem”: “^0.8.1” 配置步骤: 我这个方式是 npm run eject 暴露 webpack配置的方法 1.安装 postcss-plugin-px2rem 和 lib-flexible cnpm install postcss-plugin-px2rem…...
AVL树的实现及原理
目录 AVL树的由来 AVL的实现原理 左单旋 右单旋 先左后右 先右后左 总结 AVL树的由来 查找,无论在什么情况下都与我们息息相关。在我们学习数组阶段学习到了线性查找,可是它的效率很低下,又演变出来了二分查找,它的效率非常…...
NestJs和Vite使用monorepo管理项目中,需要使用共享的文件夹步骤
NestJs和Vite使用monorepo管理项目中,需要使用共享的文件夹步骤 1 首先需要将nest-cli打包的功能通过webpack接管 nest-cli.json文件内容 {"$schema": "https://json.schemastore.org/nest-cli","collection": "nestjs/schematics",…...
我用PYQT5做的第一个实用的上位机项目(三)
基本的程序框架: 因为自己不是专业的程序员,只是一个搞电气控制的“票友”,所以尽量减少手动输入 代码量,能在Qt Dsigner里面完成的组态就不要放在代码里面完成。 在框架的建设方面,尽量做到集中和整合,位…...
代谢组学分析平台(二)
GC/MS分析生物样本为何要衍生化处理?有哪些衍生化的方法? GC的流动相为气体(通常为高纯氦),这就要求被分析物必须能够气化,而生物样本中很多内源性代谢物都含有极性基团,具有沸点高、不易气化特…...
【统计学】Top-down自上而下的角度模型召回率recall,精确率precision,特异性specificity,模型评价
最近在学 logistic regression model,又遇见了几个之前的老面孔。 召回率recall, 精确率precision,特异性spcificity,准确率accuracy,True positive rate,false positive rate等等名词在学习之初遇到的困难在于&#x…...
AutoDL使用tensorboard
目录 一,训练形成log文件 二. 切换logs目录 三,在AutoPanel中访问TensorBoard 一,训练形成log文件 例子: from torch.utils.tensorboard import SummaryWriter import numpy as npwriter SummaryWriter() for x in range(1, …...
代谢组学分析手段(一)
核磁共振技术(Nuclear Magnetic Resonance, NMR) 定义:指核磁矩不为零的原子核在外磁场的作用下,核自旋能级发生塞曼分裂,共振吸收某一特定频率的射频辐射的物理过程。 优点: (1)…...
网络基础入门(网络基础概念详解)
本篇文章主要是对网络初学的概念进行解释,可以让你对网络有一个大概整体的认知。 文章目录 一、简单认识网络 1、1 什么是网络 1、2 网络分类 二、网络模型 2、1OSI七层模型 2、1、1 简单认识协议 2、1、2 OSI七层模型解释 2、2 TCP/IP五层(或四层)模型 三、网络传…...
简化任务调度与管理:详解XXL-Job及Docker Compose安装
在现代应用程序开发中,任务调度和管理是至关重要的一部分。XXL-Job是一个强大的分布式任务调度平台,它使得任务的调度和管理变得更加轻松和高效。本文将介绍XXL-Job的基本概念,并详细演示如何使用Docker Compose进行快速安装和配置。 什么是X…...
QByteArray字节数组
QByteArray字节数组 文章目录 QByteArray字节数组1.1 QByteArray类基本使用说明1.2 设置数组字节大小1.3 返回数组大小1.4 将数据转为其他类型1.5 将数据转为C语言的字符指针返回1.6 数组数据追加1.7 清除数组数据为指定值1.8 数组数据插入1.9 删除指定位置指定长度的数据1.10 …...
ubuntu20.04.3中qt程序界面嵌套另一个qt界面
先上代码 #include "mainwindow.h" #include <QApplication> #include <iostream> using namespace std; #ifdef _WIN32// Windows 平台的代码 #include <windows.h> #elif __linux__// Linux 平台的代码// ...#include <X11/Xlib.h> #else…...
【chainlit】使用chainlit部署chatgpt
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…...
测开 | Vue速查知识点
文章目录 Vue知识1. Vue 概述2. Vue 代码格式3. Vue 指令3.1 v-bind & v-model3.2 v-on3.3 v-if和v-show3.4 v-for 4. 生命周期 Vue知识 1. Vue 概述 简介: Vue.js(读音 /vjuː/, 类似于 view) 是一套构建用户界面的 渐进式框架。与其他…...
数据结构——二叉树的基本概念及顺序存储(堆)
目录 一.前言 二.树概念及结构 2.1 树的概念 2.2 树的相关概念 2.3 树的表现 2.4 树在实际中的应用(表示文件系统的目录树结构) 三.二叉树的概念及结构 3.1 概念 3.2 特殊的二叉树 3.3 二叉树的性质 3.4 二叉树的存储结构 3.4.1 顺序存储 3…...
acwing算法基础之基础算法--整数二分算法
目录 1 知识点2 代码模板 1 知识点 有单调性一定可以二分,但在某些情况下,不具有单调性也可以二分。 单调性也可以抽象成某类性质,分界点左边不满足此性质,而右边满足此性质。当然也可以分界点左边满足此性质,而右边不…...
windows C 开发
在win下用C/C开发 非图形界面 应用程序 基础环境包括3个内容1. API : 一般是系统(包括c标准库和其他dll)提供的2. 编译器 : 可以是gnu的,可以是微软提供的3. 编辑器 : 随意都可以 // 不再考虑范围开发方式(API编译器) 原生windows API 使用 Windows API 来编写非视窗代码。…...
C语言——动态内存管理详解(内存结构、动态内存函数、易错题、柔性数组)
本篇概要 本篇文章从基本出发讲述为什么要存在动态内存分配,动态内存函数有哪些,常见的动态内存错误,一些关于内存分配的练习题以及柔性数组的相关知识。 文章目录 本篇概要1.为什么存在动态内存分配1.1为什么要动态分配内存1.2内存结构 2.常…...
2023年全国控制科学与工程学科评估结果 - 自动化考研
考研选择学校时,控制科学与工程考研学校排名情况怎样是广大考研学子十分关心的问题,以下是我们自动化考研联盟为大家整理得最新控制科学与工程学科评估结果情况,还比较权威,供大家参考。 最后祝大家一战成硕,有其他问题欢迎评论区…...
React wangEditor5 使用说明
1、支持包安装 yarn add wangeditor/editor # 或者 npm install wangeditor/editor --saveyarn add wangeditor/editor-for-react # 或者 npm install wangeditor/editor-for-react --save2、使用 import wangeditor/editor/dist/css/style.css // 引入 cssimport { useState…...
vue 实现数字验证码功能
需求:写了一个 手机发送验证码后 输入固定验证码的功能 封装成一个组件,如下: <template><div class"conts"><div class"box"><div class"code_list"><div :class"[ code_item, hideIndex 0 ? co…...
【计算机网络】HTTP协议详解(举例解释,超级详细)
文章目录 一、HTTP协议简单介绍 1、1 什么是HTTP协议 1、2 再次理解“协议” 二、HTTP请求 2、1 HTTP的工作过程 2、1、1 demo代码 2、2 URL 介绍 2、2、1 urlencode 和 urldecode 2、3 HTTP 请求格式 三、HTTP响应 3、1 响应demo 3、2 HTTP 响应格式 四、HTTP 请求和响应中的…...
PCB放置过孔技巧
合理的放置过孔能有效的节约面积。 我们根据嘉立创的pcb工艺能力中写出单双面板最小过孔为0.3mm(内径)/0.5mm(外径) 设置过孔尺寸外直径为24mil(0.61mm))内直径为12mil(0.305mm) 嘉立创PCB工艺加工能力范围说明-嘉立…...
淘宝商品详情接口数据采集用于上货,无货源选品上货,采集淘宝天猫商品详情数据
淘宝商品详情接口数据采集可用于上货。先通过关键字搜索接口,抓取到批量的商品ID,再将商品ID传入商品详情数据采集接口的请求参数中,从而达到批量抓取商品详情数据的功能。 接口名称:item_get,获取商品详情数据&#…...
DoS和DDos攻攻击
介绍 DDoS 和 DoS 攻击是我们最常见的网络攻击之一,而且历史相当悠久,算是很经典的两种攻击方式,但它们实际上是如何运作的呢? 虽然两者基本上都能够让工作停摆,但其中有很大的差异,接下来我们将逐一说明&a…...
Python实时采集Windows CPU\MEMORY\HDD使用率
文章目录 安装psutil库在Python脚本中导入psutil库获取CPU当前使用率,并打印结果获取内存当前使用率,并打印结果获取磁盘当前使用情况,并打印结果推荐阅读 要通过Python实时采集Windows性能计数器的数据,你可以使用psutil库。psut…...
【改造中序遍历算法】1038. 从二叉搜索树到更大和树
1038. 从二叉搜索树到更大和树 解题思路 改造中序遍历算法先遍历右子树 然后累加当前节点的值 再遍历左子树 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode…...
克服网络安全压力:如何掌控无限的云数据
管理云中的数字风险比以往任何时候都更加重要。数字化转型引发的云数据呈指数级增长,为安全分析师创造了一个更大的威胁环境。随着威胁行为者继续危害组织最敏感的数据,这一挑战将会加剧。 预计未来五年全球网络犯罪成本将激增,从 2022 年的…...
【数据结构和算法】--N叉树中,返回某些目标节点到根节点的所有路径
目录 一、前言二、具体实现及拓展2.1、递归-目标节点到根节点的路径数据2.2、list转换为tree结构2.3、tree转换为list结构 一、前言 这么多年工作经历中,“数据结构和算法”真的是超重要,工作中很多业务都能抽象成某种数据结构问题。下面是项目中遇到的…...
wordpress可以商用吗/武汉建站公司
/* ******************************************************************************************************* * * 文件名称 : gui_user.c * 版 本 : V1.0 * 作 者 : OpenRabbit * 说 明 : GUI 与 RTOS 和硬件的交互文件,使用时注意区分 MCU 端和模拟器…...
设计做兼职最好的网站/各网站收录
状态模式又是一个比较难的设计模式 定义如下: 当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。 个人理解:通俗的讲,状态模式就是状态的改变引起了行为的改变,但是,我们只能看到行为的…...
wordpress友情链接激活/百度竞价排名规则
简介 zabbix 是一个基于 WEB 界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案 zabbix 能监视各种网络参数,保证服务器系统的安全运营;并提供灵活的通知机制以让系统管理员快速定位解决存在的各种问题。 Zabbix 主要特点 安装与配置简…...
高品质的网站开发公/永久免费不收费的污染app
公司运营免不了让我们数据做一些临时取数,这些取数有时候是重复的,或者可以做成可配置的。需要开发成界面,供他们选择,自然想到SpringBoot连接Hive,可以把取数做成一键生成,或者让他们自己写sql,…...
泉州网站建设泉州/山东关键词优化联系电话
本周主要复习了高数,感觉掌握了忘的比较快,所以在前几天主要是看了知识点,以及书上的例题,后几天就找了一些题做,物理在下周五考,中间的时间间隔较长,所以准备考完高数再复习。 而且上周的模拟考…...
网站开发主题/百度关键字搜索排名
Ctrl D:将当前页面添加到收藏夹或阅读列表 Ctrl E:在地址栏中执行搜索查询 Ctrl F:在页面上查找 Ctrl H:打开历史记录面板 Ctrl G:打开阅读列表面板 Ctrl I: 打开收藏夹列表面板(测试好像…...