mysql禁用join_阿里规定超过三张表禁止JOIN,为啥呢?

作者:e71hao

一、 问题提出

《阿里巴巴JAVA开发手册》里面写超过三张表禁止join,这是为什么?关注我回复嵩山可以获取这个完整版。

二、问题分析

对这个结论,你是否有怀疑呢?也不知道是哪位先哲说的不要人云亦云,今天我设计sql,来验证这个结论。(实验没有从代码角度分析,目前达不到。

可以把mysql当一个黑盒,使用角度来验证这个结论) 验证结论的时候,会有很多发现,各位往后看。

三、 实验环境

vmware10+centos7.4+mysql5.7.22

centos7内存4.5G,4核,50G硬盘。

mysql配置为2G,特别说明硬盘是SSD。

四、我概述下我的实验

有4张表,student学生表,teacher老师表,course课程表,sc中间关系表,记录了学生选修课程以及分数。

具体sql脚本,看文章结尾,我附上。中间我自己写了造数据的脚本,也在结尾。

6a014e128efa6bfd05fd3fc3fbfd3395.png

实验是为解决一个问题的:查询选修“tname553”老师所授课程的学生中,成绩最高的学生姓名及其成绩。

查询sql是:

我来分析一下这个语句:4张表等值join,还有一个子查询。算是比较简单的sql语句了(相比ERP动就10张表的哦,已经很简单了)。我 还会分解这个语句成3个简单的sql:

我来分析下:第一句,就是查询最高分,得到最高分590分。第二句就是查询出最高分的学生id,得到

第三句就是查询出学生名字和分数。这样这3个语句的就可以查询出来 成绩最高的学生姓名及其成绩 。

接下来我会分别造数据:1千万选课记录(一个学生选修2门课),造500万学生,100万老师(一个老师带5个学生,挺高端的吧),1000门课,。用上面查询语句查询。其中sc表我测试了下有索引和没有索引情况,具体见下表。

再接下来,我会造1亿选课记录(一个学生选修2门课),5000万学生,1000万老师,1000门课。然后分别执行上述语句。最后我会在oracle数据库上执行上述语句。

五、下面两张表是测试结果

67dcc8d8cf1701f33564fcaf67cc50d8.png

194d93f64c6b71e3185171c212005f09.png

六、仔细看上表,可以发现:

1、步骤3.1没有在连接键上加索引,查询很慢,说明:“多表关联查询时,保证被关联的字段需要有索引”;

2、步骤6.1,6.2,6.3,换成简单sql,在数据量1亿以上, 查询时间还能勉强接受。此时说明mysql查询有些吃力了,但是仍然嫩查询出来。

3、步骤5.1,mysql查询不出来,4表连接,对我本机mysql来说,1.5亿数据超过极限了(我调优过这个SQL,执行计划和索引都走了,没有问题,show profile显示在sending data.这个问题另外文章详谈。)

4、对比1.1 和5.1 步骤sql查询,4表连接,对我本机mysql来说 ,1.5千万数据查询很流利,是一个mysql数据量流利分水岭。(这个只是现象,不太准确,需要同时计算表的容量)。

5、步骤5.1对比6.1,6.2,6.3,多表join对mysql来说,处理有些吃力。

6、超过三张表禁止join,这个规则是针对mysql来说的。后续会看到我用同样机器,同样数据量,同样内存,可以完美计算 1.5亿数据量join。针对这样一个规则,对开发来说 ,需要把一些逻辑放到应用层去查询。

七、让我们来看看oracle数据库的优秀表现:

e34f9325473ba01e53ee32e8442e88ef.png

看步骤7.1,就是没有索引,join表很多的情况下,oracle仍然26秒查询出结果来。所以我会说mysql的join很弱。那么问题来了,为什么现在使用很多人使用mysql呢?这是另外一个问题,我会另外说下我的思考。

看完本篇文章,另外我还附加赠送,所谓搂草打兔子。就是快速造数据。你可以自己先写脚本造数据,看看我是怎么造数据的,就知道我的技巧了。

八、附上部分截图

f1d18ff6ff009706f575c7ace30669b3.png

1cc8b9797ba85af4cf39111a5f21c7cd.png

376cd4632dde219a0557cd257d452f90.png

九、附上sql语句和造数据脚本

use stu;

drop tableif exists student;

create tablestudent

( s_idint(11) notnull auto_increment ,

snoint(11),

snamevarchar(50),

sageint(11),

ssexvarchar(8) ,

father_idint(11),

mather_idint(11),

notevarchar(500),

primarykey (s_id),

unique keyuk_sno (sno)

) engine=innodbdefault charset=utf8mb4;

truncate table student;

delimiter $$

drop functionif exists insert_student_data $$

create functioninsert_student_data()

returnsint deterministic

begin

declare iint;

set i=1;

while i

insertinto studentvalues(i ,i, concat( name ,i),i,case whenfloor(rand()*10)%2= then felse m end,floor(rand()*100000),floor(rand()*1000000),concat( note ,i) );

set i=i+1;

endwhile;

return 1;

end$$

delimiter ;

select insert_student_data();

select count(*)from student;

use stu;

create tablecourse

(

c_idint(11) notnull auto_increment ,

cnamevarchar(50)

notevarchar(500), primarykey (c_id)

) engine=innodbdefault charset=utf8mb4;

truncate table course;

delimiter $$

drop functionif exists insert_course_data $$

create functioninsert_course_data()

returnsint deterministic

begin

declare iint;

set i=1;

while i

insertinto coursevalues(i , concat( course ,i),floor(rand()*1000),concat( note ,i) );

set i=i+1;

endwhile;

return 1;

end$$

delimiter ;

select insert_course_data();

select count(*)from course;

use stu;

drop tableif exists sc;

create tablesc

(

s_idint(11),

c_idint(11),

t_idint(11),

scoreint(11)

) engine=innodbdefault charset=utf8mb4;

truncate table sc;

delimiter $$

drop functionif exists insert_sc_data $$

create functioninsert_sc_data()

returnsint deterministic

begin

declare iint;

set i=1;

while i

insertinto scvalues( i,floor(rand()*1000),floor(rand()*10000000),floor(rand()*750));

set i=i+1;

endwhile;

return 1;

end$$

delimiter ;

select insert_sc_data();

commit;

select insert_sc_data();

commit;

create index idx_s_idon sc(s_id);

create index idx_t_idon sc(t_id);

create index idx_c_idon sc(c_id);

select count(*)from sc;

use stu;

drop tableif exists teacher;

create tableteacher

(

t_idint(11) notnull auto_increment ,

tnamevarchar(50) ,

notevarchar(500),primarykey (t_id)

) engine=innodbdefault charset=utf8mb4;

truncate table teacher;

delimiter $$

drop functionif exists insert_teacher_data $$

create functioninsert_teacher_data()

returnsint deterministic

begin

declare iint;

set i=1;

while i

insertinto teachervalues(i , concat( tname ,i),concat( note ,i) );

set i=i+1;

endwhile;

return 1;

end$$

delimiter ;

select insert_teacher_data();

commit;

select count(*)from teacher;

这个是oracle的测试和造数据脚本

create tablespace scott_datadatafile /home/oracle/oracle_space/sitpay1/scott_data.dbfsize 1024mautoextend on;

create tablespace scott_indexdatafile /home/oracle/oracle_space/sitpay1/scott_index.dbfsize 64mautoextend on;

create temporary tablespace scott_temp tempfile /home/oracle/oracle_space/sitpay1/scott_temp.dbfsize 64mautoextend on;

drop user scottcascade;

create user scottidentified by tigerdefault tablespace scott_datatemporary tablespace scott_temp ;

grant resource,connect,dbato scott;

drop table student;

create table student

( s_idnumber(11) ,

snonumber(11) ,

sname varchar2(50),

sagenumber(11),

ssex varchar2(8) ,

father_idnumber(11),

mather_idnumber(11),

note varchar2(500)

) nologging;

truncate table student;

create or replace procedure insert_student_data

is

qnumber(11);

begin

q:=;

for i in 1..50 loop

insert /*+append*/ into studentselect rownum+qas s_id,rownum+qas sno,concat( sutdent ,rownum+q )as sname,floor(dbms_random.value(1,100))as sage, fas ssex,rownum+qas father_id,rownum+qas mather_id,concat( note ,rownum+q )as notefrom dualconnect by level

q:=q+1000000;

commit;

end loop;

end insert_student_data;

/

call insert_student_data();

alter table studentadd constraint pk_student primarykey (s_id);

commit;

select count(*)from student;

create table course

(

c_idnumber(11) primarykey,

cname varchar2(50),

note varchar2(500)

) ;

truncate table course;

create or replace procedure insert_course_data

is

qnumber(11);

begin

for iin 1..1000 loop

insert /*+append*/ into coursevalues(i ,concat(name ,i),concat( note ,i) );

end loop;

end insert_course_data;

/

call insert_course_data();

commit;

select count(*)from course;

create table sc

(

s_idnumber(11),

c_idnumber(11),

t_idnumber(11),

scorenumber(11)

) nologging;

truncate table sc;

create or replace procedure insert_sc_data

is

qnumber(11);

begin

q:=;

for i in 1..50 loop

insert /*+append*/ into scselect rownum+qas s_id,floor(dbms_random.value(,1000))as c_id,floor(dbms_random.value(,10000000)) t_id,floor(dbms_random.value(,750))as scorefrom dualconnect by level

q:=q+1000000;

commit;

end loop;

end insert_sc_data;

/

call insert_sc_data();

create index idx_s_idon sc(s_id) ;

create index idx_t_idon sc(t_id) ;

create index idx_c_idon sc(c_id) ;

select count(*)from sc;

create table teacher

(

t_idnumber(11) ,

tname varchar2(50) ,

note varchar2(500)

)nologging ;

truncate table teacher;

create or replace procedure insert_teacher_data

is

qnumber(11);

begin

q:=;

for i in 1..10 loop

insert /*+append*/ into teacherselect rownum+qas t_id,concat( teacher ,rownum+q )as tname,concat( note ,rownum+q )as notefrom dualconnect by level

q:=q+1000000;

commit;

end loop;

end insert_teacher_data;

/

call insert_teacher_data();

alter table teacheradd constraint pk_teacher primarykey (t_id);

select count(*)from teacher;

-END-

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值