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

 更新时间:2023年08月14日 10:35:09   作者:怪 咖@  
当在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)

参数:

  • obj:从哪个内容中截取,可以是数值或字符串。
  • start:从哪个字符开始截取(1开始,而不是0开始)
  • 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

  • InnoDB支持在虚拟生成的列上建立二级索引。不支持其他索引类型(主键索引)。在虚拟列上定义的二级索引有时也称为“虚拟索引”。
  • 二级索引可以在一个或多个虚拟列上创建,也可以在虚拟列与常规列或存储生成列的组合上创建。包含虚拟列的二级索引可以定义为UNIQUE。
  • 当在虚拟列上使用辅助索引时,由于在INSERT和UPDATE操作期间在辅助索引(辅助又叫二级索引)记录中实现虚拟列值时执行计算,因此需要考虑额外的写成本。即使有额外的写成本,虚拟列上的二级索引也可能比生成的存储列更可取,生成的存储列在集群索引中具体化,从而导致需要更多磁盘空间和内存的更大的表。如果没有在虚拟列上定义二级索引,则会产生额外的读取成本,因为每次检查列的行时都必须计算虚拟列值。

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

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

  • VIRTUAL(默认):不存储列值,在读取表的时候自动计算并返回,不消耗任何存储,这种存储方式仅 InnoDB 支持设置索引。
  • STORED:在插入或更新时计算存储列值,存储的虚拟列需要存储空间,并且 MyISAM 也可以设置索引。

下面我们基于 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函数不走索引优化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL server has gone away的问题解决

    MySQL server has gone away的问题解决

    本文主要介绍了MySQL server has gone away的问题解决,意思就是指client和MySQL server之间的链接断开了,下面就来介绍一下几种原因及其解决方法,感兴趣的可以了解一下
    2024-07-07
  • MySQL中的流式查询及游标查询方式

    MySQL中的流式查询及游标查询方式

    这篇文章主要介绍了MySQL中的流式查询及游标查询方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • MySQL按照汉字的拼音排序简单实例

    MySQL按照汉字的拼音排序简单实例

    下面小编就为大家带来一篇MySQL按照汉字的拼音排序简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • Mysql5.6启动内存占用过高解决方案

    Mysql5.6启动内存占用过高解决方案

    vps的内存为512M,安装好nginx,php等启动起来,mysql死活启动不起来看了日志只看到对应pid被结束了,后跟踪看发现是内存不足被killed;mysql5.6启动内存占用过高怎么办呢,下面小编给大家解答下
    2016-09-09
  • MySQL关闭过程详解和安全关闭MySQL的方法

    MySQL关闭过程详解和安全关闭MySQL的方法

    这篇文章主要介绍了MySQL关闭过程详解和安全关闭MySQL的方法,在了解了关闭过程后,出现故障能迅速定位,本文还给出了安全关闭MySQL的建议及方法,需要的朋友可以参考下
    2014-08-08
  • MySQL数据库CRUD、常见函数及union查询详解

    MySQL数据库CRUD、常见函数及union查询详解

    在MySQL中CRUD是指对数据库进行增加(Create)、读取(Retrieve)、更新(Update)和删除(Delete)这四种基本操作的缩写,这篇文章主要给大家介绍了关于MySQL数据库CRUD、常见函数及union查询的相关资料,需要的朋友可以参考下
    2024-01-01
  • WINDOWS下安装MYSQL教程详解

    WINDOWS下安装MYSQL教程详解

    这篇文章主要介绍了WINDOWS下安装MYSQL教程,本文图文并茂给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-10-10
  • 解析mysql中:单表distinct、多表group by查询去除重复记录

    解析mysql中:单表distinct、多表group by查询去除重复记录

    本篇文章是对mysql中的单表distinct、多表group by查询去除重复记录进行了详细的分析介绍,需要的朋友参考下
    2013-06-06
  • mysql中的limit用法有哪些(推荐)

    mysql中的limit用法有哪些(推荐)

    在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢,mysql已经为我们提供了这样一个功能,尽管语法逻辑很是怪异,这个功能就好比oracle里的rownum,但比mysql提供的这个LIMIT好用、好记和好理解多了,具体内容一起通过本文看看吧
    2017-10-10
  • MySQL面试题讲解之如何设置Hash索引

    MySQL面试题讲解之如何设置Hash索引

    今天研究下mysql中索引,首先我应该知道的是,mysql中不同存储引擎的索引工作方式不一样,并且不是所有的存储引擎都支持所有类型的索引。即使多个存储引擎支持同一种类型的索引,那么他们的实现原理也是不同的,本文将讲解Hash索引该如何设置
    2021-10-10

最新评论