mysql索引优化实践
来源:SegmentFault
时间:2023-02-16 15:26:32 399浏览 收藏
来到golang学习网的大家,相信都是编程学习爱好者,希望在这里学习数据库相关编程知识。下面本篇文章就来带大家聊聊《mysql索引优化实践》,介绍一下MySQL、sql优化,希望对大家的知识积累有所帮助,助力实战开发!
sql执行方案计算
mysql底层会对sql进行查询优化,依据各个方案所产生的cost成本计算最优执行方案,sql的最终执行方案是否走了索引,抑或为什么没有走索引的原因可以用trace工具来分析。
开启trace:
mysql> set session optimizer_trace="enabled=on",end_markers_in_json=on; ‐‐开启trace mysql> select * from user where name > 'a' order by age; mysql> SELECT * FROM information_schema.OPTIMIZER_TRACE;
查看trace字段:
6 { 7 "steps": [ 8 { 9 "join_preparation": { ‐‐第一阶段:SQL准备阶段,格式化sql 10 "select#": 1, 11 "steps": [ 12 { 13 "expanded_query": "/* select#1 */ select `employees`.`id` AS `id`,`employees`.`name` AS `name`,`empl oyees`.`age` AS `age`,`employees`.`position` AS `position`,`employees`.`hire_time` AS `hire_time` from `employees` where (`employees`.`name` > 'a') order by `employees`.`position`" 14 } 15 ] /* steps */ 16 } /* join_preparation */ 17 }, 18 { 19 "join_optimization": { ‐‐第二阶段:SQL优化阶段 20 "select#": 1, 21 "steps": [ 22 { 23 "condition_processing": { ‐‐条件处理 24 "condition": "WHERE", 25 "original_condition": "(`employees`.`name` > 'a')", 26 "steps": [ 27 { 28 "transformation": "equality_propagation", 29 "resulting_condition": "(`employees`.`name` > 'a')" 30 }, 31 { 32 "transformation": "constant_propagation", 33 "resulting_condition": "(`employees`.`name` > 'a')" 34 }, 35 { 36 "transformation": "trivial_condition_removal", 37 "resulting_condition": "(`employees`.`name` > 'a')" 38 } 39 ] /* steps */ 40 } /* condition_processing */ 41 }, 42 { 43 "substitute_generated_columns": { 44 } /* substitute_generated_columns */ 45 }, 46 { 47 "table_dependencies": [ ‐‐表依赖详情 48 { 49 "table": "`employees`", 50 "row_may_be_null": false, 51 "map_bit": 0, 52 "depends_on_map_bits": [ 53 ] /* depends_on_map_bits */ 54 } 55 ] /* table_dependencies */ 56 }, 57 { 58 "ref_optimizer_key_uses": [ 59 ] /* ref_optimizer_key_uses */ 60 }, 61 { 62 "rows_estimation": [ ‐‐预估表的访问成本 63 { 64 "table": "`employees`", 65 "range_analysis": { 66 "table_scan": { ‐‐全表扫描情况 67 "rows": 10123, ‐‐扫描行数 68 "cost": 2054.7 ‐‐查询成本 69 } /* table_scan */, 70 "potential_range_indexes": [ ‐‐查询可能使用的索引 71 { 72 "index": "PRIMARY", ‐‐主键索引 73 "usable": false, 74 "cause": "not_applicable" 75 }, 76 { 77 "index": "idx_name_age_position", ‐‐辅助索引 78 "usable": true, 79 "key_parts": [ 80 "name", 81 "age", 82 "position", 83 "id" 84 ] /* key_parts */ 85 } 86 ] /* potential_range_indexes */, 87 "setup_range_conditions": [ 88 ] /* setup_range_conditions */, 89 "group_index_range": { 90 "chosen": false, 91 "cause": "not_group_by_or_distinct" 92 } /* group_index_range */, 93 "analyzing_range_alternatives": { ‐‐分析各个索引使用成本 94 "range_scan_alternatives": [ 95 { 96 "index": "idx_name_age_position", 97 "ranges": [ 98 "a 'a')", 149 "attached_conditions_computation": [ 150 ] /* attached_conditions_computation */, 151 "attached_conditions_summary": [ 152 { 153 "table": "`employees`", 154 "attached": "(`employees`.`name` > 'a')" 155 } 156 ] /* attached_conditions_summary */ 157 } /* attaching_conditions_to_tables */ 158 }, 159 { 160 "clause_processing": { 161 "clause": "ORDER BY", 162 "original_clause": "`employees`.`position`", 163 "items": [ 164 { 165 "item": "`employees`.`position`" 166 } 167 ] /* items */, 168 "resulting_clause_is_simple": true, 169 "resulting_clause": "`employees`.`position`" 170 } /* clause_processing */ 171 }, 172 { 173 "reconsidering_access_paths_for_index_ordering": { 174 "clause": "ORDER BY", 175 "steps": [ 176 ] /* steps */, 177 "index_order_summary": { 178 "table": "`employees`", 179 "index_provides_order": false, 180 "order_direction": "undefined", 181 "index": "unknown", 182 "plan_changed": false 183 } /* index_order_summary */ 184 } /* reconsidering_access_paths_for_index_ordering */ 185 }, 186 { 187 "refine_plan": [ 188 { 189 "table": "`employees`" 190 } 191 ] /* refine_plan */ 192 } 193 ] /* steps */ 194 } /* join_optimization */ 195 }, 196 { 197 "join_execution": { ‐‐第三阶段:SQL执行阶段 198 "select#": 1, 199 "steps": [ 200 ] /* steps */ 201 } /* join_execution */ 202 } 203 ] /* steps */ 204 } 205 206 结论:全表扫描的成本低于索引扫描,所以mysql最终选择全表扫描 207 208 mysql> select * from employees where name > 'zzz' order by position; 209 mysql> SELECT * FROM information_schema.OPTIMIZER_TRACE; 210 211 查看trace字段可知索引扫描的成本低于全表扫描,所以mysql最终选择索引扫描 212
(↑↑↑引用↑↑↑)
mysql> set session optimizer_trace="enabled=off"; ‐‐关闭trace
索引优化
核心1:索引排序分为Using index和Using filesort,其中Using filesort较慢,如果出现则需要考虑使用Using index进行优化。
Using filesort的出现原因是因为内存大小不足,无法存放需要排序的值,所以采用了外部文件排序,如果能放得下则会采取Using index。
filesort的单路排序和双路排序 单路排序:单路排序是一次性取出所有的数据在内存中排序 双路排序:双路排序是只取出需要排序的字段和索引ID,排序后再根据id回表取出所有的数据 有点类似于聚集索引和辅助索引的查询方式区别 MySQL 通过比较系统变量 max_length_for_sort_data(默认1024字节) 的大小和需要查询的字段总大小来 判断使用哪种排序模式。 如果 字段的总长度小于max_length_for_sort_data ,那么使用 单路排序模式; 如果 字段的总长度大于max_length_for_sort_data ,那么使用 双路排序模式。 简单说就是看放不放得下,放得下就直接都取出来,放不下就只取一部分
核心2:所有的优化原则都是基于B+tree构建的索引树,辅助索引的检索优先于聚集索引,组合索引的最左前缀原则意味着组合原因里每一个索引字段都是前面那个索引字段的细分,必须依序执行,否则无法成功索引。
核心3:范围查询应该放在查询的最后一位,一般来说范围查询后的查询条件无法匹配到对应的索引,如果有多个范围查询可以考虑使用冗余的常量字段来替代范围查询。
核心4:如果非必要,在查询时尽量使用覆盖索引代替select * from 的方式来查找,可以大大提升查询效率。
索引设计原则
1、代码先行,索引后上
2、联合索引尽量覆盖条件
3、不要在小基数字段上建立索引
4、长字符串我们可以采用前缀索引
5、where与order by冲突时优先where
6、基于慢sql查询做优化
Order by与Group by优化
使用级联索引可以使order by和group by的执行速度大幅度加快,但不能违背最左前缀法则,条件和orderby或者groupby必须以索引建立的顺序进行查询。
唯一的例外是
select * from user where name='a' and age=12 order by height,age;
user表中存在一个name,height,age的索引,以上查询是可以走索引的,因为age的值12是常量,在执行的时候会被优化,所以最终走的索引依旧是name,height,age。
分页查询优化
limit分页的执行原理:
select * from user limit 100,10
以上查询mysql会先查询出表中的前100条数据,然后舍弃掉,再查询10条,所以一共是查询了110条数据,在数据量过大时效率会比较慢,可以采用以下优化方式。
select * from user u inner join (select id from user order by uid limit 90000,5) ud on u.id = ud.id;
这种查询方式只查ID,然后使用ID的主键索引进行回表检索,会大幅度减少查询的数据量,在大数据查询时候有效的避免了filesort方式的排序。
Join关联查询优化
join的查询方式分两种
1.嵌套循环链接(Nested-Loop Join(NLJ))
1. 从驱动表中读取一行数据(如果驱动表表有查询过滤条件的,会从过滤结果里取出一行数据); 2. 从第 1 步的数据中,取出关联字段,到被驱动表中查找; 3. 取出被驱动表中满足条件的行,跟驱动表中获取到的结果合并,作为结果返回给客户端; 4. 重复上面 3 步。
2.基于块的嵌套循环链接(Block Nested-Loop Join(BNL))
1. 把驱动表的所有数据放入到 join_buffer 中 2. 把被驱动表中每一行取出来,跟 join_buffer 中的数据做对比 3. 返回满足 join 条件的数据 ps:如果join_buffer中放不下则分批把驱动表中的数据放入进去
mysql优化时inner join会自动选取较小的表作为驱动表,但并非100%选择正确
left join 左侧为驱动表
right join 右侧为驱动表
优化重点:
关联字段加索引,让mysql做join操作时尽量选择NLJ算法
小表驱动大表,写多表连接sql时如果明确知道哪张表是小表可以用straight_join写法固定连接驱动方式,省去
mysql优化器自己判断的时间
in和exsits优化
优化重点:小表驱动大表
count(*)查询优化
count(*)是最快的查询总数的函数,执行效率如下:
字段有索引:count(*)≈count(1)>count(字段)>count(主键 id) //字段有索引,count(字段)统计走二级索引,二 级索引存储数据比主键索引少,所以count(字段)>count(主键 id) 字段无索引:count(*)≈count(1)>count(主键 id)>count(字段) //字段没有索引count(字段)统计走不了索引, count(主键 id)还可以走主键索引,所以count(主键 id)>count(字段)
本篇关于《mysql索引优化实践》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于数据库的相关知识,请关注golang学习网公众号!
-
499 收藏
-
244 收藏
-
235 收藏
-
157 收藏
-
101 收藏
-
259 收藏
-
411 收藏
-
476 收藏
-
312 收藏
-
244 收藏
-
195 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习