Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > Mysql函数不走索引优化

Mysql使用函数后不走索引怎么优化

作者:怪 咖@

当在MySQL中使用函数时,可能会导致查询不走索引,从而影响性能,本文就介绍一下Mysql使用函数后不走索引怎么优化,感兴趣的可以了解一下

网上很多人说mysql一旦使用函数就不走函数,但是事实真的是如此吗?我先说明,并不是如此的,本篇文章会通过 DAYOFWEEK() substr() 两个函数作为条件查询,看看究竟是否会走索引(其他函数同理),使用函数不走索引的时候又应该如何做sql优化,本篇文章重点是基于这两点进行分析。

一、什么场景下使用函数索引会失效?

测试数据如下:

create_time和name列是都建立了索引的。

DROP TABLE IF EXISTS `demo`;
CREATE TABLE `demo`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `create_time` datetime NULL DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  INDEX `create_time`(`create_time`) USING BTREE,
  INDEX `name`(`name`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
INSERT INTO `demo` VALUES (1, '2023-04-28 10:41:16', 'zhangsan');
INSERT INTO `demo` VALUES (2, '2023-04-01 10:41:22', 'lisi');

DAYOFWEEK() :函数返回日期的工作日索引值,即星期日为1,星期一为2,星期六为7。 这些索引值对应于ODBC标准。

通过下面会发现一个问题,假如是 select * 的情况下是不会走索引的,假如是只返回使用函数的列是会走索引的。

EXPLAIN SELECT * from  demo WHERE dayofweek(create_time) = 6 \G;
EXPLAIN SELECT dayofweek(create_time),create_time from  demo WHERE dayofweek(create_time) = 6 \G;

关于执行计划的解读:

截取字符串语法: substr(obj,start,length)

参数:

通过下面案例会发现,跟上面的案例是一样的,同样是 select * 的情况下是不会走索引的。

EXPLAIN SELECT *  from demo WHERE substr(name,1,3) = 'lis'\G;
EXPLAIN SELECT substr(name,1,3),name,id  from demo WHERE substr(name,1,3) = 'lis'\G;

二、索引失效了应该怎么处理?

1.通过【sql优化】让索引生效

那么问题来了遇到这种查询所有数据使用函数不走索引的我们应该如何优化。通过以下试验发现可以携带id,id是主键的情况下不会导致索引失效!

EXPLAIN SELECT substr(name,1,3),name,id,create_time  from demo WHERE substr(name,1,3) = 'lis'\G;
EXPLAIN SELECT substr(name,1,3),name,id  from demo WHERE substr(name,1,3) = 'lis'\G;

通过以下试验得出结论,假如使用函数作为条件查询,只能返回条件的那一列跟id主键列,一旦返回其他的列就会索引失效!

由此优化方案便出来了,假设我们要查name列当中前三个字母是lis的全行数据,然后我们想让他使用到索引,可以使用嵌套查询的方案:

这里进行提示以下:MySQL的 IN 运算符可以使用索引,但是,有一点需要注意。如果你的IN子句中包含的值很多,那么MySQL可能会选择不使用索引,因为扫描大量的值可能比使用索引更快。这个阈值通常是1000个值,但这个值是可配置的。表内数据太少使用 IN 也不会使用索引!

EXPLAIN SELECT * FROM demo WHERE id in (SELECT id  from demo WHERE substr(name,1,3) = 'lis') \G;

如下案例显示实际上并未使用到索引

上面测试的表当中就两条数据所以显示的in并没有使用索引,如下表内共有一万条数据,然后对主键使用in查询,可以很明显的看到,是使用了索引的。由此可证明in是会使用索引的,只不过mysql会根据权衡利弊到底使用索引快还是不使用索引快。

2.通过【虚拟列】让索引生效

Mysql 5.7 中推出了一个非常实用的功能 虚拟列 Generated (Virtual) Columns

语法: ALTER TABLE 表名称 add column 虚拟列名称 虚拟列类型 GENERATED ALWAYS as (表达式) [VIRTUAL | STORED];

MySQL 在处理 虚拟列存储问题的时候有两种方式:

下面我们基于 substr(name,1,3) 函数来创建一个虚拟列:

ALTER TABLE demo add column virtual_name VARCHAR(5) GENERATED ALWAYS as (substr(name,1,3)) VIRTUAL;

对虚拟列添加索引:

ALTER TABLE `demo`.`demo` 
ADD INDEX `virtual_name`(`virtual_name`) USING BTREE;

这时候就可以直接通过虚拟列来完成查询操作了

 EXPLAIN SELECT *  from demo WHERE virtual_name = 'lis';

三、总结

假如使用函数作为条件查询,只能返回条件的那一列跟id主键列,一旦返回其他的列就会索引失效!针对于使用函数索引失效问题,可以使用嵌套查询来解决,也可以使用虚拟列来解决!

到此这篇关于Mysql使用函数后不走索引怎么优化的文章就介绍到这了,更多相关Mysql函数不走索引优化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文