Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Upcoming SlideShare
My sql overview 2012 04-25 by scott chen - 30min - tw-1
Next
Download to read offline and view in fullscreen.

13

Share

Download to read offline

5 古雷my sql源碼與資料庫規範

Download to read offline

MySQL Source Code

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all

5 古雷my sql源碼與資料庫規範

  1. 1. MYSQL源碼 與資料庫規範 CNTV(央視國際網路) 資深MYSQL DBA 古雷
  2. 2. CMUG(中國MYSQL⽤用⼾戶組)成員 古雷 CNTV資深MYSQL⼯工程師 • 在MySQL DBA領域混跡多年 • 在搜狐和暢遊獲得成⾧長 • ⺫⽬目前在CNTV繼續深⼊入學習 MySQL • 喜歡研究MySQL源碼 • 積極參加MySQL⽤用⼾戶組(CMUG) 的活動 • 由於愛好佛教,⼈人送綽號“古⼤大 師”——純屬朋友送的昵稱,希 望⼤大家⾒見怪不怪
  3. 3. 可能涉及到的術語 • 資料庫——數據庫——database • 資料——數據——data • 欄位——字段——column, field • 1位元——1位——one bit • 1位元組——1個字節——one byte • 檔案——⽂文件——file • 暫存檔案——臨時⽂文件——temporary file • 記憶體——內存——memory • 字元——字符——character • 網路──網絡──network
  4. 4. 為什麼要看源碼 • 運維MySQL多年,⽤用得越多越想知道為什麼 • 看⽂文檔覺得不夠解渴 • 推⾏行資料庫開發規範,開發(研發)部⾨門的同事也想知道更多的“為什 麼” • 進展: • 了解了⼀一些執⾏行計劃的執⾏行過程 • 了解了InnoDB page的⼀一部分結構 • 了解了⼀一點有關SQL成本(cost)估算的內容
  5. 5. 資料庫開發規範 • 學習、借鑒多家公司的規範 • 制訂並推⾏行適合⾃自⼰己公司的規範 • 每⼀一條規範都是不可打破的嗎?有適⽤用範圍嗎? • 開發⼈人員可以被我說服嗎 • 嘗試向源碼尋求幫助
  6. 6. FILESORT 從⼀一個排序的SQL說起 • MySQL中,當ORDER BY無法使⽤用索引時,則產⽣生filesort • 本例是⼀一個簡化的例⼦子,為了演⽰示filesort,有意不加索引 • 實際情況中,會有⼀一些稍微複雜的SQL不容易使⽤用索引,或者是確實缺 少索引 • 本例試圖以⼀一個簡化的例⼦子專⾨門展⽰示filesort的效果
  7. 7. FILESORT SELECT多⼀一個欄位,時間相差6倍 • select * 僅⽐比select id,name多了⼀一個欄位 address varchar(255) • ⽽而且address全部是空,即NULL • SELECT多⼀一個欄位,時間相差6倍——1.19秒VS 0.20秒
  8. 8. mysql>  flush  status;     mysql>  select  *  from  testsort  order  by  name;     mysql>  select  *  from  information_schema.session_status  where  variable_name  in   ('created_tmp_files','sort_merge_passes');     +-------------------+----------------+     |  VARIABLE_NAME          |  VARIABLE_VALUE  |     +-------------------+----------------+     |  CREATED_TMP_FILES  |  3                            |     |  SORT_MERGE_PASSES  |  3                            |     +-------------------+----------------+       mysql>  flush  status;     mysql>  select  id,name  from  testsort  order  by  name;     mysql>  select  *  from  information_schema.session_status  where  variable_name  in   ('created_tmp_files','sort_merge_passes');     +-------------------+----------------+     |  VARIABLE_NAME          |  VARIABLE_VALUE  |     +-------------------+----------------+     |  CREATED_TMP_FILES  |  0                            |     |  SORT_MERGE_PASSES  |  0                            |     +-------------------+----------------+  
  9. 9. FILESORT排序記憶體計算 • select id,name,address from testsort order by name; • order by name欄位name varchar(50) utf8: • 50個utf8字元占50*3位元組,轉換為占2位元組編碼(150*2+2)/3=100 • name可為空,需要加1個位元組,共101位元組 • select id,name,address欄位 • id int占4位元組;name占50*3+1+1=152(兩個1的來源150<255, 151<255) • address varchar(255): 255*3+2+2=769(兩個2的來源765>255, 767>255) • name和address可以為空,共⽤用1個位元組表⽰示空值(各占⼀一bit) • ⼀一個char*(指標),占8位元組(只存在於sort buffer中,在暫存檔案中不 存) • 共101+4+152+769+1+8=1035位元組
  10. 10. ⼀一⾏行之差 mysql>  set  sort_buffer_size=1035*122881;                flush  status;     mysql>  select  *  into  outfile  '/data/dump/sort.txt'  from  testsort  order  by  name;     Query  OK,  122881  rows  affected  (0.56  sec)   mysql>  select  *  from  information_schema.session_status  where  variable_name  in   ('created_tmp_files','sort_merge_passes');     +-------------------+----------------+     |  VARIABLE_NAME          |  VARIABLE_VALUE  |     +-------------------+----------------+     |  CREATED_TMP_FILES  |  0                            |     |  SORT_MERGE_PASSES  |  0                            |     +-------------------+----------------+     mysql>  set  sort_buffer_size=1035*122880;              flush  status;     mysql>  select  *  into  outfile  '/data/dump/sort.txt'  from  testsort  order  by  name;     Query  OK,  122881  rows  affected  (0.91  sec)   mysql>  select  *  from  information_schema.session_status  where  variable_name  in   ('created_tmp_files','sort_merge_passes');     +-------------------+----------------+     |  VARIABLE_NAME          |  VARIABLE_VALUE  |     +-------------------+----------------+     |  CREATED_TMP_FILES  |  2                            |     |  SORT_MERGE_PASSES  |  1                            |     +-------------------+----------------+  
  11. 11. FILESORT兩種演算法的選擇 mysql>  set  max_length_for_sort_data=1024;  //讓filesort每行資料最大長度小於1035位元組   mysql>  set  sort_buffer_size=117*122881;      //filesort會選擇另一演算法,每行只保存排序的   mysql>  flush  status;                                                      //(接上面)  KEY、主鍵(8位元組)、指標(8位元組)   mysql>  show  global  status  like  'innodb_rows_read';     +------------------+---------+     |  Variable_name        |  Value      |     +------------------+---------+     |  Innodb_rows_read  |  1720348  |     +------------------+---------+     mysql>  select  *  into  outfile  '/data/dump/sort.txt'  from  testsort  order  by  name;     Query  OK,  122881  rows  affected  (0.66  sec)     mysql>  select  *  from  information_schema.session_status  where  variable_name  in   ('created_tmp_files','sort_merge_passes','innodb_rows_read');     +-------------------+----------------+     |  VARIABLE_NAME          |  VARIABLE_VALUE  |     +-------------------+----------------+     |  CREATED_TMP_FILES  |  0                            |                                      //這次sort_buffer_size較小,也足夠用。   |  INNODB_ROWS_READ    |  1966110                |                  //另外,1966110  -  1720348  =  245762   |  SORT_MERGE_PASSES  |  0                            |                                  //(接上面)恰好是122881的兩倍   +-------------------+----------------+  
  12. 12. FILESORT落實到資料庫規範 • 請勿使⽤用SELECT * • SELECT後⾯面指明實際需要的欄位名,在⾜足夠⽤用的前提下,儘量少 • VARCHAR(n),n的⼤大⼩小也是需要計較的,在⾜足夠⽤用的前提下,儘量⼩小 • 把不會在SQL的WHERE以及ORDER BY、GROUP BY中出現的TEXT欄 位、⽐比較⼤大的VARCHAR欄位等單獨放在⼀一張表裡 • 上述習慣將避免很多後續的優化⼯工作 • ⽽而且有些優化⼯工作是成本很⾼高的,⽐比如把⼤大的欄位拆到新表裡
  13. 13. SORT_MERGE_PASSES的計算 mysql> desc tab; +---------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(15) | YES | | NULL | | | address | varchar(200) | YES | | NULL | | +---------+--------------+------+-----+---------+----------------+ mysql> select * into outfile '/media/psf/Home/workspace/dump/sort.txt' from tab order by name; Query OK, 63584 rows affected (3.70 sec) mysql> select * from information_schema.session_status where variable_name in ('created_tmp_files','sort_merge_passes'); +-------------------+----------------+ | VARIABLE_NAME | VARIABLE_VALUE | +-------------------+----------------+ | CREATED_TMP_FILES | 3 | | SORT_MERGE_PASSES | 28 | +-------------------+----------------+
  14. 14. 統計相關函數的執⾏行次數 引⼊入新玩具——SYSTEMTAP root@ubuntu:~# stap calls_count.stp /usr/local/mysql56debug/bin/mysqld make_sortkey 63584 write_keys 169 merge_buffers 28 create_temp_file 3 filesort_free_buffers 3 filesort 1 trace_filesort_information 1 init_for_filesort 1 merge_many_buff 1 merge_index 1
  15. 15. SYSTEMTAP腳本 root@ubuntu:~# cat calls_count.stp global calls probe process(@1).function("*write_keys*").call , process(@1).function("*filesort*").call , process(@1).function("*merge_buffers*").call , process(@1).function("*create_temp_file*").call , process(@1).function("*make_sortkey*").call , process(@1).function("*merge_many_buff*").call , process(@1).function(“*merge_index*").call { calls[ppfunc()] ++ } probe timer.s(10) { foreach (name in calls- limit 30) printf ("%st%dn", name, calls[name]) print("n") }
  16. 16. SORT_MERGE_PASSES的計算 • 第1批合併:169=7*24+1;即合併24次排序結果,前23次每次合併7個,最後⼀一 次合併8個 • 第2批合併:24=7*3+3;即合併3次排序結果,前2次每次合併7個,最後⼀一次10 個 • 第3批合併:3個排序結果,最後再合併1次,得到最終結果 • 24+3+1=28;即調⽤用merge_buffers的次數,也即sort_merge_passes的值 函數 執⾏行次數 解釋 make_sortkey 65384 製作排序的key,本例是name欄位 write_keys 169 每在sort buffer中排⼀一次序,在排序後要把排序結果寫 ⼊入暫存檔案,⼀一共寫了169次。也即排序排了169次 merge_buffers 28 合併排序結果,即進⾏行merge sort,每7個結果合併⼀一次 create_temp_file 3 創建了3個暫存檔案,其中⼀一個應該是 16*sort_buffer_size那麼⼤大
  17. 17. SYSTEMTAP監控暫存檔案的讀寫 • root@ubuntu:~# stap iotime.stp 19120 ##刪除了部分輸出內容 • (mysqld) access /tmp/MY2h0vCA read: 43682208 write: 43682208 • (mysqld) access /tmp/MYfjNKjs read: 87364416 write: 87364416 • (mysqld) access /tmp/MYXM65AV read: 41711104 write: 41711104 • (mysqld) access /media/psf/Home/workspace/dump/sort.txt read: 0 write: 36424243 • id int 4位元組,name varchar(15) utf8 45+1+1位元組,address varchar(200) utf8 600+2+2,再加1個空值位元組,共656 • name作為排序的KEY,(45*2+2)/3=30,再加1個空值位元組,共31 • (656+31)*63584=43682208; 43682208*2=87364416 • 41711104/63584=656 • 169次排序,結果寫⼊入/tmp/MYfjNKjs;第⼀一批合併排序,結果寫⼊入/ tmp/MY2h0vCA;第⼆二批合併排序,結果寫⼊入/tmp/MYfjNKjs;第三批 合併排序,/tmp/MYXM65AV;最終輸出的結果從/tmp/MYXM65AV讀
  18. 18. SYSTEMTAP官網的腳本IOTIME.STP(⼀一) root@ubuntu:~# cat iotime.stp #! /usr/bin/env stap global start global time_io function timestamp:long() { return gettimeofday_us() - start } function proc:string() { return sprintf("%d (%s)", pid(), execname()) } probe begin { start = gettimeofday_us() } global filehandles, fileread, filewrite probe syscall.open.return { if( pid() == strtol(@1,10) ) { filename = user_string($filename) if ($return != -1) { filehandles[pid(), $return] = filename } else { printf("%d %s access %s failn", timestamp(), proc(), filename) } } }
  19. 19. IOTIME.STP(⼆二) probe syscall.read.return ,syscall.pread.return { #MySQL使⽤用了pread if( pid() == strtol(@1,10) ) { p = pid() fd = $fd bytes = $return time = gettimeofday_us() - @entry(gettimeofday_us()) if (bytes > 0) fileread[p, fd] += bytes time_io[p, fd] <<< time } }
  20. 20. IOTIME.STP(三) probe syscall.write.return { if( pid() == strtol(@1,10) ) { p = pid() fd = $fd bytes = $return time = gettimeofday_us() - @entry(gettimeofday_us()) if (bytes > 0) filewrite[p, fd] += bytes time_io[p, fd] <<< time } }
  21. 21. IOTIME.STP(四) probe syscall.close { if( pid() == strtol(@1,10) ) { if ([pid(), $fd] in filehandles) { printf("%d %s access %s read: %d write: %dn", timestamp(), proc(), filehandles[pid(), $fd], fileread[pid(), $fd], filewrite[pid(), $fd]) if (@count(time_io[pid(), $fd])) printf("%d %s iotime %s time: %dn", timestamp(), proc(), filehandles[pid(), $fd], @sum(time_io[pid(), $fd])) } delete fileread[pid(), $fd] delete filewrite[pid(), $fd] delete filehandles[pid(), $fd] delete time_io[pid(),$fd] } }
  22. 22. 總結 • 看MySQL源碼很有樂趣 • 可以很⾃自然地落實到資料庫開發規範上 • systemap好強⼤大,可以好好學習和利⽤用 • 當前正在學習:opitmizer_trace中cost和rows的計算公式 • 有什麼問題?交流⼀一下 謝謝⼤大家
  • freezejonny

    Jan. 13, 2016
  • itplayer

    Dec. 29, 2015
  • AshrafChu

    Dec. 28, 2015
  • hochungchang

    Dec. 28, 2015
  • bestlong

    Dec. 28, 2015
  • c9s

    Dec. 28, 2015
  • AaronKing6

    Dec. 28, 2015
  • bamoo456

    Dec. 27, 2015
  • fghhfg

    Dec. 27, 2015
  • senfuwen

    Dec. 27, 2015
  • alxcho

    Dec. 25, 2015
  • FelixYang

    Dec. 25, 2015
  • mshang5

    Dec. 25, 2015

MySQL Source Code

Views

Total views

1,399

On Slideshare

0

From embeds

0

Number of embeds

55

Actions

Downloads

30

Shares

0

Comments

0

Likes

13

×