MySQL查詢執行的基礎——查詢優化處理

来源:https://www.cnblogs.com/AmosH/archive/2019/01/11/10256407.html
-Advertisement-
Play Games

查詢的生命周期的下一步是將一個SQL轉換成一個可執行計劃,MySQL再按照這個計劃和存儲引擎進行交互 ...


查詢的生命周期的下一步是將一個SQL轉換成一個可執行計劃,MySQL再按照這個計劃和存儲引擎進行交互

語法解析器和預處理

首先,MySQL通過關鍵詞將SQL語句進行解析,並生成一顆對應的“解析樹”。MySQL解析器將使用MySQL語法規則驗證和解析查詢。比如是否使用了錯誤的關鍵字,關鍵字的順序是否正確,或者引號是否能夠正確的前後匹配。

預處理器則會根據一些MySQL規則進一步檢查解析樹是否合法。它會檢查數據表和數據列是否存在,還會解析名字和別名,看看它們是否存在歧義。

查詢優化器

當語法樹被認為是合法的時候,將轉由優化器去轉化成執行計劃。一條查詢可以有很多種執行方式,最後都返回相同的結果。優化器的作用就是找到這其中最好的執行計劃。

MySQL使用的是基於成本的優化器,它將會嘗試預測一個查詢使用某種執行計劃時的成本,並選擇其中成本最小的那一個。可以通過查詢當前會話的“Last_query_cost”的值來的值MySQL計算的當前查詢的成本。

優化器估算查詢成本

這個結果表示MySQL的優化器認為大概需要做1040個數據頁的隨機查找才能夠完成上面的查詢。這是根據一系列的統計信息計算的來的。優化器在評估成本時並不會考慮任何層面的緩存,它假設讀取任何數據都需要一次磁碟I/O。

有很多種情況會導致MySQL優化器選擇錯誤的執行計劃,如下所示:

  • 統計信息不准確。 MySQL依賴存儲引擎提供的統計信息來評估成本,但是有的存儲引擎提供的信息偏差非常大。比如InnoDB因為使用了MVCC架構,並不能維護一個數據表的行數的精確統計信息。
  • 執行計劃中的成本估算不等同於實際執行的成本。 所以及時統計信息精準,優化器給出的執行計劃也可能不是最優的。比如某個執行計劃雖然需要讀取很多的頁面,但是如果這些頁面都是順序讀取獲取已經在記憶體中了的話,那麼訪問它的成本將非常小。
  • MySQL的最優可能和我們想的最優是不同的。 我們理解的最優是執行時間儘可能短,但是MySQL只是基於其成本模型選擇最優的執行計劃,而有些時候並不是最快的執行方式。
  • MySQL從不考慮其他正在併發執行的查詢,這可能會影響當前查詢的速度。
  • MySQL並不是任何時候都基於成本的優化。 有時候它也會基於一些固定的規則,比如存在全文搜索的MATCH()子句時,MySQL會選擇使用全文索引而不是使用其他更快的索引或者WHERE條件。
  • MySQL不會考慮不受其控制的操作的成本,比如執行存儲過程或者用戶自定義函數的成本。
  • 優化器有時候無法去估算所有可能的執行計劃,所以可能會錯過實際上最優的執行計劃。

MySQL的查詢優化器是一個非常複雜的不見,它使用了很多優化策略來生成一個最優的執行計劃。優化策略可以簡單的分為兩種,一種是靜態優化,一種是動態優化

靜態優化可以直接對解析樹進行分析,並完成優化。例如通過一些簡單的袋鼠變換將WHERE條件轉換成另一種等價形式,可以認為是一種“編譯時優化”。

動態優化則是和查詢的上下文相關,也可能和很多其他因素有關,這些需要在每次查詢時重新評估,可以認為是“運行時優化”

在執行語句和存儲過程的時候,動態優化和靜態優化的區別很重要。MySQL對查詢的靜態優化只需要做一次,但是對查詢的動態優化則在每次執行時都需要重新評估。有時候甚至在查詢的執行過程中也會重新優化。

下麵是一些MySQL可以處理的優化類型:

  1. 重新定義關聯表的順序
  2. 將外連接轉化為內連接
  3. 使用等價變換規則。 它可以合併和減少一些比較,還可以移除一些恆成立和一些恆不成立的判斷。
  4. 優化COUNT()、MIN()和MAX()。 索引和列是否為空通常可以幫助MySQL優化這類表達式。比如需要找到某一列的最小值,只需要查詢對應B-Tree索引的最左端記錄即可。
  5. 預估並轉化為常量表達式。 當MySQL檢測到一個表達式可以轉化為常數時,就會一直把該表達式作為常數進行優化處理。
  6. 覆蓋索引掃描。 當索引中的列包含所有查詢中需要使用的列的時候,MySQL就可以使用索引返回需要的數據,而無需查詢對應的數據行。
  7. 子查詢優化
  8. 提前終止查詢。 當發現已經滿足查詢需求的時候,MySQL總是能夠立刻終止查詢。一個典型的例子就是當使用了LIMIT 子句的時候。
  9. 等值傳播。 如果兩個列的值通過等式關聯,那麼MySQL能夠把其中一個列的WHERE條件傳遞到另一列上。
  10. 列表IN()的比較。 在很多的資料庫系統中,IN()完全等同於多個OR條件的子句,因為這兩者是完全等價的。但是在MySQL中,它將IN()列表中的數據先進行排序,然後通過二分查找的方式來確定列表中的值是否滿足條件,這是一個O(log n)複雜度的操作,等價轉換為OR查詢的複雜度為O(n)。對於IN()列表中有大量取值的時候,MySQL的處理速度會更快。

上面列舉的並不是MySQL優化器的全部,MySQL還會做其他大量的優化,因此我們完全沒有必要嘗試“自己會比優化器更加聰明”,這樣不僅會讓查詢更加複雜而難以維護,並且最終收益可能為0.讓優化器按照自己的方式正常工作即可。

但是如果能夠確認優化器給出的並不是最佳選擇,並且清除背後的原理那麼也可以嘗試幫助優化器作進一步的優化。比如在查詢中添加hint提示,也可以重寫查詢或者重新設計庫表結構。

數據和索引的統計信息

MySQL在伺服器層有查詢優化器,但是沒有保存數據和索引的統計信息。統計信息由存儲引擎實現,不同的存儲引擎可能會存儲不同的統計信息或者按照不同的格式存儲統計信息。

MySQL如何執行關聯操作

MySQL中的“關聯(join)”比一般意義上理解的更加廣泛。總的來說,MySQL認為任何一個查詢都是一次“關聯”——並不僅僅是一個查詢需要用到兩張表的匹配才叫關聯。

以UNION查詢為例MySQL先將一系列的單個查詢結果放到一個臨時表中,然後再重新讀出臨時表數據來完成UNION查詢。

當前MySQL關聯執行的策略如下:MySQL對任何關聯都執行嵌套迴圈關聯操作,即MySQL現在一個表中迴圈取出單條數據,然後再嵌套迴圈到下一個表中尋找匹配的行,依次下去,直到找到所有表中匹配的行為止。然後根據各個表匹配的行,返回查詢中需要的各個列。MySQL會嘗試在最後一個關聯表中查找到所有匹配的行,如果最後一個關聯表無法找到更多的行以後,MySQL就會返回上一層次關聯表,看是否能夠找到更多的匹配記錄,以此類推迭代執行。

執行計劃

和很多其他關係型資料庫不同,MySQL並不會生成查詢位元組碼來執行查詢。MySQL生成查詢的一棵指令書,然後通過存儲引擎執行完成這棵指令書並返回結果。最終的執行計劃包含了重構查詢的全部信息

關聯查詢優化器

MySQL優化器最重要的一部分就是關聯查詢優化,它決定了多個表關聯時的順序。通常多表關聯時,可以有多種不同的關聯順序來獲得相同的結果。

關聯查詢優化器則通過評估不同順序時的成本來選擇一個代價最小的關聯順序。它會遍歷每一個表然後逐個做嵌套迴圈計算每一棵可能的執行計劃樹的成本,最後返回一個最優的執行計劃。

然而,如果有超過n個表的關聯,那麼需要檢查n的階乘種關聯順序。這被稱為可能的執行計劃的“搜索空間”,搜索空間的增長速度非常快,如果我們需要關聯10個表,那麼共有3628800種不同的關聯順序。

當搜索空間非常大時,優化器會選擇使用“貪婪”搜索的方式查找“最優”的關聯順序。有時候,各個查詢的順序是不能隨意安排的,比如左連接等,這時候關聯優化器就可以根據這些規則大大減少搜索空間。

排序優化

無論如何排序都是一個成本很高的操作,所以從性能上看,應該儘可能避免排序或者儘可能避免對大量數據進行排序。

當不能使用索引生成排序結果的時候,MySQL需要自己進行排序。如果數據量小則在記憶體中進行,如果數據量大則需要使用磁碟,不過MySQL將這個過程統一稱為文件排序(filesort),即使完全是記憶體排序不需要任何磁碟文件時也是如此。

如果需要排序的數據量小於“排序緩衝區”,MySQL使用記憶體進行“快速排序”操作。如果記憶體不夠排序,那麼MySQL會將數據分塊,對每個獨立的塊使用“快速排序”進行排序,將各個塊的排序結果存放在磁碟上然後將各個排好序的快進行合併,最終返回排序結果。


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

-Advertisement-
Play Games
更多相關文章
  • 一 Kubernetes概述 Kubernetes是一個全新的基於容器技術的分散式架構領先方案。Kubernetes(k8s)是Google開源的容器集群管理系統(谷歌內部:Borg)。在Docker技術的基礎上,為容器化的應用提供部署運行、資源調度、服務發現和動態伸縮等一系列完整功能,提高了大規模 ...
  • 使用hostname 進行修改。 創建用戶,修改密碼 ...
  • 一、背景 在平時開發過程當中需要針對 MySQL 資料庫進行監控,這裡我們可以使用 Grafana 和 Prometheus 來實現監控功能。Grafana 是一款功能強大的儀錶盤面板,支持多種數據源,可以自定義圖表進行監控。而 Prometheus 就是 Grafana 支持的數據源之一,Prom ...
  • 本文收錄在容器技術學習系列文章總目錄 1、製作鏡像 1.1 鏡像的生成途徑 基於容器製作 dockerfile,docker build 本篇主要詳細講解基於容器製作鏡像;基於dockerfile 製作鏡像在後一張文章Docker系列07—Dockerfile 詳解中詳細介紹; 1.2 基於容器製作 ...
  • 一、安裝步驟 1. 添加企業版附加包。 2. 安裝 PIP。 3. 更新 PIP。 4. 安裝 Docker Compose 二、可能遇到的問題 在執行 命令的時候可能會提示以下內容: 這個時候,你需要執行以下命令強制重新安裝 request。 安裝完成之後,Docker Compose 安裝成功。 ...
  • 關鍵字:SQL Server NEWID();BSON;MongoDB UUID 1.遇到的問題和困惑 SQL Server中的NEWID數據存儲到MongoDB中會是什麼樣子呢?發現不能簡單的通過此數據查詢了。 例如我們將SQL Server 資料庫中的QQStatements2019表遷移至Mo ...
  • 首次安裝資料庫,一般按照傻瓜式操作,So easy! 但是當我們的機器之前安裝過,現在要重新安裝的時候,總會遇到很多問題。不管是Oracle,還是MySQL,還是其他一些涉及到註冊表、服務的軟體。都很麻煩。現在來一步步解決吧。 ...
  • 不同伺服器資料庫表連接查詢,修改 exec sp_addlinkedserver 'ERP','','SQLOLEDB','10.0.10.0' exec sp_addlinkedsrvlogin 'ERP','false',null,'sa','123456' 在伺服器端-連接伺服器可以看到'10 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...