当前位置: 首页 > 科技观察

阿里规定超过3张表禁止JOIN,为啥-

时间:2023-03-19 22:45:45 科技观察

阿里规定超过3张表禁止JOIN。为什么?验证这个结论。(实验没有从代码的角度分析过,目前没有,可以把MySQL当作黑盒,用角度来验证这个结论。)验证结论的时候,会有很多发现,你会回头看。实验环境VMware10+Centos7.4+MySQL5.7.22,Centos7内存4.5G,4核,50G硬盘。MySQL配置为2G,特别说明硬盘是SSD。我的实验有4张表,student学生表,teacher老师表,course课程表,sc中间关系表,记录了学生的选修课和分数。具体的sql脚本见文末,我附上。中间自己写了创建数据的脚本,也是在最后。实验是要解决一个问题:查询上过老师“tname553”所讲课程的学生中成绩最高的学生的姓名和成绩。查询sql为:selectStudent.Sname,course.cname,scorefromStudent,SC,Course,TeacherwhereStudent.s_id=SC.s_idandSC.c_id=Course.c_idandsc.t_id=teacher.t_idandTeacher.Tname='tname553'andSC.score=(selectmax(score)fromSCwheresc.t_id=teacher.t_Id);我来分析一下这条语句:4张表等价连接,还有一个子查询。是比较简单的sql语句(相对于只有10张表的ERP来说,已经很简单了)。我还将这条语句分解为3个简单的sql:selectmax(score)fromSC,Teacherwheresc.t_id=teacher.t_IdandTeacher.Tname='tname553';selectsc.t_id,sc.s_id,scorefromSC,Teacherwheresc.t_id=teacher.t_Idandscore=590andTeacher.Tname='tname553';selectStudent.Sname,course.cname,scorefromStudent,SC,coursewhereStudent.s_id=SC.s_idandsc.s_idin(20769800,48525000,26280200)andcourse.c_id=sc.c_id;我来分析一下:第一句是查询最高分,最高分是590分。第二句是查询分数最高的学生id,得到:20769800,48525000,26280200第三句是查询学生姓名和分数。这样就可以从这三个语句中查询出成绩最高的学生姓名和成绩。接下来我单独创建数据:1000万选课记录(一个学生选2门课),500万学生,100万老师(一个老师带5个学生,相当高端),1000门课程。使用上面的查询来查询。其中,我测试了带索引和不带索引的sc表,具体见下表。接下来我要创建1亿条选课记录(一个学生选2门课),5000万学生,1000万教师,1000门课程。然后分别执行上面的语句。最后我会在oracle数据库上执行上面的语句。下面两张表是测试结果:仔细看上表,你能发现吗?①步骤3.1没有给connectionkey加索引,查询很慢。说明:“多表关联查询时,保证关联字段需要有索引。”②6.1、6.2、6.3步骤替换为简单的sql。当数据量过亿时,查询时间勉强可以接受。这个时候说明MySQL查询有点吃力,但是查询还是嫩的。③步骤5.1,找不到MySQL查询,连接了4张表,我本地的MySQL,1.5亿条数据超限(这个SQL我已经调过,执行计划和索引都没有了,没问题,显示showprofile在发送数据时,这个问题将在另一篇文章中详细讨论)。④对比步骤1.1和5.1的sql查询,4个表连接,对于我本地的MySQL,1500万条数据查询非常流畅,是MySQL数据量流畅度的一个分水岭。(这只是一个现象,不是很准确,需要同时计算表的容量)。⑤步骤5.1对比6.1、6.2、6.3,多表join对MySQL来说有点难度。⑥三张以上的表禁止加入。此规则适用于MySQL。后面会看到我用同样的机器,同样的数据量,同样的内存,可以完美计算1.5亿数据量的join。对于这样的一条规则,为了开发,需要在应用层放一些逻辑,供查询。总结:在这条规则中,禁止超过三个表的连接。当数据量太大的时候,MySQL根本查询不到,导致阿里做出了这样的规定。其实如果表数据量不大,10张表不是问题,大家可以自己试试。而我们公司的支付系统是朝着大规模高并发的目标设计的,所以遵循这个规则。在业务层面,如果我写简单的sql,把更多的逻辑放在应用层,我会更好地理解我的需求,在应用层实现具体的join也会容易很多。再来看看oracle数据库的优秀表现:看7.1步,也就是没有索引,join表很多,oracle查询结果还是需要26秒。所以我会说MySQL的连接很弱。那么问题来了,为什么现在很多人都用MySQL呢?这是另外一个问题,我单独说说我的思考。看完这篇文章,我还要加一个礼物,正所谓耙草打兔。就是快速创建数据。大家可以先自己写脚本创建数据,看看我是怎么创建数据的,就知道我的本事了。附上部分截图:附上sql语句和数据脚本:usestu;droptableifexistsstudent;createtablestudent(s_idint(11)notnullauto_increment,snoint(11),snamevarchar(50),sageint(11),ssexvarchar(8),father_idint(11),mather_idint(11),notevarchar(500),primarykey(s_id),uniquekeyuk_sno(sno))engine=innodbdefaultcharset=utf8mb4;truncatetablestudent;定界符$$dropfunctionifexistsinsert_student_data$$createfunctioninsert_student_data()returnsintdeterministicbegindeclareiint;seti=1;whilei<500000toins(doinsertvalues)i,concat('name',i),i,casewhenfloor(rand()*10)%2=0then'f'else'm'结束,floor(rand()*100000),floor(rand()*1000000),concat('note',i));seti=i+1;endwhile;return1;end$$delimiter;selectinsert_student_data();selectcount(*)fromstudent;usestu;createtablecourse(c_idint(11)notnullauto_increment,cnamevarchar(50)notevarchar(500),primarykey(c_id))engine=innodbdefaultcharset=utf8mb4;truncatetablecourse;delimiter$$dropfunctionifexistsinsert_course_data$$createfunctioninsert_course_data()returnsintdeterministicbegindeclareiint;seti=1;whilei<=1000doinsertintocoursevalues(i,concat('course',i),floor(rand()*1000),concat('note',i));seti=i+1;endwhile;return1;结束$$定界符;selectinsert_course_data();selectcount(*)fromcourse;usestu;droptableifexistssc;createtablesc(s_idint(11),c_idint(11),t_idint(11),scoreint(11))engine=innodbdefaultcharset=utf8mb4;truncatetablesc;定界符$$dropfunctionifexistsinsert_sc_data$$createfunctioninsert_sc_data()returnsintdeterministicbegindeclareiint;seti=1;whilei<=50000000doinsertintoscvalues(i,floor(rand()*1000),floor(rand()*10000000),floor(rand()*750));seti=i+1;endwhile;return1;end$$delimiter;selectinsert_sc_data();commit;selectinsert_sc_data();commit;createindexidx_s_idonsc(s_id);createindexidx_t_idonsc(t_id);createindexidx_c_idonsc(c_id);selectcount(*)fromsc;usestu;droptableifexiststeacher;createtableteacher(t_idint(11)notnullauto_increment,tnamevarchar(50),notevarchar(500),主键(t_id))引擎=innodbdefaultcharset=utf8mb4;truncatetableteacher;分隔符$$dropfunctionifexistsinsert_teacher_data$$createfunctioninsert_teacher_data()returnsintdeterministicbegindeclareiint;seti=1;whilei<=10000000doinsertintoteachervalues(i,concat('tname',i),concat('note',i));seti=i+1;endwhile;return1;end$$delimiter;selectinsert_teacher_data();commit;selectcount(*)fromteacher;这是oracle的测试和生成数据脚本:createtablespacescott_datadatafile'/home/oracle/oracle_space/sitpay1/scott_data.dbf'size1024mautoextendon;createtablespacescott_indexdatafile'/home/oracle/oracle_space/sitpay1/scott_index.dbf'size64mautoextendon;createtemporarytablespacescott_temptempfile'/home/oracle/oracle_space/sitpay1/scott_temp.dbf'size64mautoextendon;dropuserscottcascade;createuserscottidentifiedbytigerdefaulttablespacescott_datatemporarytablespacescott_temp;grantresource,connect,dbatoscott;droptablestudent;createtablestudent(s_idnumber(11),snonumber(11),snamevarchar2(50),sagenumber(11),ssexvarchar2(8),father_idnumber(11),mather_idnumber(11),notevarchar2(500))nologging;truncatetablestudent;createorreplaceprocedureinsert_student_dataisqnumber(11);beginq:=0;foriin1..50loopinsert/*+append*/intostudentselectrownum+qass_id,rownum+qassno,concat('sutdent',rownum+q)assname,floor(dbms_random.value(1,100))assage,'f'asssex,rownum+qasfather_id,rownum+qasmather_id,concat('note',rownum+q)asnotefromdualconnectbylevel<=1000000;q:=q+1000000;提交;endloop;endinsert_student_data;/callinsert_student_data();altertablestudentaddconstraintpk_studentprimarykey(s_id);提交;selectcount(*)fromstudent;createtablecourse(c_idnumber(11)主键,cnamevarchar2(50),notvarchar2(500));truncatetablecourse;createorreplaceprocedureinsert_course_dataisqnumber(11);beginforiin1..1000loopinsert/*+append*/intocoursevalues(i,concat('name',i),concat('note',i));endloop;endinsert_course_data;/callinsert_course_data();提交;selectcount(*)fromcourse;createtablesc(s_idnumber(11),c_idnumber(11),t_idnumber(11),scorenumber(11))nologging;truncatetablesc;createorreplaceprocedureinsert_sc_dataisqnumber(11);beginq:=0;foriin1..50loopinsert/*+append*/intoscselectrownum+qass_id,floor(dbms_random.value(0,1000))asc_id,floor(dbms_random.value(0,10000000))t_id,floor(dbms_random.value(0,750))asscorefromdualconnectbylevel<=1000000;q:=q+1000000;commit;endloop;endinsert_sc_data;/callinsert_sc_data();createindexidx_s_idonsc(s_id);createindexidx_t_idonsc(t_id);createindexidx_c_idonsc(c_id);selectcount(*)fromsc;createtableteacher(t_idnumber(11),tnamevarchar2(50),notvarchar2(500))nologging;truncatetableteacher;createorreplaceproceduredatainsert_number(er_teacher)11);beginq:=0;foriin1..10loopinsert/*+append*/intoteacherselectrownum+qast_id,concat('teacher',rownum+q)astname,concat('note',rownum+q)asnotefromdualconnectbylevel<=1000000;q:=q+1000000;commit;endloop;endinsert_teacher_data;/callinsert_teacher_data();altertableteacheraddconstraintpk_teacherprimarykey(t_id);selectcount(*)fromteacher;作者:e71hao编辑:陶佳龙来源:blog.itpub.net/30393770/viewspace-2650450/

猜你喜欢