mysql join的实现原理及优化思路
2012-07-31 09:25
274 查看
join的实现原理
join的实现是采用Nested Loop Join算法,就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果有多个join,则将前面的结果集作为循环数据,再一次作为循环条件到后一个表中查询数据。
接下来通过一个三表join查询来说明mysql的Nested Loop Join的实现方式。
使用explain看看执行计划:
结果如下:
从结果可以看出,explain选择user_group作为驱动表,首先通过索引user_group_uid_ind来进行const条件的索引ref查找,然后用user_group表中过滤出来的结果集group_id字段作为查询条件,对group_message循环查询,然后再用过滤出来的结果集中的group_message的id作为条件与group_message_content的group_msg_id进行循环比较查询,获得最终的结果。
这个过程可以通过如下代码来表示:
for each record g_rec in table user_group that g_rec.user_id=1{
for each record m_rec in group_message that m_rec.group_id=g_rec.group_id{
for each record c_rec in group_message_content that c_rec.group_msg_id=m_rec.id
pass the (g_rec.user_id, m_rec.subject, c_rec.content) row
combination to output;
}
}
如果去掉group_message_content表上面的group_msg_id字段的索引,执行计划会有所不一样。
得到的执行计划如下:
因为删除了索引,所以group_message_content的访问从ref变成了ALL,keys相关的信息也变成了NULL,Extra信息也变成了Using Where和Using join buffer,也就是说需要获取content内容只能通过对全表的数据进行where过滤才能获取。Using join buffer是指使用到了Cache,只有当join类型为ALL,index,rang或者是index_merge的时候才会使用join buffer,它的使用过程可以用下面代码来表示:
for each record g_rec in table user_group{
for each record m_rec in group_message that m_rec.group_id=g_rec.group_id{
put (g_rec, m_rec) into the buffer
if (buffer is full)
flush_buffer();
}
}
flush_buffer(){
for each record c_rec in group_message_content that c_rec.group_msg_id = c_rec.id{
for each record in the buffer
pass (g_rec.user_id, m_rec.subject, c_rec.content) row combination to output;
}
empty the buffer;
}
在实现过程中可以看到把user_group和group_message的结果集放到join buffer中,而不用每次user_group和group_message关联后马上和group_message_content关联,这也是没有必要的;需要注意的是join buffer中只保留查询结果中出现的列值,它的大小不依赖于表的大小,我们在伪代码中看到当join buffer被填满后,mysql将会flush buffer。
join语句的优化
1. 用小结果集驱动大结果集,尽量减少join语句中的Nested Loop的循环总次数;
2. 优先优化Nested Loop的内层循环,因为内层循环是循环中执行次数最多的,每次循环提升很小的性能都能在整个循环中提升很大的性能;
3. 对被驱动表的join字段上建立索引;
4. 当被驱动表的join字段上无法建立索引的时候,设置足够的Join Buffer Size。
join的实现是采用Nested Loop Join算法,就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果有多个join,则将前面的结果集作为循环数据,再一次作为循环条件到后一个表中查询数据。
接下来通过一个三表join查询来说明mysql的Nested Loop Join的实现方式。
select m.subject msg_subject, c.content msg_content from user_group g,group_message m,group_message_content c where g.user_id = 1 and m.group_id = g.group_id and c.group_msg_id = m.id
使用explain看看执行计划:
explain select m.subject msg_subject, c.content msg_content from user_group g,group_message m, group_message_content c where g.user_id = 1 and m.group_id = g.group_id and c.group_msg_id = m.id\G;
结果如下:
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: g type: ref possible_keys: user_group_gid_ind,user_group_uid_ind,user_group_gid_uid_ind key: user_group_uid_ind key_len: 4 ref: const rows: 2 Extra: *************************** 2. row *************************** id: 1 select_type: SIMPLE table: m type: ref possible_keys: PRIMARY,idx_group_message_gid_uid key: idx_group_message_gid_uid key_len: 4 ref: g.group_id rows: 3 Extra: *************************** 3. row *************************** id: 1 select_type: SIMPLE table: c type: ref possible_keys: idx_group_message_content_msg_id key: idx_group_message_content_msg_id key_len: 4 ref: m.id rows: 2 Extra:
从结果可以看出,explain选择user_group作为驱动表,首先通过索引user_group_uid_ind来进行const条件的索引ref查找,然后用user_group表中过滤出来的结果集group_id字段作为查询条件,对group_message循环查询,然后再用过滤出来的结果集中的group_message的id作为条件与group_message_content的group_msg_id进行循环比较查询,获得最终的结果。
这个过程可以通过如下代码来表示:
for each record g_rec in table user_group that g_rec.user_id=1{
for each record m_rec in group_message that m_rec.group_id=g_rec.group_id{
for each record c_rec in group_message_content that c_rec.group_msg_id=m_rec.id
pass the (g_rec.user_id, m_rec.subject, c_rec.content) row
combination to output;
}
}
如果去掉group_message_content表上面的group_msg_id字段的索引,执行计划会有所不一样。
drop index idx_group_message_content_msg_id on group_message_content;
explain select m.subject msg_subject, c.content msg_content from user_group g,group_message m, group_message_content c where g.user_id = 1 and m.group_id = g.group_id and c.group_msg_id = m.id\G;
得到的执行计划如下:
*************************** 1. row *************************** id: 1 select_type: SIMPLE table: g type: ref possible_keys: user_group_uid_ind key: user_group_uid_ind key_len: 4 ref: const rows: 2 Extra: *************************** 2. row *************************** id: 1 select_type: SIMPLE table: m type: ref possible_keys: PRIMARY,idx_group_message_gid_uid key: idx_group_message_gid_uid key_len: 4 ref: g.group_id rows: 3 Extra: *************************** 3. row *************************** id: 1 select_type: SIMPLE table: c type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 96 Extra:Using where;Using join buffer
因为删除了索引,所以group_message_content的访问从ref变成了ALL,keys相关的信息也变成了NULL,Extra信息也变成了Using Where和Using join buffer,也就是说需要获取content内容只能通过对全表的数据进行where过滤才能获取。Using join buffer是指使用到了Cache,只有当join类型为ALL,index,rang或者是index_merge的时候才会使用join buffer,它的使用过程可以用下面代码来表示:
for each record g_rec in table user_group{
for each record m_rec in group_message that m_rec.group_id=g_rec.group_id{
put (g_rec, m_rec) into the buffer
if (buffer is full)
flush_buffer();
}
}
flush_buffer(){
for each record c_rec in group_message_content that c_rec.group_msg_id = c_rec.id{
for each record in the buffer
pass (g_rec.user_id, m_rec.subject, c_rec.content) row combination to output;
}
empty the buffer;
}
在实现过程中可以看到把user_group和group_message的结果集放到join buffer中,而不用每次user_group和group_message关联后马上和group_message_content关联,这也是没有必要的;需要注意的是join buffer中只保留查询结果中出现的列值,它的大小不依赖于表的大小,我们在伪代码中看到当join buffer被填满后,mysql将会flush buffer。
join语句的优化
1. 用小结果集驱动大结果集,尽量减少join语句中的Nested Loop的循环总次数;
2. 优先优化Nested Loop的内层循环,因为内层循环是循环中执行次数最多的,每次循环提升很小的性能都能在整个循环中提升很大的性能;
3. 对被驱动表的join字段上建立索引;
4. 当被驱动表的join字段上无法建立索引的时候,设置足够的Join Buffer Size。
相关文章推荐
- MySQL join的实现原理及优化思路
- MySQL Query 的优化—Join的实现原理及优化思路
- mysql join的实现原理及优化思路
- Join的实现原理及优化思路
- Join的实现原理及优化思路
- 用冒泡的方式对数组进行排序, 并写出对应的优化后的代码实现。(重点写思路、原理)
- 用选择的方式对数组进行排序,并写出对应的优化后的代码实现。(重点写思路、原理)
- 读《MySQL性能调优与架构设计》笔记之Join 的实现原理及优化思路
- 转 Join的实现原理及优化思路
- join的实现原理与优化思路
- Android 颜色渲染(二) 颜色区域划分原理与实现思路
- MySQL Order By实现原理分析和Filesort优化
- Android 颜色渲染(二) 颜色区域划分原理与实现思路
- 使用临界段原理实现优化的进程间同步对象-原理和实现
- 谈一款MOBA类游戏《码神联盟》的服务端架构设计与实现(更新优化思路)
- 【web前端性能优化】css sprite(图片精灵)-雪碧图实现原理
- ListView异步加载图片实现思路(优化篇)
- 多线程系列 - 基础篇02 - 同步的原理 及 锁在应用层的优化思路 60%
- Android应用启动优化:一种DelayLoad的实现和原理(上篇)
- MySQL-join的实现原理、优化及NLJ算法