日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

mysql in优化_MySQL 探秘: 1 整体架构

發布時間:2023/12/4 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql in优化_MySQL 探秘: 1 整体架构 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

新開坑,計劃做一系列專輯。由于 MySQL 源碼太龐大,不可能面面俱到,先從丁奇《MySQL 實戰 45 講》[1] 案例開始入手,case by case 來做分享。同時強烈推薦丁奇的課,真的是受益匪淺,感謝感謝~~

最新版本己經是 MySQL 8.0 了,和我當初使用 5.5 差距非常大,增加很多實用功能也做了很多優化。對于我個人來講,很陌生,也是重新學習的過程。

案例

本次分享一個 SQL 是如何執行的,先看這個案例,如果訪問不存在的字段,那么報錯是在 MySQL 哪個層呢?

select?a,b?from?mytest.test?where?k?=1;

另外剛畢業時面試百度,問我 mvcc 是在哪一層的,直接就蒙逼了:(

整體架構

mysql arch

提到 MySQL 架構這個圖是必看的,為了支持不同的存儲引擎,分為兩層:Server 層和存儲引擎層。做過 DBA 的都知道,redo, undo log 這些是事務相關的,都屬于引擎層,具體就是 innodb 的,而 binlog 是所有引擎通用的,所以在 Server 層。目前 MySQL 大部分公司只會用過 innodb, 并且也是默認引擎。

tidb arch

同時我們也可以看下最近幾年新興的 TiDB[2] , 整體分層結構并無太大區別,但是因為底層引擎是分布式的 TiKV[3], 所以生成執行計劃與執行器執行還是有很大區別的,并且執行時還要考濾 rpc 超時等等。

Server

Server 層具體包括連接器,查詢緩存,分析器,優化器與執行器。具體看一下每個模塊的作用,后面會用 debug 方式查看

1. 連接器

負責處理新建連接,用戶名密碼認證,接收發送請求等功能。在 thread_handling 默認是 one-thread-per-connection 一個新建連接會新啟動一個線程。

root@myali:~/mysql#?ps?-T?-p?10477?|?wc?-l
28
root@myali:~/mysql#?bin/mysql?-uroot?-h127.0.0.1
mysql>?show?full?processlist;
+----+------+-----------------+------+---------+------+----------+-----------------------+
|?Id?|?User?|?Host????????????|?db???|?Command?|?Time?|?State????|?Info??????????????????|
+----+------+-----------------+------+---------+------+----------+-----------------------+
|??2?|?root?|?localhost:58506?|?NULL?|?Query???|????0?|?starting?|?show?full?processlist?|
+----+------+-----------------+------+---------+------+----------+-----------------------+
1?row?in?set?(0.00?sec)

mysql>?exit
Bye
root@myali:~/mysql#?ps?-T?-p?10477?|?wc?-l
29

可以看到線程個數隨之變化,當然 MySQL 這么做肯定低效,所以開啟線程池或是線程復用 thread_cache_size, 為了測試我把這個參數關掉了。

以前在 ganji 的時候,業務 php 經常會有連接失敗的情況,是個不錯的分析 case 啊:(

2. 查詢緩存

很古老的東西了,最新版本也己廢棄,原因在于效率太低,Query_cache 屬于表級別的,任何更新都會使之失效。

3. 分析器

以前在 ganji 做 SQL 自動上線[4] 時就用到了這塊技術,使用 lex&yacc 技術將一條 sql 解析成 ast 抽象語法樹,然后對之進行 sql 審核后再上線。基本大公司的上線平臺也是同樣套路。

至于 MySQL 這塊也差不多,將 sql 識別成 MySQL 認可的語法,然后交給下一層去執行。據說 TiDB 的 sql parser 實現效率最高,很多 go 的庫也都在使用,以后有機會我也試用下。

4. 優化器

經過 parser 后的 SQL,就知道要獲取什么樣的數據了,但是我們知道 SQL 是一種聲明式語言,不會指導數據庫如何去獲取數據,那么在執行器執行前,就要經過優化器去分析一波,選擇哪個索引合適。這一塊 MySQL 和 TiDB 區別還是很大的,以后有機會再細看。

5. 執行器

MySQL 通過分析器知道 client 要做什么,通過優化器知道 MySQL 該怎么做,于是就進入了執行器階段,開始執行語句。

這一層會對用戶是否有查詢權限進行校驗,如果沒有返回報錯。有的話調用 Innodb 引擎層接口獲取數據,循環獲取滿足條件的行數據。

案例

回到文章開頭的案例,如果字段不存在肯定報錯,這個屬于哪層呢?

cmake?.?-DCMAKE_INSTALL_PREFIX=/root/my-mysql8?\
-DMYSQL_DATADIR=/root/my-mysql8/data?\
-DWITH_BOOST=/root/my-mysql8/boost/boost_1_70_0?\
-DSYSCONFDIR=/etc?\
-DEFAULT_CHARSET=utf8mb4?\
-DDEFAULT_COLLATION=utf8mb4_general_ci?\
-DENABLED_LOCAL_INFILE=1?\
-DWITH_DEBUG=1?\
-DSYSCONFDIR=/root/my-mysql8/etc?\
-DEXTRA_CHARSETS=all

先編譯 MySQL,記住一定要加 WITH_DEBUG 選項

nohup?sh?mysql.server?start?--debug??&

然后啟動并打開調式模式。

bin/mysql?-uroot?-h127.0.0.1?-e?"select?*?from?mytest.test?where?a=1"

trace 文件在 /tmp/mysqld.trace, 我們直接截取 sql 執行的報錯部分展示出來

T@3:?|?|?|?|?>handle_query
T@3:?|?|?|?|?|?THD::enter_stage:?'init'?/root/mysql-5.7.23/sql/sql_select.cc:121
T@3:?|?|?|?|?|?>PROFILING::status_change
T@3:?|?|?|?|?|?<:status_change>T@3:?|?|?|?|?|?>SELECT_LEX::prepare
T@3:?|?|?|?|?|?|?opt:?(null):?starting?struct
T@3:?|?|?|?|?|?|?opt:?join_preparation:?starting?struct
T@3:?|?|?|?|?|?|?opt:?select#:?1
T@3:?|?|?|?|?|?|?>SELECT_LEX::setup_conds
T@3:?|?|?|?|?|?|?|?info:?thd->mark_used_columns:?1
T@3:?|?|?|?|?|?|?|?>find_field_in_table_ref
T@3:?|?|?|?|?|?|?|?|?enter:?table:?'test'??field?name:?'k'??item?name:?'k'??ref?0x7fd620007aa8
T@3:?|?|?|?|?|?|?|?|?>find_field_in_table
T@3:?|?|?|?|?|?|?|?|?|?enter:?table:?'test',?field?name:?'k'
T@3:?|?|?|?|?|?|?|?|?T@3:?|?|?|?|?|?|?|?T@3:?|?|?|?|?|?|?|?>find_field_in_table_ref
T@3:?|?|?|?|?|?|?|?|?enter:?table:?'test'??field?name:?'k'??item?name:?'k'??ref?0x7fd620007aa8
T@3:?|?|?|?|?|?|?|?|?>find_field_in_table
T@3:?|?|?|?|?|?|?|?|?|?enter:?table:?'test',?field?name:?'k'
T@3:?|?|?|?|?|?|?|?|?T@3:?|?|?|?|?|?|?|?T@3:?|?|?|?|?|?|?|?>check_grant_column
T@3:?|?|?|?|?|?|?|?|?enter:?table:?test??want_privilege:?1
T@3:?|?|?|?|?|?|?|?T@3:?|?|?|?|?|?|?|?>my_error
T@3:?|?|?|?|?|?|?|?|?my:?nr:?1054??MyFlags:?0??errno:?2
T@3:?|?|?|?|?|?|?|?|?>my_message_sql
T@3:?|?|?|?|?|?|?|?|?|?error:?error:?1054??message:?'Unknown?column?'k'?in?'where?clause''
T@3:?|?|?|?|?|?|?|?|?|?>mysql_audit_acquire_plugins
T@3:?|?|?|?|?|?|?|?|?|?

可以看到字段不存在的報錯是在 mysql_parse 之后,在 prepare 函數里做的檢查,這一塊屬于 optimize 優化器層前的預處理

另外非常有意思的是,字段不存在的報錯竟然是在檢查權限 check_grant_column 函數中。感興趣的可以自行 debug 看下 trace 文件,可以幫助快速定位源碼與流程。

select 完整流程

通過 trace 文件追蹤了 mysql 源碼,大致清楚了整體流程。比較關鍵的數據結構是 THD, 每個連接一個實例。這個結構光定義就 3300 行代碼,還不包括方法實現... 囧:(

  • login_connection 處理新連接,Global_THD_manager::add_thd 生成 THD,acl_authenticate 用戶認證
  • dispatch_command 分發命令
  • mysql_parse 分析器,主要就是詞法解析 lex_start 和語法解析 parse_sql
  • check_access 檢查 DB 權限,open_tables_for_query 打開 table
  • handle_query 主要就是 prepare 和 optimize
  • exec 調用引擎接口獲取數據,然后 sending_data 給客戶端
  • Global_THD_manager::remove_thd 連接退出
  • 大致 select sql 完整流程就是這些,不包括事務,不包括 innodb 層處理。

    小結

    這次分享參考了《MySQL 實戰 45 講》[1] 第一節,評論的內容也更精彩,推薦大家圍觀。以后面還會分享更多關于 MySQL 的內容,如果感興趣,可以關注并轉發(:

    參考資料

    [1]

    《MySQL 實戰 45 講》: https://time.geekbang.org/column/intro/139,

    [2]

    tidb 源碼分析: https://pingcap.com/blog-cn/tidb-source-code-reading-2/,

    [3]

    tikv 是什么: https://pingcap.com/blog-cn/#TiKV,

    [4]

    sql 自動上線: https://myslide.cn/slides/9070,

    總結

    以上是生活随笔為你收集整理的mysql in优化_MySQL 探秘: 1 整体架构的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。