MySQL之SQL語句優化

来源:https://www.cnblogs.com/duizhangz/archive/2022/05/25/16306834.html
-Advertisement-
Play Games

語句優化 即優化器利用自身的優化器來對我們寫的SQL進行優化,然後再將其放入InnoDB引擎中執行。 條件簡化 移除不必要的括弧 select * from x where ((a = 5)); 上面的括弧很沒必要,優化器就會直接去掉。 select * from x where a = 5; 等值 ...


語句優化

即優化器利用自身的優化器來對我們寫的SQL進行優化,然後再將其放入InnoDB引擎中執行。

條件簡化

移除不必要的括弧

select * from x where ((a = 5));

上面的括弧很沒必要,優化器就會直接去掉。

select * from x where a = 5;

等值傳遞

select * from x where b = a and a = 5;

同樣的,雖然是兩列比較,但是a的值只有一個,所以可以優化

select * from x where b = 5 and a = 5;

常量傳遞

select * from x where a = 5 and b > a;

可以優化為

select * from x where a = 5 and b > 5;

移除沒用的條件

select * from x where a < 5 and b > 10 and b > a;

當前兩個條件發生時,最後一個條件必然發生,所以可以優化

select * from x where a < 5 and b > 10;

表達式計算

select * from x where -a > -5;

優化器不會對其進行優化,而且這個壞處很多就是不能使用索引了,所以我們儘量讓列單獨出現,而不是在表達式計算中。

常量表檢測

當表中只有一兩條數據,或則使用主鍵或唯一列的索引等值查詢的話就會被MySQL優化器視為常量表,直接將SQL語句優化成常量。

select * from table1 join table2 on table1.col1 = table2.col2 where table1 = 'a';
select table1的列都作為常量,table2.* from table2 where table1的常量col1 = table2.col2;

外連接消除

外連接呢,首先連接的順序是固定的,故驅動表和被驅動表是固定不變的。所以是不能像內連接一樣交換驅動表的。

但是呢,有一種情況

select * from table1 left join table2 on table1.col1 = table2.col2 where table2.col2 is not null;	

我們設定了table2的列是非空的,這意味著什麼,當table1匹配不到時設置table2列為null,但是卻不滿足搜索條件被過濾掉,所以左連接匹配失敗null相當於是失效的。這個語句和內連接是沒有區別的,直接將其優化為內連接即可。

所以當在外連接出現時,但是被驅動表拒絕空值時,此時外連接和內連接是可以互相轉換的,而內連接可以通過交換驅動表來優化SQL查詢成本。

子查詢優化

子查詢分類

  • 標量子查詢
  • 列子查詢
  • 行子查詢
  • 表子查詢

再分

  • 相關子查詢
  • 不相關子查詢

標量子查詢

不相關標量子查詢

select * from x where key1 = (select y.key1 from y where y.primarykey = 1);

對於不相關的標量子查詢來說,就是先執行子查詢,然後在對外部查詢進行查詢。

相關子查詢

select * from s1 where key1 = (select common_field from s2 where s1.key3 = s2.key3 limit 1);

對於相關的標量子查詢

  1. 首先取出外部的每條滿足自身搜索條件的行,然後傳入子查詢對應列的值。
  2. 計運算元查詢的結果
  3. 在判斷外部key1對於這個子查詢給的結果是否滿足條件,滿足加入結果行。
  4. 繼續迴圈回1,直到遍歷完所有外層表的行。

其實和連接的流程差不多。

優化器對於標量的子查詢並不需要什麼優化,因為對於標量的子查詢來說,數據量還算很小的了。

IN子查詢優化

select * from x where key1 in (select key3 from y);

對於上述不相關的IN查詢來說,如果IN子查詢的參數少的話,還可以試著載入到記憶體,然後讓外層查詢對很多的條件進行比較。

但是如果子查詢數據量一旦大了起來,記憶體無法全部載入完,或導致外層查詢需要比較的參數太多,外層記錄需要對於過多條件進行比較,導致索引無法使用,因為每一次都要使用索引,每次都要比較,還不如直接全表掃描。最後導致性能很低。

物化表優化

MySQL對這種in參數過多時,不會將子查詢在作為外部的參數,而是直接創建一個臨時表來存儲子查詢的結果。

  1. 將臨時表的列為子查詢結果的列,並對其進行去重。
  2. 臨時表經過去重通常不會太大,創建的是Memory的存儲引擎的臨時表,並對其創建哈希索引。

子查詢轉物化表materialized_table後,我們還能將物化表和外層查詢轉換為連接的方式。

select x.* from x inner join materialized_table m on key1 = m.key3;

然後我們就可以用之前計算成本的知識來計算那個作為驅動表更合適了。

只有不相關子查詢才能轉換為物化表

semi-join優化

像上述結果一樣,我們將查詢結果轉換為物化表,然後我們在把物化表轉換為連接的方式。

我們為什麼不能直接將子查詢轉換為連接的方式呢?這就是semi-join優化。

我們可以試試將其轉換為如下語句

select x.* from x join y on key1 = key3;

三種情況

  • 被驅動表y的行不滿足連接條件的,不能加入結果集。
  • 被驅動表y一個key3滿足和驅動表x的key1相等且y表key3有且僅有一條,有一條記錄加入結果集。
  • 被驅動表y有key3滿足連接條件但是一個key3有很多條記錄,就會有多條記錄加入結果集。

能滿足的條件就是y表的key3是主鍵或唯一列,不然就會出現多條的情況,這條語句就不等於原語句了。

但是此時semi join半連接概念的出現,在半連接的情況下,對於驅動表x來說,我們只關心被驅動表y是否有記錄能夠滿足連接條件的,而不關心被驅動表y有幾條能匹配,最後結果集只保存驅動表x的記錄。

實現半連接semi join的方法。PS:semi join半連接只是一個概念。

  • Table pullout (子查詢中表上拉)
    • 當子查詢的查詢列 ( 即select 的列 ) 是主鍵或唯一列,就是我們上面說的直接join 出來即可,因為不會出現多條的情況
  • DuplicateWeedout execution strategy (重覆值消除策略)
    • 我們不是提到上述的我們自己改為join的方法會出現重覆的情況嗎,因為被驅動表的重覆導致驅動表的重覆。
    • 我們就直接創建一個臨時表,把s1連接的結果記錄id (是數據行的id可以這麼理解把) 放入臨時表中,當該數據行再次被加入時臨時表就會拋出主鍵重覆的異常,就不會加入重覆行了。
  • LooseScan execution strategy (鬆散索引掃描)
    • 當子查詢列key1有子查詢表的索引,這樣我們就可以通過索引訪問,對於每個值,只訪問一行,重覆值不再訪問,這樣來防止出現多條記錄。
  • Semi-join Materialization execution strategy (物化表半連接)
    • 不相關子查詢通過物化表的方式物化為臨時表,沒有重覆行的情形,我們可以直接轉換為連接。
  • FirstMatch execution strategy (首次匹配)
    • 取外連接的一條記錄,然後和子查詢進行一條一條的比較。最原始的方法

semi join使用條件:

  • 該子查詢必須是和IN語句組成的布爾表達式,並且在外層的Where和on子句中出現。
  • 外層的搜索條件必須是用and 和in子查詢連接的。
  • 子查詢是單一的查詢,不能union
  • 子查詢不能包含group by、having、聚集函數
  • ...

EXISTS優化

如果不能使用semi join和物化表,我們還可以將in的語句改造成EXISTS語句。

將上述改造為如下語句。

select * from x where exists (select 1 from y where key3 = x.key1)

如果被驅動表key3有索引,就可以使用索引了啊 o( ̄▽ ̄)d。

這個算是下下策了。


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

-Advertisement-
Play Games
更多相關文章
  • 1、引言 最近在查一個bug,查到最後發現是數組越界導致的。數組只有30個位元組,代碼卻向這個數組填充了35個數據,這個bug還是偶現的,查到它確實廢了一番功夫。我就突然想到:C語言為什麼不檢查數組下標呢???先來個demo驗證下 #include<stdio.h> #include<stdlib.h ...
  • 一 、通過雲開發平臺快速創建初始化應用 1.創建相關應用模版請參考鏈接:基於 vue.js 的 SSR 技術—Nuxt.js // 註意在後面提示中,上移下移,按空格選中 Element 2.完成創建後就可以在github中查看到新增的Nuxt倉庫 二 、 本地編寫 流程圖、拓撲圖項目 1.將應用模 ...
  • 思路: 1、執行df -h 找到 帶mnt的行。將結果存入一個文件中。 system("df -h |grep mnt >./extendevinfo.txt"); 也可以直接popen用管道打開,感覺效率可能會更高一些。 2、解析文件中最後/mnt/XXX部分即為掛載路徑。(具體看自己內核掛載路徑 ...
  • 為什麼要使用Nuxt.js Nuxt 基於一個強大的模塊化架構。你可以從 50 多個模塊中進行選擇,讓你的開發變得更快、更簡單。對 PWA 的支持、添加谷歌分析到你的網頁或生成網站地圖,這些功能都無需重新發明輪子來獲得。 Nuxt.js 預設會優化你的應用程式。我們儘可能地利用 Vue.js 和 N ...
  • 一、概述 EFAK(Eagle For Apache Kafka,以前稱為 Kafka Eagle)是一款由國內公司開源的Kafka集群監控系統,可以用來監視kafka集群的broker狀態、Topic信息、IO、記憶體、consumer線程、偏移量等信息,併進行可視化圖表展示。獨特的KQL還可以通過 ...
  • 導讀: 在電商推薦中,除了推送商品的圖片和價格信息外,文案也是商品非常重要的維度。基於編碼器解碼器範式的序列文本生成模型是文案挖掘的核心,但該種方法面臨著兩大技術挑戰:一是文案生成結果不可靠和生成質量不可控,無法滿足業務對電商商品文案內容可靠性的嚴格要求;二是序列文本生成模型經常面臨數據坍塌,比較容 ...
  • DR實驗存在的隱患 DR可能會掛,單點故障 RS可能會掛 解決方案: 解決單點故障 主備:準備多個DR備用機,做好配置,主機掛掉備用機頂上 主主 解決RS會掛的問題 給RS發送請求,如果收到200 ok回覆則說明RS正常 keepalived keepalived就是實現了上述解決方法的工具,檢測w ...
  • 本文介紹資料庫的結構和基本理論,以及資料庫的實際應用。同時還介紹關係資料庫專用的 SQL 語句的書寫方法和規則。 一、資料庫是什麼 本節重點 資料庫是將大量數據保存起來,通過電腦加工而成的可以進行高效訪問的數據集合。 用來管理資料庫的電腦系統稱為資料庫管理系統(DBMS)。 通過使用 DBMS, ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...