ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

MySQL join的自动优化

2021-04-28 21:34:04  阅读:166  来源: 互联网

标签:join PRIMARY tid MySQL test table NULL 优化


MySQL的多表Join查询是会自动优化顺序的,本文将以一个实例讲述。

1、首先,编写一个建表脚本

[roo@localhost test]$ vi createA.sql
use test;
DROP PROCEDURE IF EXISTS PcreateA;
drop table if exists A;
drop table if exists B;
drop table if exists C;
create table A(
     aid int(11) primary key,
     title varchar(16),
     content varchar(16),
     uid int(11),
     tid int(11)
);
create table B(
     uid int(11) primary key,
     uname varchar(16)
);
create table C(
    tid int(11) primary key,
    tname varchar(16),
    age int(11)
);
DELIMITER //
CREATE procedure PcreateA() # 创建无参存储过程
BEGIN
  DECLARE i INT default 0;
  WHILE i<40000 DO # 结束循环的条件: 当i大于n时跳出while循环
      INSERT INTO A VALUES(i,concat("title",i),'content', i%4000, i%100);  # 往表添数据
      SET i = i+1;    # 循环一次,i加1
  END WHILE;  # 结束while循环
  SELECT count(*) FROM A; # 查看表数据

  set i=0;
  WHILE i<8000 DO # 结束循环的条件: 当i大于n时跳出while循环
      INSERT INTO B VALUES(i,concat('uname',i));  # 往表添数据
      SET i = i+1;    # 循环一次,i加1
  END WHILE;  # 结束while循环
  SELECT count(*) FROM B; # 查看表数据

  set i=0;
  WHILE i<200 DO # 结束循环的条件: 当i大于n时跳出while循环
      INSERT INTO C VALUES(i,concat('tname',i),i%10);  # 往表添数据
      SET i = i+1;    # 循环一次,i加1
  END WHILE;  # 结束while循环
  SELECT count(*) FROM C; # 查看表数据
END;
//  # 结束定义语句
DELIMITER ; # 重新将分隔符设置为;
CALL PcreateA();    # 调用存储过程
 

2、编写查询脚本

[roo@localhost test]$ vi selectjoin.sql
use test;
explain select count(*) from (SELECT A.aid, A.title, B.uname, C.tname, C.age FROM A LEFT JOIN B ON A.uid=B.uid left JOIN C ON A.tid=C.tid where C.age<1) AA;
explain select count(*) from (select AC.aid, AC.title from (SELECT A.aid, A.title, A.uid, C.tname, C.age FROM A LEFT JOIN C ON A.tid=C.tid where C.age<1) AC LEFT JOIN B ON AC.uid=B.uid) BB;
 

3、依次执行脚本看结果

mysql> source /home/roo/test/createA.sql

(1)去掉selectjoin.sql中的explain,执行

Database changed
+----------+
| count(*) |
+----------+
|     4000 |
+----------+
1 row in set (0.08 sec)

+----------+
| count(*) |
+----------+
|     4000 |
+----------+
1 row in set (0.08 sec)
发现两者居然时间相同,难道不应该第二个“提前剪枝”的更优么??。。。。。

(2)执行explain查看执行计划

mysql> source /home/roo/test/selectjoin.sql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
+----+-------------+-------+------------+--------+---------------+---------+---------+------------+-------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref        | rows  | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------+---------+---------+------------+-------+----------+-------------+
|  1 | SIMPLE      | A     | NULL       | ALL    | NULL          | NULL    | NULL    | NULL       | 39303 |   100.00 | NULL        |
|  1 | SIMPLE      | C     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.A.tid |     1 |    33.33 | Using where |
|  1 | SIMPLE      | B     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.A.uid |     1 |   100.00 | Using index |
+----+-------------+-------+------------+--------+---------------+---------+---------+------------+-------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)

+----+-------------+-------+------------+--------+---------------+---------+---------+------------+-------+----------+-------------+
| id | select_type | table | partitions | type   | possible_keys | key     | key_len | ref        | rows  | filtered | Extra       |
+----+-------------+-------+------------+--------+---------------+---------+---------+------------+-------+----------+-------------+
|  1 | SIMPLE      | A     | NULL       | ALL    | NULL          | NULL    | NULL    | NULL       | 39303 |   100.00 | NULL        |
|  1 | SIMPLE      | C     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.A.tid |     1 |    33.33 | Using where |
|  1 | SIMPLE      | B     | NULL       | eq_ref | PRIMARY       | PRIMARY | 4       | test.A.uid |     1 |   100.00 | Using index |
+----+-------------+-------+------------+--------+---------------+---------+---------+------------+-------+----------+-------------+
3 rows in set, 1 warning (0.00 sec)
 

发现两者执行计划相同。

4、结果分析

MySQL执行语句过程中涉及到两大流程:优化器和执行器。其中优化器最主要的任务,是选择索引和在多表连接时选择连接顺序。

join顺序的选择会影响执行性能,确定join执行顺序就需要估算所有join操作的代价。

默认配置下MySQL会估算所有可能的组合,由于MySQL里限制一个查询的join表数目上限为61,所以MySQL有一个参数叫做optimizer_search_depth,默认为62,限制优化器的深度。

加入有20张表join查询,如optimizer_search_depth为4,则评估次数为20*19*18*17。

mysql> show variables like '%optimizer_search_depth%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| optimizer_search_depth | 62    |
+------------------------+-------+
在本例中,MySQL优化器执行了优化,所以两者都选取了最优的顺序。

 

 

标签:join,PRIMARY,tid,MySQL,test,table,NULL,优化
来源: https://blog.csdn.net/typ2004/article/details/116243119

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有