亚欧色一区w666天堂,色情一区二区三区免费看,少妇特黄A片一区二区三区,亚洲人成网站999久久久综合,国产av熟女一区二区三区

  • 發布文章
  • 消息中心
點贊
收藏
評論
分享
原創

MySQL是如何得到一個客戶端命令的?

2024-09-05 09:26:34
14
0

MySQL是如何得到一個客戶端命令的?

因為在線程池中看到AliSQL的優化,其中說到改進到在線程池中做到:
 接收到一個請求之后,先讀取網絡包,在根據包的進行操作類型的識別,然后得到SQL語句,然后可以根據SQL的類型與上下文將其分類:

  • 查詢操作,會話處于自動提交模式,SQL類型為查詢語句。
  • 更新操作,會話處于自動提交模式,SQL類型為DML語句。
  • 事務操作,會話處于事務模式(start transaction或autocommit=0)下的任何語句。
  • 管理操作,以上之外的操作,比如“show”、“set”等操作。

所以在解析器執行之前對SQL進行分類,是到底是怎么做到的呢? 通過源碼來做一個分析

Server等待客戶端的請求

在mysql原生的連接管理方式中每線程每連接,每個連接會阻塞在get_command這個函數里,等待客戶端的請求
在這之前會設置阻塞的時間(net_wait_timeout默認8小時),超時后會退出

> do_command
  > my_net_set_read_timeout(net, thd->variables.net_wait_timeout)
  > thd->get_protocol()->get_command()

而在percona線程池中,其通過監聽線程(listener)來監聽(epoll方式)事件,如果客戶端有數據可以讀,那么監聽線程會把這個連接分配給一個工作線程去處理(也可能自己處理)
這里可以注意到,工作線程處理時,在正常情況下,到了get_command()的時候一定是有數據的,不用等待

一步步讀取網絡包

> Protocol_classic::get_command()
  > read_packet()
    > my_net_read()
      > net_read_compressed_packet()/net_read_uncompressed_packet() // 壓縮/未壓縮
        > net_read_packet()           // 這里可能會有多個包,超過最大長度
          > net_read_packet_header()  // 讀取包頭 包括協議頭,大小和數量
            > net_read_raw_loop()     // 讀取包頭
          > net_read_raw_loop()       // 讀取包的內容
            > vio_read()              // 循環讀取
              > mysql_socket_recv()
                > recv()              // 接收socket緩存區的數據
  > parse_packet()                    // 解析包

解析數據包

parse_packet()函數把網絡包解析并保存

格式:

Type Name Description
int<1> 執行命令 執行的操作,比如切換數據庫,查詢表等操作
string 參數 命令相關的內容

第一個參數是執行的命令類型(enum_server_command),如COM_QUERY,COM_INIT_DB等
 第二個參數是命令相關的內容,如果COM_INIT_DB保存切換的數據庫名,COM_QUERY保存了執行的SQL及參數等

如何區分不同的SQL

在線程池的處理階段,我們可以通過從網絡包中解析到客戶端執行命令的類型,但是有一個問題:
由于事務在do_command階段還需要解析,意味著每個請求的網絡包會被解析兩次,第一次需要通過MSG_PEEK的方式讀取,即不會清空緩沖區,這樣第二次仍然可以讀取到網絡包

通過解析數據包,可以很容易的區別不同的server_command,直接通過返回的網絡包的第一個字節即可判斷

如何區分COM_QUERY命令中執行的SQL,沒有通過解析器解析SQL,只能通過字符串匹配的方式來獲取信息,這樣獲取到的信息是不足的

再看AliSQL的區分的:

  • 查詢操作,會話處于自動提交模式,SQL類型為查詢語句。
  • 更新操作,會話處于自動提交模式,SQL類型為DML語句。
  • 事務操作,會話處于事務模式(start transaction或autocommit=0)下的任何語句。
  • 管理操作,以上之外的操作,比如“show”、“set”等操作。

只能通過簡單的字符串匹配select,來確定是否是查詢語句
通過匹配insert,update,delete來確定是否是DML
可以通過thd_is_transaction_active()來判斷是否開啟事務

0條評論
0 / 1000
qinyl
6文章數
0粉絲數
qinyl
6 文章 | 0 粉絲
qinyl
6文章數
0粉絲數
qinyl
6 文章 | 0 粉絲
原創

MySQL是如何得到一個客戶端命令的?

2024-09-05 09:26:34
14
0

MySQL是如何得到一個客戶端命令的?

因為在線程池中看到AliSQL的優化,其中說到改進到在線程池中做到:
 接收到一個請求之后,先讀取網絡包,在根據包的進行操作類型的識別,然后得到SQL語句,然后可以根據SQL的類型與上下文將其分類:

  • 查詢操作,會話處于自動提交模式,SQL類型為查詢語句。
  • 更新操作,會話處于自動提交模式,SQL類型為DML語句。
  • 事務操作,會話處于事務模式(start transaction或autocommit=0)下的任何語句。
  • 管理操作,以上之外的操作,比如“show”、“set”等操作。

所以在解析器執行之前對SQL進行分類,是到底是怎么做到的呢? 通過源碼來做一個分析

Server等待客戶端的請求

在mysql原生的連接管理方式中每線程每連接,每個連接會阻塞在get_command這個函數里,等待客戶端的請求
在這之前會設置阻塞的時間(net_wait_timeout默認8小時),超時后會退出

> do_command
  > my_net_set_read_timeout(net, thd->variables.net_wait_timeout)
  > thd->get_protocol()->get_command()

而在percona線程池中,其通過監聽線程(listener)來監聽(epoll方式)事件,如果客戶端有數據可以讀,那么監聽線程會把這個連接分配給一個工作線程去處理(也可能自己處理)
這里可以注意到,工作線程處理時,在正常情況下,到了get_command()的時候一定是有數據的,不用等待

一步步讀取網絡包

> Protocol_classic::get_command()
  > read_packet()
    > my_net_read()
      > net_read_compressed_packet()/net_read_uncompressed_packet() // 壓縮/未壓縮
        > net_read_packet()           // 這里可能會有多個包,超過最大長度
          > net_read_packet_header()  // 讀取包頭 包括協議頭,大小和數量
            > net_read_raw_loop()     // 讀取包頭
          > net_read_raw_loop()       // 讀取包的內容
            > vio_read()              // 循環讀取
              > mysql_socket_recv()
                > recv()              // 接收socket緩存區的數據
  > parse_packet()                    // 解析包

解析數據包

parse_packet()函數把網絡包解析并保存

格式:

Type Name Description
int<1> 執行命令 執行的操作,比如切換數據庫,查詢表等操作
string 參數 命令相關的內容

第一個參數是執行的命令類型(enum_server_command),如COM_QUERY,COM_INIT_DB等
 第二個參數是命令相關的內容,如果COM_INIT_DB保存切換的數據庫名,COM_QUERY保存了執行的SQL及參數等

如何區分不同的SQL

在線程池的處理階段,我們可以通過從網絡包中解析到客戶端執行命令的類型,但是有一個問題:
由于事務在do_command階段還需要解析,意味著每個請求的網絡包會被解析兩次,第一次需要通過MSG_PEEK的方式讀取,即不會清空緩沖區,這樣第二次仍然可以讀取到網絡包

通過解析數據包,可以很容易的區別不同的server_command,直接通過返回的網絡包的第一個字節即可判斷

如何區分COM_QUERY命令中執行的SQL,沒有通過解析器解析SQL,只能通過字符串匹配的方式來獲取信息,這樣獲取到的信息是不足的

再看AliSQL的區分的:

  • 查詢操作,會話處于自動提交模式,SQL類型為查詢語句。
  • 更新操作,會話處于自動提交模式,SQL類型為DML語句。
  • 事務操作,會話處于事務模式(start transaction或autocommit=0)下的任何語句。
  • 管理操作,以上之外的操作,比如“show”、“set”等操作。

只能通過簡單的字符串匹配select,來確定是否是查詢語句
通過匹配insert,update,delete來確定是否是DML
可以通過thd_is_transaction_active()來判斷是否開啟事務

文章來自個人專欄
文章 | 訂閱
0條評論
0 / 1000
請輸入你的評論
0
0