谢邀,利益相关。大多数互联网应用场景都是读多写少,业务逻辑更多分布在写上。对读的要求大概就是要快。那么都有什么原因会导致我们完成一次出色的慢查询呢?
在数据量不是很大时,大多慢查询可以用索引解决,大多慢查询也因为索引不合理而产生。
MySQL 索引基于 B 树,这句话相信面试都背烂了,接着就可以问最左前缀索引、 B 树和各种树了。
说到最左前缀,实际就是组合索引的使用规则,使用合理组合索引可以有效的提高查询速度,为什么呢?
因为索引下推。如果查询条件包含在了组合索引中,比如存在组合索引(a,b),查询到满足 a 的记录后会直接在索引内部判断 b 是否满足,减少回表次数。同时,如果查询的列恰好包含在组合索引中,即为覆盖索引,无需回表。索引规则估计都知道,实际开发中也会创建和使用。问题可能更多的是:为什么建了索引还慢?
建了索引还慢,多半是索引失效(未使用),可用 explain 分析。索引失效常见原因有 :
如果要 MySQL 给一个理由,还是那棵 B 树。
当在 查询 where = 左侧使用表达式或函数时,如字段 A 为字符串型且有索引, 有 where length(a) = 6查询,这时传递一个 6 到 A 的索引树,不难想象在树的第一层就迷路了。
隐式类型转换和隐式字符编码转换也会导致这个问题。
至于 Like 语句 % 开头、字符串未加 ’’ 原因基本一致,MySQL 认为对索引字段的操作可能会破坏索引有序性就机智的优化掉了。
不过,对于如性别这种区分度过低的字段,索引失效就不是因为这个原因。
为什么索引区分度低的字段不要加索引。盲猜效率低,效率的确低,有时甚至会等于没加。
对于非聚簇索引,是要回表的。假如有 100 条数据,在 sex 字段建立索引,扫描到 51 个 male,需要再回表扫描 51 行。还不如直接来一次全表扫描呢。
所以,InnoDB 引擎对于这种场景就会放弃使用索引,至于区分度多低多少会放弃,大致是某类型的数据占到总的 30% 左右时,就会放弃使用该字段的索引,有兴趣可以试一下。
前面说到大多慢查询都源于索引,怎么建立并用好索引。这里有一些简单的规则。
有时,建立了猛一看挺正确的索引,但事情却没按计划发展。就像“为啥 XXX 有索引,根据它查询还是慢查询”。
此刻没准要自信点:我的代码不可能有 BUG,肯定是 MySQL 出了问题。MySQL 的确可能有点问题。
这种情况常见于建了一大堆索引,查询条件一大堆。没使用你想让它用的那一个,而是选了个区分度低的,导致过多的扫描。造成的原因基本有两个:
但根据我浅薄的经验来看,更可能是因为你建了些没必要的索引导致的。不会真有人以为 MySQL 没自己机灵吧?
除了上面这些索引原因外,还有下面这些不常见或者说不好判断的原因存在。
在 MySQL 5.5 版本中引入了 MDL,对一个表做 CRUD 操作时,自动加 MDL 读锁;对表结构做变更时,加 MDL 写锁。读写锁、写锁间互斥。
当某语句拿 MDL 写锁就会阻塞 MDL 读锁,可以使用show processlist命令查看处于Waiting for table metadata lock状态的语句。
flush 很快,大多是因为 flush 命令被别的语句堵住,它又堵住了 select 。通过show processlist命令查看时会发现处于Waiting for table flush状态。
某事物持有写锁未提交。
InnoDB 默认级别是可重复读。设想一个场景:事物 A 开始事务,事务 B 也开始执行大量更新。B 率先提交, A 是当前读,就要依次执行 undo log ,直到找到事务 B 开始前的值。
在未二次开发的 MYSQL 中,上亿的表肯定算大表,这种情况即使在索引、查询层面做到了较好实现,面对频繁聚合操作也可能会出现 IO 或 CPU 瓶颈,即使是单纯查询,效率也会下降。
且 Innodb 每个 B 树节点存储容量是 16 KB,理论上可存储 2kw 行左右,这时树高为3层。我们知道,innodb_buffer_pool 用来缓存表及索引,如果索引数据较大,缓存命中率就堪忧,同时 innodb_buffer_pool 采用 LRU 算法进行页面淘汰,如果数据量过大,对老或非热点数据的查询可能就会把热点数据给挤出去。
所以对于大表常见优化即是分库分表和读写分离了。
是分库还是分表呢?这要具体分析。
水平即切分数据,分散原有数据到更多的库表中。
垂直即按照业务对库,按字段对表切分。
工具方面有 sharding-sphere、TDDL、Mycat。动起手来需要先评估分库、表数,制定分片规则选 key,再开发和数据迁移,还要考虑扩容问题。
实际运行中,写问题不大,主要问题在于唯一 ID 生成、非 partition key 查询、扩容。
当然,如果分库还会面临事务一致性和跨库 join 等问题。
分表针对大表解决 CPU 瓶颈,分库解决 IO 瓶颈,二者将存储压力解决了。但查询还不一定。
如果落到 DB 的 QPS 还是很高,且读远大于写 ,就可以考虑读写分离,基于主从模式将读的压力分摊,避免单机负载过高,同时也保证了高可用,实现了负载均衡。
主要问题有过期读和分配机制。
以上列举了 MySQL 常见慢查询原因和处理方法,介绍了应对较大数据场景的常用方法。
分库分表和读写分离是针对大数据或并发场景的,同时也为了提高系统的稳定和拓展性。但也不是所有的问题都最适合这么解决。
前文有提到对于关键字查询可以使用 ES。那接着聊聊 ES 。
ES 是基于 Lucene 的近实时分布式搜索引擎。使用场景有全文搜索、NoSQL Json 文档数据库、监控日志、数据采集分析等。
对非数据开发来说,常用的应该就是全文检索和日志了。ES 的使用中,常和 Logstash, Kibana 结合,也成为 ELK 。先来瞧瞧日志怎么用的。
下面是我司日志系统某检索操作:打开 Kibana 在 Discover 页面输入格式如 “xxx” 查询。
该操作可以在 Dev Tools 的控制台替换为:
GET yourIndex/_search{ "from" : 0, "size" : 10, "query" : { "match_phrase" : { "log" : "xxx" } }}
什么意思?Discover 中加上 “” 和 console 中的 match_phrase 都代表这是一个短语匹配,意味着只保留那些包含全部搜索词项,且位置与搜索词项相同的文档。
在 ES 7.0 之前存储结构是 Index -> Type -> Document,按 MySQL 对比就是 database – table – id(实际这种对比不那么合理)。7.0 之后 Type 被废弃了,就暂把 index 当做 table 吧。
在 Dev Tools 的 Console 可以通过以下命令查看一些基本信息。也可以替换为 crul 命令。
1. GET /_cat/health?v&pretty:查看集群健康状态2. GET /_cat/shards?v :查看分片状态3. GET yourindex/_mapping :index mapping结构4. GET yourindex/_settings :index setting结构5. GET /_cat/indices?v :查看当前节点所有索引信息
重点是 mapping 和 setting ,mapping 可以理解为 MySQL 中表的结构定义,setting 负责控制如分片数量、副本数量。
以下是截取了某日志 index 下的部分 mapping 结构,ES 对字符串类型会默认定义成 text ,同时为它定义一个叫做 keyword 的子字段。这两的区别是:text 类型会进行分词, keyword 类型不会进行分词。
"******": { "mappings": { "doc": { "properties": { "appname": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } }
分词是什么意思?看完 ES 的索引原理你就 get 了。
ES 基于倒排索引。嘛意思?传统索引一般是以文档 ID 作索引,以内容作为记录。倒排索引相反,根据已有属性值,去找到相应的行所在的位置,也就是将单词或内容作为索引,将文档 ID 作为记录。
下图是 ES 倒排索引的示意图,由 Term index,Team Dictionary 和 Posting List 组成。
图中的 Ada、Sara 被称作 term,其实就是分词后的词了。如果把图中的 Term Index 去掉,是不是有点像 MySQL 了?Term Dictionary 就像二级索引,但 MySQL 是保存在磁盘上的,检索一个 term 需要若干次的 random access 磁盘操作。
而 ES 在 Term Dictionary 基础上多了层 Term Index ,它以 FST 形式保存在内存中,保存着 term 的前缀,借此可以快速的定位到 Term dictionary 的本 term 的 offset 。而且 FST 形式和 Term dictionary 的 block 存储方式都很节省内存和磁盘空间。
到这就知道为啥快了,就是因为有了内存中的 Term Index , 它为 term 的索引 Term Dictionary 又做了一层索引。
不过,也不是说 ES 什么查询都比 MySQL 快。检索大致分为两类。
ES 的索引存储的就是分词排序后的结果。比如图中的 Ada,在 MySQL 中
免责声明:本站发布的内容(图片、视频和文字)以原创、来自本网站内容采集于网络互联网转载等其它媒体和分享为主,内容观点不代表本网站立场,如侵犯了原作者的版权,请告知一经查实,将立刻删除涉嫌侵权内容,联系我们QQ:712375056,同时欢迎投稿传递力量。
Copyright © 2009-2022 56dr.com. All Rights Reserved. 特网科技 特网云 版权所有 特网科技 粤ICP备16109289号
域名注册服务机构:阿里云计算有限公司(万网) 域名服务机构:烟台帝思普网络科技有限公司(DNSPod) CDN服务:阿里云计算有限公司 百度云 中国互联网举报中心 增值电信业务经营许可证B2
建议您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流浏览器浏览本网站