导读

  • 现代大部分的登录系统都支持邮箱、手机号码登录两种方式,那么如何在邮箱或者手机号码这个字符串上建立索引才能保证性能最佳呢?
  • 今天这篇文章就来探讨一下在Mysql中如何给一个字符串加索引才能达到性能最佳。
  • 本文首发于作者的微信公众号【码猿技术专栏】,喜欢的读者关注一下,谢谢!!!

Mysql性能优化:如何给字符串加索引?​mp.weixin.qq.com

  • 陈某将会从「什么是前缀索引」「前缀索引和普通索引的比较」「如何建丽最佳性能的前缀索引」「前缀索引对覆盖索引的影响」这几段来讲。

前缀索引

  • 顾名思义,对于列值较长,比如BLOBTEXTVARCHAR,就 "必须" 使用「前缀索引」,即将值的前一部分作为索引。因为索引的存储也是需要空间的,同样索引太长维护起来也比较困难。
  • 比如我们给User表中的邮箱添加前缀索引,如下:
alter table user add index index1(email(7));

  • 上述语句将email的前7个字符作为索引。

前缀索引和普通索引比较

  • 我们分别将email的全部作为索引和前7个字符作为索引来看看在性能上有什么差异。建立索引的语句如下:
alter table user add index index1(email);alter table user add index index2(email(7));

  • 假设有user表中有这样几条数据(id,name,email):(1,"陈某","chenmou1993@xxx")(2,"张某","chenmou1994@xxx")(3,"李某","chenmou1995@xxx")(4,"王某","chenmou1996@xxx")
  • 对应于index1和index2的索引树如下两张图:
码猿技术专栏
码猿技术专栏
  • 如果执行下面的查询语句,Mysql如何利用索引来查询呢?
select * from user where email="chenmou1995@xxx";

「【1】普通索引的执行过程」

  1. 从index1索引树找到满足索引值是chenmou1995@xxx的这条记录,取得id=2的值;
  2. 到主键上查到主键值是id=2的行,判断email的值是正确的,将这行记录加入结果集;
  3. index1索引树上刚刚查到的位置的下一条记录,发现已经不满足email=chenmou1995@xxx的条件了,循环结束。

这个过程中,只需要回主键索引取一次数据,所以系统认为「只扫描了一行」

「【2】前缀索引的执行过程」

  1. 从index2索引树找到满足索引值是chenmou的记录,找到的第一个是id=1;
  2. 到主键上查到主键值是id=1的行,判断出email的值不是chenmou1995@xxx,这行记录丢弃;
  3. 取index2上刚刚查到的位置的下一条记录,发现仍然是chenmou,取出id=2,再到ID索引上取整行然后判断,这次值对了,将这行记录加入结果集;
  4. 重复上一步,直到在idxe2上取到的值不是chenmou时,循环结束。

在这个过程中,要回主键索引取4次数据,「也就是扫描了4行。」

  • 通过以上查询的对比,很容易就可以发现,「使用前缀索引后,可能会导致查询语句读数据的次数变多。」
  • 但是对于这个查询语句来说,如果建立的前缀索引的长度为13呢?那么满足chenmou1995的记录只有一个,这样就可以直接定位到id=2,此时不但空间缩小了,扫描的行数也减少了。
  • 于是结论就来了:「使用前缀索引,只要定义好长度,就可以做到既节省空间,又不用额外增加太多的查询成本。」
  • 那么如何建立正确的前缀索引才能达到最佳的性能呢?接着往下看................

如何建立最佳性能的前缀索引

  • 通过上述的比较,可以得出一个结论,「建立前缀索引的区分度越高越好,意味着重复的键值越少」
  • 那么如何统计区分度,其实很简单,只需要判断数据库中重复的次数即可。sql如下:
select count(distinct left(email,4))as L4,count(distinct left(email,5))as L5,count(distinct left(email,6))as L6,count(distinct left(email,7))as L7,
from user;

  • 但是如果对于使用前缀区分度不太好的情况,比如,我们国家的身份证号,一共18位,其中前6位是地址码,所以同一个县的人的身份证号前6位一般会是相同的。 这时候如果对身份证号做长度为6的前缀索引的话,这个索引的区分度就非常低了。
  • 按照我们前面说的方法,可能你需要创建长度为12以上的前缀索引,才能够满足区分度要求。
  • 但是,索引选取的越长,占用的磁盘空间就越大,相同的数据页能放下的索引值就越少,搜索的效率也就会越低。
  • 那么,如果我们能够确定业务需求里面只有按照身份证进行等值查询的需求,还有没有别的处理方法呢?这种方法,既可以占用更小的空间,也能达到相同的查询效率。现在简单的介绍一种解决此种问题的方式,当然方法肯定不止一种,如下:

「【1】倒序存储」

如果你存储身份证号的时候把它倒过来存,每次查询的时候,你可以这么写:

select field_list from t where id_card = reverse('输入的身份证号');

由于身份证号的「最后6位」没有地址码这样的重复逻辑,所以最后这6位很可能就提供了足够的区分度。当然了,实践中你不要忘记使用count(distinct)方法去做个验证。

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

  • 前缀索引会导致覆盖索引失效,查询语句如下:
select id,name from user where email="chenmou1995@xxx";

  • 由于使用了前缀索引,因此必须会「回表」验证查询到的时候正确,此处使用了覆盖索引也是无效的。
  • 也就是说,使用前缀索引就用不上覆盖索引对查询性能的优化了,这也是你在选择是否使用前缀索引时需要考虑的一个因素。

总结

  • 如何给字符串加索引是一个需要考量的问题,陈某在这里给出如下的建议:
  1. 如果字符串长度很短,建议直接用全部作为索引。
  2. 使用前缀索引注意分析区分度,区分度越高越好。
  3. 使用前缀索引需要考虑覆盖索引失效的问题。

distinct性能问题_Mysql性能优化:如何给字符串加索引?相关推荐

  1. leftjoin多了性能下降_MySQL 性能优化总结

    作者 | 如果耐,请真耐 出处 : https://www.cnblogs.com/joeyJss/p/11096597.html 1,Sql优化概要: Sql优化就是指语句在执行的时候效率不是那么乐 ...

  2. mysql 批量加索引_mysql优化:按期删数据 + 批量insert + 字符串加索引为何很傻

    嗯,犯了一个很低级的错误,最近暴露出来了.html 背景:mysql 1. 内部平台,接口间断性无返回,查询日志注意到失败时,接口耗时达到4000+(正常状态:100+ms)git 2. 增长日志打点 ...

  3. mysql 索引 insert_mysql优化:定期删数据 + 批量insert + 字符串加索引为什么很傻

    嗯,犯了一个很低级的错误,最近暴露出来了. 背景: 1. 内部平台,接口间断性无返回,查询日志注意到失败时,接口耗时达到4000+(正常状态:100+ms) 2. 增加日志打点,在关键步骤插入时间戳, ...

  4. mysql proxy性能差_mysql性能的检查和优化方法

    mysql在遇到严重性能问题时,一般都有这么几种可能: 1.索引没有建好; 2.sql写法过于复杂; 3.配置错误; 4.机器实在负荷不了; 1.索引没有建好 如果看到mysql消耗的cpu很大,可以 ...

  5. mysql执行计划中 性能最好_MySQL性能优化-explain执行计划

    explain用于获取查询执行计划信息, 一.语法 只需要在select前加上explain即可,如: mysql> explain select 1; +----+-------------+ ...

  6. mysql 性能问题_mysql性能问题

    性能优化的目的是什么呢?(合理利用可利用的资源) 性能优化的方向: 硬件方面:CPU.内存.IO.网络.硬盘.显卡 软件方面:mysql这个软件内部优化,比如sql.算法,一些配置 项目方面:需求设计 ...

  7. mysql 性能问题_mysql 性能问题

    1.场景,模拟一天的数据,每个10秒,遍历1000个设备,每个设备模拟一个实时数据,总的数据量为:24*60*60/10*1000 = 864万条记录. 2.采用策略,对时间分段,拼接sql语句查询, ...

  8. 哪里的mysql性能监控_mysql性能监控工具Innotop简介及配置

    # wget http://innotop.googlecode.com/files/innotop-1.9.0.tar.gz # tar -zxvf innotop-1.9.0.tar.gz # c ...

  9. mysql 性能状态_MySQL性能状态查看方式

    1. QPS(每秒Query量) QPS = Questions(or Queries) / seconds mysql > show global status like 'Question% ...

最新文章

  1. 运动目标的背景建模-混合高斯背景建模和KNN模型建模的OpenCV代码实现
  2. mininet编程实现交换机规则的插入、删除与修改。_Mysql事务隔离以及MVCC实现原理...
  3. 协同工作php,PHPOA:灵活、高效、协同,让企业高效运转
  4. [转载] python元组 tuple
  5. c语言筛选法求100之内素数,用筛选法求100之内的素数。
  6. 闪电网络开启BTC支付时代?他们不同意
  7. win 10 企业版 激活
  8. 任玉刚【Android开发艺术探索】读后笔记三
  9. Java SE 正则表达式
  10. Unsupervised Super Resolution Reconstruction of Traffic Surveillance Vehicle Images
  11. Codeforces 592 A. PawnChess 【Codeforces Round #328 (Div. 2)】
  12. python paramiko包 ssh报错No existing session 调试记录
  13. Java 开发flink流/批处理程序
  14. 软件测试拿了几个20K offer,分享一波面经
  15. linux curse库函数,curse
  16. Windows 11正式发布,新功能太绝了!
  17. 国网智能电表视在功率kVA、有功功率Kw、无功功率kVar的概念含义及区别
  18. python时间戳datetime取出年、月、日、时
  19. hfs服务器 linux,(转)linux读写HFS+分区
  20. linux中cmd是什么文件格式,CMD 文件扩展名: 它是什么以及如何打开它?

热门文章

  1. docker compose安装_docker stack,docker-compose前世今生
  2. vba 修改文本文档 指定行_再说For Each循环——无论Python还是VBA都要看
  3. Win10 开启移动热点 WiFi 的简单方法
  4. zookeeper注册中心安装(单机版)
  5. web页面的回流,认识与避免
  6. 拼接sql语句参数绑定
  7. 将Tomcat配置到你的mac电脑上,命令行启动tomcat
  8. spring-boot spring-security-oauth2
  9. JS键盘KEYCODE值参考
  10. php 修改最大上传,php 修改上传文件大小限制实例详解