從Mysql架構看一條查詢sql的執行過程

来源:https://www.cnblogs.com/sharloon/archive/2023/10/28/17794820.html
-Advertisement-
Play Games

1. 基本信息 高性能MySQL:經過大規模運維驗證的策略(第4版) High Performance MySQL, Fourth Edition [美] Silvia Botros(西爾維亞·博特羅斯);Jeremy Tinley(傑里米·廷利) 電子工業出版社,2022年10月出版 1.1. 讀 ...


1. 通信協議

我們的程式或者工具要操作資料庫,第一步要做什麼事情? 跟資料庫建立連接。

首先,MySQL必須要運行一個服務,監聽預設的3306埠。在我們開發系統跟第三方對接的時候,必須要弄清楚的有兩件事。

  • 第一個就是通信協議,比如我們是用HTTP還是WebService還是TCP?

  • 第二個是消息格式,比如我們用XML格式,還是JSON格式,還是定長格式?報文頭長度多少,包含什麼內容,每個欄位的詳細含義。

MySQL是支持多種通信協議的,可以使用同步/非同步的方式,支持長連接/短連接。我們分別來看:

同步通信

同步通信依: 賴於被調用方,受限於被調用方的性能。也就是說,應用操作資料庫,線程會阻塞,等待資料庫的返回。一般只能做到一對一,很難做到一對多的通信。

非同步通信

非同步可以避免應用阻塞等待,但是不能節省SQL執行的時間。

如果非同步存在併發,每一個SQL的執行都要單獨建立一個連接,避免數據混亂。但是這樣會給服務端帶來巨大的壓力(一個連接就會創建一個線程,線程間切換會占用大量CPU資源)。另外非同步通信還帶來了編碼的複雜度,所以一般不建議使用。如果要非同步,必須使用連接池,排隊從連接池獲取連接而不是創建新連接。

長連接與短連接

MySQL既支持短連接,也支持長連接。短連接就是操作完畢以後,馬上close掉。長連接可以保持打開,減少服務端創建和釋放連接的消耗,後面的程式訪問的時候還可以使用這個連接。一般我們會在連接池中使用長連接。

保持長連接會消耗記憶體。長時間不活動的連接,MySQL伺服器會斷開。

showglobalvariableslike'wait_timeout';--非互動式超時時間,如JDBC程式
showglobalvariableslike'interactive_timeout';--互動式超時時間,如資料庫工具

預設都是28800秒,8小時。

可以用showstatus命令:showglobalstatuslike'Thread%';

Threads_cached:緩存中的線程連接數。
Threads_connected:當前打開的連接數。
Threads_created:為處理連接創建的線程數。
Threads_running:非睡眠狀態的連接數,通常指併發連接數。

MySQL支持哪些通信協議呢?

UnixSocket

比如我們在Linux伺服器上,如果沒有指定-h參數,它就用socket方式登錄(省略了-S/var/lib/mysql/mysql.sock)。

它不用通過網路協議,也可以連接到MySQL的伺服器,它需要用到伺服器上的一個物理文件(/var/lib/mysql/mysql.sock)。

select @@socket;

TCP/IP 協議

我們的編程語言的連接模塊都是用 TCP 協議連接到 MySQL 伺服器的,比如 mysql-connector-java-x.x.xx.jar

2. 語法解析和預處理

為什麼一條 SQL 語句能夠被識別呢?假如我隨便執行一個字元串 penyuyan,伺服器報了一個 1064 的錯, 它是怎麼知道我輸入的內容是錯誤的?

[Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the
right syntax to use near 'penyuyan' at line 1

這個就是 MySQL 的 Parser 解析器和 Preprocessor 預處理模塊。 這一步主要做的事情是對語句基於 SQL 語法進行詞法和語法分析和語義的解析。

詞法解析

詞法分析就是把一個完整的 SQL 語句打碎成一個個的單詞。 比如一個簡單的 SQL 語句:

select name from user where id = 1;

它會打碎成 8 個符號,每個符號是什麼類型,從哪裡開始到哪裡結束。

語法解析

語法分析會對 SQL 做一些語法檢查,比如單引號有沒有閉合,然後根據 MySQL 定義的語法規則,根據 SQL 語句生成一個數據結構。這個數據結構我 們把它叫做解析樹(select_lex)

任何資料庫的中間件,比如Mycat,Sharding-JDBC(用到了DruidParser),都必須要有詞法和語法分析功能,在市面上也有很多的開源的詞法解析的工具(比如LEX,Yacc).

預處理器

如果我寫了一個詞法和語法都正確的SQL,但是表名或者欄位不存在,會在哪裡報錯?是在資料庫的執行層還是解析器?比如:

select * from xxx;

解析器可以分析語法,但是它怎麼知道資料庫裡面有什麼表,表裡面有什麼欄位呢?實際上還是在解析的時候報錯,解析SQL的環節裡面有個預處理器。 它會檢查生成的解析樹,解決解析器無法解析的語義。比如,它會檢查表和列名是否存在,檢查名字和別名,保證沒有歧義。預處理之後得到一個新的解析樹。

3.查詢優化(QueryOptimizer)與查詢執行計劃

得到解析樹之後,是不是執行SQL語句了呢?這裡我們有一個問題,一條SQL語句是不是只有一種執行方式?或者說資料庫最終執行的SQL是不是就是我們發送的SQL?

這個答案是否定的。一條SQL語句是可以有很多種執行方式的,最終返回相同的結果,他們是等價的。但是如果有這麼多種執行方式,這些執行方式怎麼得到的?最終選擇哪一種去執行?根據什麼判斷標準去選擇?

這個就是MySQL的查詢優化器的模塊(Optimizer)。 查詢優化器的目的就是根據解析樹生成不同的執行計劃(ExecutionPlan),然後選擇一種最優的執行計劃,MySQL裡面使用的是基於開銷(cost)的優化器,那種執行計劃開銷最小,就用哪種。

可以使用這個命令查看查詢的開銷:

showstatus like 'Last_query_cost';

優化器可以做什麼?

舉兩個簡單的例子:

1、當我們對多張表進行關聯查詢的時候,以哪個表的數據作為基準表。 2、有多個索引可以使用的時候,選擇哪個索引。

實際上,對於每一種資料庫來說,優化器的模塊都是必不可少的,他們通過複雜的演算法實現儘可能優化查詢效率的目標。 如果對於優化器的細節感興趣,可以看看《資料庫查詢優化器的藝術-原理解析與SQL 性能優化》。

但是優化器也不是萬能的,並不是再垃圾的SQL語句都能自動優化,也不是每次都能選擇到最優的執行計劃,大家在編寫SQL語句的時候還是要註意。

優化器是怎麼得到執行計劃的?

首先我們要啟用優化器的追蹤(預設是關閉的):

SHOWVARIABLES LIKE 'optimizer_trace';
set optimizer_trace ='enabled=on';

註意開啟這開關是會消耗性能的,因為它要把優化分析的結果寫到表裡面,所以不要輕易開啟,或者查看完之後關閉它(改成off

接著我們執行一個SQL語句,優化器會生成執行計劃:

select t.tcid from teacher t, teacher_contact tc wheret.tcid=tc.tcid;

這個時候優化器分析的過程已經記錄到系統表裡面了,我們可以查詢:

select * from information_schema.optimizer_trace\G

它是一個JSON類型的數據,主要分成三部分,準備階段、優化階段和執行階段。

expanded_query是優化後的SQL語句。
considered_execution_plans裡面列出了所有的執行計劃。

優化器得到的結果

優化器最終會把解析樹變成一個查詢執行計劃,查詢執行計劃是一個數據結構。當然,這個執行計劃是不是一定是最優的執行計劃呢?不一定,因為MySQL也有可能覆蓋不到所有的執行計劃。

我們怎麼查看MySQL的執行計劃呢?比如多張表關聯查詢,先查詢哪張表?在執行查詢的時候可能用到哪些索引,實際上用到了什麼索引?

MySQL提供了一個執行計劃的工具。我們在SQL語句前面加上EXPLAIN,就可以看到執行計劃的信息。

EXPLAIN select name from user where id=1;

*註意Explain的結果也不一定最終執行的方式。

4.存儲引擎

得到執行計劃以後,SQL語句是不是終於可以執行了? 問題又來了:

1、從邏輯的角度來說,我們的數據是放在哪裡的,或者說放在一個什麼結構裡面?
2、執行計劃在哪裡執行?是誰去執行?

存儲引擎基本介紹

我們先回答第一個問題:在關係型資料庫裡面,數據是放在什麼結構裡面的?

放在表Table裡面的 我們可以把這個表理解成Excel電子錶格的形式。所以我們的表在存儲數據的同時,還要組織數據的存儲結構,這個存儲結構就是由我們的存儲引擎決定的,所以我們也可以把存儲引擎叫做表類型。

查看存儲引擎

比如我們資料庫裡面已經存在的表,我們怎麼查看它們的存儲引擎呢?

show table status from `xxx`;

在MySQL裡面,我們創建的每一張表都可以指定它的存儲引擎,而不是一個資料庫只能使用一個存儲引擎。存儲引擎的使用是以表為單位的。而且,創建表之後還可以修改存儲引擎。

我們說一張表使用的存儲引擎決定我們存儲數據的結構,那在伺服器上它們是怎麼存儲的呢?我們先要找到資料庫存放數據的路徑:

showvariableslike'datadir';

預設情況下,每個資料庫有一個自己文件夾,任何一個存儲引擎都有一個frm文件,這個是表結構定義文件。 不同的存儲引擎存放數據的方式不一樣,產生的文件也不一樣,innodb是1個,memory沒有,myisam是兩個。

這些存儲引擎的差別在哪呢?

存儲引擎比較

MyISAMInnoDB是我們用得最多的兩個存儲引擎,在MySQL5.5版本之前,預設的存儲引擎是MyISAM,它是MySQL自帶的。我們創建表的時候不指定存儲引擎,它就會使用MyISAM作為存儲引擎.

MyISAM的前身是ISAM(IndexedSequentialAccessMethod:利用索引,順序存取數據的方法).

5.5版本之後預設的存儲引擎改成了InnoDB,它是第三方公司為MySQL開發的。為什麼要改呢?最主要的原因還是InnoDB支持事務,支持行級別的鎖,對於業務一致性要求高的場景來說更適合。

MyISAM

應用範圍比較小。表級鎖定限制了讀/寫的性能,因此在Web和數據倉庫配置中,它通常用於只讀或以讀為主的工作。 特點:

  • 支持表級別的鎖(插入和更新會鎖表)。不支持事務。

  • 擁有較高的插入(insert)和查詢(select)速度。

  • 存儲了表的行數(count速度更快)。

InnoDB

mysql5.7中的預設存儲引擎。InnoDB是一個事務安全(與ACID相容)的MySQL 存儲引擎,它具有提交、回滾和崩潰恢復功能來保護用戶數據。InnoDB行級鎖(不升級為更粗粒度的鎖)和Oracle風格的一致非鎖讀提高了多用戶併發性和性能。InnoDB將用戶數據存儲在聚集索引中,以減少基於主鍵的常見查詢的I/O。為了保持數據完整性, InnoDB還支持外鍵引用完整性約束。 特點:

  • 支持事務,支持外鍵,因此數據的完整性、一致性更高。

  • 支持行級別的鎖和表級別的鎖。

  • 支持讀寫併發,寫不阻塞讀(MVCC)。

  • 特殊的索引存放方式,可以減少IO,提升查詢效率。

  • 適合:經常更新的表,存在併發讀寫或者有事務處理的業務系統.

Memory

將所有數據存儲在RAM中,以便在需要快速查找非關鍵數據的環境中快速訪問。這個引擎以前被稱為堆引擎。其使用案例正在減少;InnoDB及其緩衝池記憶體區域提供了一種通用、持久的方法來將大部分或所有數據保存在記憶體中,而ndbcluster為大型分散式數據集提供了快速的鍵值查找。 特點:

  • 把數據放在記憶體裡面,讀寫的速度很快,但是資料庫重啟或者崩潰,數據會全部消失。只適合做臨時表。

CSV

它的表實際上是帶有逗號分隔值的文本文件。csv表允許以csv格式導入或轉儲數據,以便與讀寫相同格式的腳本和應用程式交換數據。因為csv表沒有索引,所以通常在正常操作期間將數據保存在innodb表中,並且只在導入或導出階段使用csv表。 特點: 特點:不允許空行,不支持索引。格式通用,可以直接編輯,適合在不同資料庫之間導入導出。

Archive

這些緊湊的未索引的表用於存儲和檢索大量很少引用的歷史、存檔或安全審計信息。 特點:

  • 不支持索引,不支持updatedelete。

如何選擇存儲引擎?

  • 如果對數據一致性要求比較高,需要事務支持,可以選擇InnoDB。

  • 如果數據查詢多更新少,對查詢性能要求比較高,可以選擇MyISAM。

  • 如果需要一個用於查詢的臨時表,可以選擇Memory。

5. 執行引擎

存儲引擎分析完了,它是我們存儲數據的形式,繼續第二個問題,是誰使用執行計划去操作存儲引擎呢?

這就是我們的執行引擎,它利用存儲引擎提供的相應的API來完成操作。

為什麼我們修改了表的存儲引擎,操作方式不需要做任何改變?因為不同功能的存儲引擎實現的API是相同的。

最後把數據返回給客戶端,即使沒有結果也要返回。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 雷達圖(Radar Chart),也被稱為蛛網圖或星型圖,是一種用於可視化多個變數之間關係的圖表形式。雷達圖是一種顯示多變數數據的圖形方法。通常從同一中心點開始等角度間隔地射出三個以上的軸,每個軸代表一個定量變數,各軸上的點依次連接成線或幾何圖形。 雷達圖可以用來在變數間進行對比,或者查看變數中有沒 ...
  • 不想裝golang,不想裝IDE,還想有個流暢的運行環境,最重要的是一分錢都不想花,嗯嗯,GitHub雲開發環境全部滿足你,一切操作盡在本文 ...
  • 什麼是快捷代碼段:例如: 只需要輸入mst後按一下TAB就會自動生成代碼memset(str, 0, sizeof(str));,只需要輸入Pow就可以自動生成一個快速冪函數等等,非常方便快捷,一定程度提高了編寫代碼的效率 Visual Studio 設置自定義代碼段方法:①新建文件XXX.snip ...
  • 圖片特征向量是一種用於描述圖片內容的數學表示,它可以反映圖片的顏色、紋理、形狀等信息。圖片特征向量可以用於做很多事情,比如圖片檢索、分類、識別等。 本文將介紹圖片特征向量的提取以及相似度的計算,並使用C#來實現它們。 文章開始前,我們先來簡單瞭解一下 OpenCV 和 OpenCvSharp4,這兩 ...
  • 最近玩《星露穀物語》上癮,本來是看著個休閑游戲,現在玩成修仙游戲了,上百個小時渾身是肝,中午午休習慣都強行給改了。 雖然挺有意思,但是太肝了,入坑前請謹慎。補充一下,這個游戲應該是基於 XNA/MonoGame 寫的。 這個游戲在喪失焦點的時候會自動暫停,無法自動推進,我覺得效率太低了,為了齊先生的 ...
  • 本章將和大家分享在 Windows 系統上如何搭建 Elasticsearch 的開發環境。話不多說,下麵我們直接進入主題。 一、安裝Java的JDK Elasticsearch 其中最主要的開發語言就是 Java ,所以我們在安裝 Elasticsearch 之前,首先需要安裝的就是 Java 的 ...
  • 一、 前言 OpenSSH 的加密功能需要用到OpenSSL,所以在升級OpenSSH的時候,大部分情況是需要將OpenSSL一起升級的。 這裡我們選擇先升級OpenSSL到OpenSSL 1.1.1w 11 Sep 2023 然後再升級OpenSSH 到OpenSSH_9.5p1, OpenSSL ...
  • 1. 概念 1.1. 實體 1.1.1. 通常用名詞來表示 1.1.2. 描述一個領域中的事物或者事物類型 1.1.2.1. 汽車 1.1.2.2. 用戶 1.1.2.3. 地理位置 1.1.3. 在邏輯模型和技術實現過程中,實體通常會變成“頂點” 1.2. 關係 1.2.1. 用動詞(或動詞短語) ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...