谈及数据库优化首先声明几个概念(情况):
- 聚集索引
聚集索引是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。一个表只能有一个聚集索引,因为一个表的物理顺序只有一种情况,所以,对应的聚集索引只能有一个。如果某索引不是聚集索引,则表中的行物理顺序与索引顺序不匹配,与非聚集索引相比,聚集索引有着更快的检索速度。 其实理论内容理解有难度的话 直接可以理解为表的主键 oid 其实绝大多数情况下 主键oid就是聚集索引的代表
- 非聚集索引
非聚集索引和聚集索引一样, 同样是采用平衡树作为索引的数据结构。索引树结构中各节点的值来自于表中的索引字段, 假如给user表的name字段加上索引 , 那么索引就是由name字段中的值构成,在数据改变时, DBMS需要一直维护索引结构的正确性。如果给表中多个字段加上索引 , 那么就会出现多个独立的索引结构,每个索引(非聚集索引)互相之间不存在关联 简述就是 多个字段整合 并且这些字段整合的结果不会出现重复的情况 这样的索引一般称为非聚集索引 其实这方面的例子有很多 举例说明 如果是个学生表除了oid 还想有其他形式表示唯一的索引表示 姓名字段重复很正常 甚至加上年纪 班级 性别等字段也不能保证唯一 这时就需要添加其他属性整合作为聚集索引了 譬如 性别 或者某个特定编号 举例并不是特别合理 但是含义应该能表述的清楚吧……emmmmmm
- 覆盖索引
覆盖索引是select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。 理解方式:非聚集复合索引的一种形式,它包括在查询里的Select、Join和Where子句用到的所有列(即建索引的字段正好是覆盖查询条件中所涉及的字段,也即,索引包含了查询正在查找的数据 其实理解起来可以是 这个是一个特殊的 非聚集索引 因为sql的查询和检索条件包含了已经创建的一个索引的所有字段。所以不必读取完整的数据行
- 最左匹配原则
顾名思义:最左优先,以最左边的为起点任何连续的索引都能匹配上。同时遇到范围查询(>、<、between、like)就会停止匹配。 换句话理解就是 你写的sql 使用的字段顺序应该和你创建索引的时候字段的编写顺序一致
- 单表最大创建索引数量
16 innodb引擎下 单表创建索引最大数量为16个 这也就要求了如果我们要创建索引 一定要在高热度场景下设想创建 不要浪费创建数
- sql nocache 缓存
如果我们的数据库支持缓存并且开启缓存的情况下 复杂sql执行经常发生response time 时高时低的情况 这种情况下的处理一定要按照实际场景进行:例如该场景不是高热场景可以不做处理 假如在高热度场景那么就要做一个处理取消缓存拿到正常执行的时间并且优化该内容
- 回表情况
!如果索引的列在select子句中就不需要回表,如果select子句中有大量的非索引列,索引就需要到表中找到相应的列的信息,这就叫回表 解决方案 如果sql是必定要用的高热度场景 那就加索引吧 如果字段可以删减那就删减掉索引中没有的字段 当然第二种情况很少发生 8 change buffer写缓存
采用了敖丙大佬的图 :
要点 :虽然叫change buffer 但是他是持久化的
marge操作 访问数据页会触发执行 系统后台会定期执行 数据库服务关闭也会执行
好处: 减少读磁盘 避免内存占用 提高内存利用率
- 函数操作索引字段
索引字段不能使用函数操作 类似count () str() 等
- 前缀索引
MySQL是支持前缀索引的,也就是说,你可以定义字符串的一部分作为索引。默认地,如果 你创建索引的语句不指定前缀长度,那么索引就会包含整个字符串。 很明显的是 索引也是占用磁盘的那么如果确定某个字段的前n位数据就能保证唯一性的情况下 我们完全可以采用这种方式来达到优化和节约空间的效果 此外 如果字段采用邮箱 例如 www.123456789@qq.com 这种形式的数据 很明显 www. 这部分是没有区分度的 所以我们可以采用截取字符串的形式 再例如如果是地区字段的话 则可以用 reverse()翻转数据来处理
- 条件字段函数操作
日常开发过程中,大家经常对很多字段进行函数操作,如果对日期字段操作,浮点字符操作等 等,大家需要注意的是,如果对字段做了函数计算,就用不上索引了,这是MySQL的规定。 对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树搜索功能。 需要注意的是,优化器并不是要放弃使用这个索引。 比如 select * from tradelog where id + 1 = 10000 就走不上索引,select * from tradelog where id = 9999就可以
- 隐式类型转换
select * from t where id = 1
如果id是字符类型的,1是数字类型的,你用explain会发现走了全表扫描,根本用不上索引,
为啥呢?
因为MySQL底层会对你的比较进行转换,相当于加了 CAST( id AS signed int) 这样的一个函
数,上面说过函数会导致走不上索引。
- Explain
哦…………我是不是忘了什么 调优调优 怎么看优怎么看劣emmm当然是 Explain
| Column | 含义 |
| id | 查询序号 |
| select_type | 查询类型 |
| table | 表名 |
| partitions | 匹配的分区 |
| type | join类型 |
| prossible_keys | 可能会选择的索引 |
| key | 实际选择的索引 |
| key_len | 索引的长度 |
| ref | 与索引作比较的列 |
| rows | 要检索的行数(估算值) |
| filtered | 查询条件过滤的行数的百分比 |
| Extra | 额外信息 |
| select_type 查询的类型,可以是下表的任何一种类型: | |
| select_type | 类型说明 |
| -- | -- |
| SIMPLE | 简单SELECT(不使用UNION或子查询) |
| PRIMARY | 最外层的SELECT |
| UNION | UNION中第二个或之后的SELECT语句 |
| DEPENDENT UNION | UNION中第二个或之后的SELECT语句取决于外面的查询 |
| UNION RESULT | UNION的结果 |
| SUBQUERY | 子查询中的第一个SELECT |
| DEPENDENT | SUBQUERY 子查询中的第一个SELECT, 取决于外面的查询 |
| DERIVED | 衍生表(FROM子句中的子查询) |
| MATERIALIZED | 物化子查询 |
| UNCACHEABLE SUBQUERY | 结果集无法缓存的子查询,必须重新评估外部查询的每一行 |
| UNCACHEABLE UNION | UNION中第二个或之后的SELECT,属于无法缓存的子查询 |