成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

阿里規定超過3張表禁止JOIN,為啥?

開發 后端 開發工具
《阿里巴巴 Java 開發手冊》里面寫超過三張表禁止 join,這是為什么?

[[424463]]

圖片來自 包圖網

問題分析

對這個結論,你是否有懷疑呢?也不知道是哪位先哲說的不要人云亦云,今天我設計 sql,來驗證這個結論。(實驗沒有從代碼角度分析,目前達不到。可以把 MySQL 當一個黑盒,使用角度來驗證這個結論)

驗證結論的時候,會有很多發現,各位往后看。

實驗環境

VMware 10+Centos 7.4+MySQL 5.7.22 ,Centos 7 內存 4.5G,4 核,50G 硬盤。MySQL 配置為 2G,特別說明硬盤是 SSD。

我的實驗

有 4 張表,student 學生表,teacher 老師表,course 課程表,sc 中間關系表,記錄了學生選修課程以及分數。

具體 sql 腳本,看文章結尾,我附上。中間我自己寫了造數據的腳本,也在結尾。

實驗是為解決一個問題的:查詢選修“tname553”老師所授課程的學生中,成績最高的學生姓名及其成績 。

查詢 sql 是:

  1. select Student.Sname,course.cname,score 
  2.     from Student,SC,Course ,Teacher 
  3.     where Student.s_id=SC.s_id and SC.c_id=Course.c_id  and sc.t_id=teacher.t_id 
  4.     and Teacher.Tname='tname553' 
  5.     and SC.score=(select max(score)from SC where sc.t_id=teacher.t_Id); 

我來分析一下這個語句:4 張表等值 join,還有一個子查詢。算是比較簡單的 sql 語句了(相比 ERP 動就 10 張表的哦,已經很簡單了)。

我還會分解這個語句成 3 個簡單的 sql:

  1. select max(score)  from SC ,Teacher where sc.t_id=teacher.t_Id and Teacher.Tname='tname553'
  2.   select sc.t_id,sc.s_id,score   from SC ,Teacher 
  3.   where sc.t_id=teacher.t_Id 
  4.   and score=590 
  5.   and Teacher.Tname='tname553'
  6.    select Student.Sname,course.cname,score 
  7.    from Student,SC ,course 
  8.    where Student.s_id=SC.s_id and  sc.s_id in (20769800,48525000,26280200) and course.c_id = sc.c_id; 

我來分析下:第一句,就是查詢最高分,得到最高分 590 分。第二句就是查詢出最高分的學生 id,得到:

  1. 20769800,48525000,26280200 

第三句就是查詢出學生名字和分數。這樣這 3 個語句的就可以查詢出來成績最高的學生姓名及其成績。

接下來我會分別造數據:1 千萬選課記錄(一個學生選修 2 門課),造 500 萬學生,100 萬老師(一個老師帶 5 個學生,挺高端的吧),1000 門課。

用上面查詢語句查詢。其中 sc 表我測試了下有索引和沒有索引情況,具體見下表。

再接下來,我會造 1 億選課記錄(一個學生選修 2 門課)5000 萬學生,1000 萬老師,1000 門課。然后分別執行上述語句。最后我會在 oracle 數據庫上執行上述語句。

下面兩張表是測試結果:

仔細看上表,可以發現?

①步驟 3.1 沒有在連接鍵上加索引,查詢很慢,說明:“多表關聯查詢時,保證被關聯的字段需要有索引”。

②步驟 6.1,6.2,6.3,換成簡單 sql,在數據量 1 億以上, 查詢時間還能勉強接受。此時說明 MySQL 查詢有些吃力了,但是仍然嫩查詢出來。

③步驟 5.1,MySQL 查詢不出來,4 表連接,對我本機 MySQL 來說,1.5 億數據超過極限了(我調優過這個 SQL,執行計劃和索引都走了,沒有問題,show profile 顯示在 sending data,這個問題另外文章詳談)。

④對比 1.1 和 5.1 步驟 sql 查詢,4 表連接,對我本機 MySQL 來說 ,1.5 千萬數據查詢很流利,是一個 MySQL 數據量流利分水嶺。(這個只是現象,不太準確,需要同時計算表的容量)。

⑤步驟 5.1 對比 6.1,6.2,6.3,多表 join 對 MySQL 來說,處理有些吃力。

⑥超過三張表禁止 join,這個規則是針對 MySQL 來說的。后續會看到我用同樣機器,同樣數據量,同樣內存,可以完美計算 1.5 億數據量 join。

針對這樣一個規則,對開發來說 ,需要把一些邏輯放到應用層去查詢。

總結:這個規則,超過三張表禁止 join,由于數據量太大的時候,MySQL 根本查詢不出來,導致阿里出了這樣一個規定。

其實如果表數據量少,10 張表也不成問題,你自己可以試試。而我們公司支付系統朝著大規模高并發目標設計的,所以,遵循這個規定。

在業務層面來講,寫簡單 sql,把更多邏輯放到應用層,我的需求我會更了解,在應用層實現特定的 join 也容易得多。

讓我們來看看 oracle 數據庫的優秀表現:

看步驟 7.1,就是沒有索引,join 表很多的情況下,oracle 仍然 26 秒查詢出結果來。所以我會說 MySQL 的 join 很弱。

那么問題來了,為什么現在使用很多人使用 MySQL 呢?這是另外一個問題,我會另外說下我的思考。

看完本篇文章,另外我還附加贈送,所謂摟草打兔子。就是快速造數據。你可以自己先寫腳本造數據,看看我是怎么造數據的,就知道我的技巧了。

附上部分截圖:

附上 sql 語句和造數據腳本:

  1. use stu; 
  2. drop table if exists student; 
  3. create table student 
  4.   (  s_id int(11) not null auto_increment , 
  5.      sno    int(11), 
  6.      sname varchar(50), 
  7.      sage  int(11), 
  8.      ssex  varchar(8) , 
  9.      father_id int(11), 
  10.       mather_id int(11), 
  11.       note varchar(500), 
  12.      primary key (s_id), 
  13.    unique key uk_sno (sno) 
  14.   ) engine=innodb default charset=utf8mb4; 
  15. truncate table student; 
  16.   delimiter $$ 
  17. drop function if exists   insert_student_data $$ 
  18. create function insert_student_data() 
  19.  returns  int deterministic 
  20.     begin 
  21.     declare  i int
  22.       set i=1; 
  23.       while  i<50000000 do 
  24.       insert into student  values(i ,i, concat('name',i),i,case when floor(rand()*10)%2=0 then 'f' else 'm' end,floor(rand()*100000),floor(rand()*1000000),concat('note',i) ); 
  25.       set i=i+1; 
  26.       end while; 
  27.       return 1; 
  28.     end$$ 
  29. delimiter ; 
  30. select  insert_student_data(); 
  31. select count(*) from student; 
  32. use stu; 
  33. create table course 
  34.   ( 
  35.      c_id int(11) not null auto_increment , 
  36.      cname varchar(50) 
  37.      note varchar(500), primary key (c_id) 
  38.   )  engine=innodb default charset=utf8mb4; 
  39. truncate table course; 
  40.   delimiter $$ 
  41. drop function if exists   insert_course_data $$ 
  42. create function insert_course_data() 
  43.  returns  int deterministic 
  44.     begin 
  45.     declare  i int
  46.       set i=1; 
  47.       while  i<=1000 do 
  48.       insert into course  values(i , concat('course',i),floor(rand()*1000),concat('note',i) ); 
  49.       set i=i+1; 
  50.       end while; 
  51.       return 1; 
  52.     end$$ 
  53. delimiter ; 
  54. select  insert_course_data(); 
  55. select count(*) from course; 
  56. use stu; 
  57. drop table if exists sc; 
  58. create table sc 
  59.   ( 
  60.      s_id    int(11), 
  61.      c_id    int(11), 
  62.      t_id    int(11), 
  63.      score int(11) 
  64.   )  engine=innodb default charset=utf8mb4; 
  65. truncate table sc; 
  66.   delimiter $$ 
  67. drop function if exists   insert_sc_data $$ 
  68. create function insert_sc_data() 
  69.  returns  int deterministic 
  70.     begin 
  71.     declare  i int
  72.       set i=1; 
  73.       while  i<=50000000 do 
  74.       insert into sc  values( i,floor(rand()*1000),floor(rand()*10000000),floor(rand()*750)) ; 
  75.       set i=i+1; 
  76.       end while; 
  77.       return 1; 
  78.     end$$ 
  79. delimiter ; 
  80. select  insert_sc_data(); 
  81. commit
  82. select  insert_sc_data(); 
  83. commit
  84. create index idx_s_id  on sc(s_id)   ; 
  85. create index idx_t_id  on sc(t_id)   ; 
  86. create index idx_c_id  on sc(c_id)   ; 
  87. select count(*) from sc; 
  88. use stu; 
  89. drop table if exists teacher; 
  90. create table teacher 
  91.   ( 
  92.     t_id  int(11) not null auto_increment , 
  93.      tname varchar(50) , 
  94.      note varchar(500),primary key (t_id) 
  95.   )  engine=innodb default charset=utf8mb4; 
  96.  
  97.   truncate table teacher; 
  98.   delimiter $$ 
  99. drop function if exists   insert_teacher_data $$ 
  100. create function insert_teacher_data() 
  101.  returns  int deterministic 
  102.     begin 
  103.     declare  i int
  104.       set i=1; 
  105.       while  i<=10000000 do 
  106.       insert into teacher  values(i , concat('tname',i),concat('note',i) ); 
  107.       set i=i+1; 
  108.       end while; 
  109.       return 1; 
  110.     end$$ 
  111. delimiter ; 
  112. select  insert_teacher_data(); 
  113. commit
  114. select count(*) from teacher; 

這個是 oracle 的測試和造數據腳本:

  1. create tablespace scott_data  datafile  '/home/oracle/oracle_space/sitpay1/scott_data.dbf'  size 1024m autoextend on
  2. create tablespace scott_index   datafile  '/home/oracle/oracle_space/sitpay1/scott_index.dbf'  size 64m  autoextend on
  3. create temporary tablespace scott_temp  tempfile  '/home/oracle/oracle_space/sitpay1/scott_temp.dbf'  size 64m autoextend on
  4. drop user  scott cascade
  5. create user  scott  identified by  tiger  default tablespace scott_data  temporary tablespace scott_temp  ; 
  6. grant resource,connect,dba to  scott; 
  7. drop table student; 
  8. create table student 
  9.   (  s_id number(11) , 
  10.      sno    number(11) , 
  11.      sname varchar2(50), 
  12.      sage  number(11), 
  13.      ssex  varchar2(8) , 
  14.      father_id number(11), 
  15.       mather_id number(11), 
  16.       note varchar2(500) 
  17.   ) nologging; 
  18. truncate table student; 
  19. create or replace procedure insert_student_data 
  20.  is 
  21.    q number(11); 
  22.     begin 
  23.      q:=0; 
  24.       for i in  1..50 loop 
  25.       insert /*+append*/ into student   select rownum+q as s_id,rownum+q  as sno, concat('sutdent',rownum+q ) as sname,floor(dbms_random.value(1,100)) as sage,'f' as ssex,rownum+q  as father_id,rownum+q  as mather_id,concat('note',rownum+q ) as note from dual connect by level<=1000000; 
  26.       q:=q+1000000; 
  27.       commit
  28.       end loop; 
  29. end insert_student_data; 
  30. call insert_student_data(); 
  31. alter table student  add constraint  pk_student primary key (s_id); 
  32. commit
  33. select count(*) from student; 
  34. create table course 
  35.   ( 
  36.      c_id number(11) primary key
  37.      cname varchar2(50), 
  38.      note varchar2(500) 
  39.   )  ; 
  40. truncate table course; 
  41.  create or replace procedure insert_course_data 
  42.  is 
  43.    q number(11); 
  44.     begin 
  45.  
  46.       for i in  1..1000 loop 
  47.       insert /*+append*/ into course  values(i , concat('name',i),concat('note',i) ); 
  48.       end loop; 
  49. end insert_course_data; 
  50. call insert_course_data(); 
  51. commit
  52. select count(*) from course; 
  53. create table sc 
  54.   ( 
  55.      s_id    number(11), 
  56.      c_id    number(11), 
  57.      t_id    number(11), 
  58.      score number(11) 
  59.   ) nologging; 
  60. truncate table sc; 
  61.  create or replace procedure insert_sc_data 
  62.  is 
  63.    q number(11); 
  64.     begin 
  65.      q:=0; 
  66.       for i in  1..50 loop 
  67.       insert /*+append*/ into sc   select rownum+q as s_id, floor(dbms_random.value(0,1000))  as c_id,floor(dbms_random.value(0,10000000)) t_id,floor(dbms_random.value(0,750)) as score from dual connect by level<=1000000; 
  68.       q:=q+1000000; 
  69.       commit
  70.       end loop; 
  71. end insert_sc_data; 
  72. call insert_sc_data(); 
  73. create index idx_s_id  on sc(s_id)   ; 
  74. create index idx_t_id  on sc(t_id)   ; 
  75. create index idx_c_id  on sc(c_id)   ; 
  76. select count(*) from sc; 
  77. create table teacher 
  78.   ( 
  79.     t_id  number(11) , 
  80.      tname varchar2(50) , 
  81.      note varchar2(500) 
  82.   )nologging ; 
  83.     truncate table teacher; 
  84. create or replace procedure insert_teacher_data 
  85.  is 
  86.    q number(11); 
  87.     begin 
  88.      q:=0; 
  89.       for i in  1..10 loop 
  90.       insert /*+append*/ into teacher   select rownum+q as t_id, concat('teacher',rownum+q ) as tname,concat('note',rownum+q ) as note from dual connect by level<=1000000; 
  91.       q:=q+1000000; 
  92.       commit
  93.       end loop; 
  94. end insert_teacher_data; 
  95. call insert_teacher_data(); 
  96. alter table teacher  add constraint  pk_teacher primary key (t_id); 
  97. select count(*) from teacher; 

作者:e71hao

編輯:陶家龍

出處:blog.itpub.net/30393770/viewspace-2650450/

 

責任編輯:武曉燕 來源: blog.itpub.net
相關推薦

2020-11-12 07:49:18

MySQL

2022-09-05 10:06:21

MySQL外循環內循環

2022-02-22 12:51:39

存儲過程JavaSQL

2021-06-17 06:19:20

存儲SQL數據庫

2023-11-16 12:34:00

MySQLjoin

2019-03-18 15:00:48

SQLJoin用法數據庫

2009-04-02 08:28:17

2021-06-26 07:18:15

JscodeshiftBabel節點

2018-09-19 21:34:12

阿里云芯片達摩院

2022-01-27 07:40:27

iOS微信朋友圈

2021-07-28 22:45:32

人臉識別生物識別信息安全

2010-05-04 14:10:53

Oracle表

2022-01-11 10:51:29

FlinkJoin數據

2024-09-27 09:41:31

2022-11-03 11:25:30

阿里云低代碼

2025-04-29 10:24:01

大數據StarRocksJOIN

2022-07-13 12:53:59

數據存儲

2023-01-09 08:43:34

2020-06-22 08:23:42

阿里技術架構圖

2019-03-04 13:54:18

MySQL分區表數據
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91久久精品一区二区二区 | 国产精品不卡视频 | 亚洲欧美视频在线观看 | 九九久久在线看 | avmans最新导航地址 | 雨宫琴音一区二区在线 | 精品一区二区三区在线观看国产 | 成人精品鲁一区一区二区 | 欧美日韩精品中文字幕 | 亚洲欧美视频一区 | 麻豆久久 | 在线免费av电影 | 国产精品久久久久久网站 | 97精品超碰一区二区三区 | 麻豆久久久9性大片 | 成人不卡在线 | 日本三级电影免费 | 欧美一级一区 | 欧美成人一区二区三区 | 亚洲精品乱码久久久久久蜜桃 | 精品免费在线 | 国产福利视频 | 色www精品视频在线观看 | 男女一区二区三区 | 久久中文视频 | 一区二区在线不卡 | 精品成人佐山爱一区二区 | 综合网视频 | 午夜精品一区二区三区在线视频 | 玖玖玖在线 | 美国十次成人欧美色导视频 | 亚洲免费一区二区 | 国产伦精品一区二区三区高清 | 国产成人精品一区二区三区四区 | 97久久精品午夜一区二区 | 久久久精品视频一区二区三区 | 亚洲一区二区av | 亚洲精品在线看 | 亚洲精品91 | 精品中文字幕视频 | 国产精品免费视频一区 |