MySQL調優02 - SQL語句的優化

SQL語句的優化

文章目錄

  • SQL語句的優化
    • 一:SQL優化的小技巧
      • 1:編寫SQL時的注意點
        • 1.1:查詢時盡量不要使用*
        • 1.2:連表查詢時盡量不要關聯太多表
        • 1.3:多表查詢時一定要以小驅大
        • 1.4:like不要使用左模糊或者全模糊
        • 1.5:查詢時盡量不要對字段做空值判斷
        • 1.6:不要在條件查詢=前對字段做任何運算
        • 1.7:!=、!<>、not in、or...要慎用
        • 1.8:必要情況下可以強制指定索引
        • 1.9:避免頻繁創建、銷毀臨時表
        • 1.10:盡量將大事務拆分為小事務執行
        • 1.11:從業務設計層面減少大量數據返回的情況
        • 1.12:盡量避免深分頁的情況出現
        • 1.13:SQL務必要寫完整,不要使用縮寫法
        • 1.14:基于聯合索引查詢時請務必確保字段的順序性
        • 1.15:客戶端的一些操作可以批量化完成
        • 1.17:明確僅返回一條數據的語句可以使用limit 1
      • 2:業內標準
        • 2.1:3秒原則和5秒原則
        • 2.2:mysql的500ms原則
    • 二:MySQL索引優化
      • 1:explain分析工具
        • 1.1:id字段
        • 1.2:select_type字段
        • 1.3:table字段
        • 1.4:partitions字段
        • 1.5:type字段
        • 1.6:possible_keys字段
        • 1.7:key字段
        • 1.8:key_len字段
        • 1.9:ref字段
        • 1.10:rows字段
        • 1.11:filtered字段
        • 1.12:extra字段
      • 2:索引優化參考項

一:SQL優化的小技巧

1:編寫SQL時的注意點

1.1:查詢時盡量不要使用*

除非確確實實的想要返回所有的字段,并且字段個數比較多。至于為什么不建議使用 *,有如下幾點原因:

網絡開銷變大

當使用*時,查詢時每條數據會返回所有字段值,然后這些查詢出的數據會先被放到結果集中,最終查詢完成后會統一返回給客戶端

但線上Java程序和MySQL都是分機器部署的,所以返回數據時需要經過網絡傳輸,而由于返回的是所有字段數據,因此網絡數據包的體積就會變大

從而導致占用的網絡帶寬變高,影響數據傳輸的性能和資源開銷。

但實際上可能僅需要用到其中的某幾個字段值,所以寫清楚字段后查詢,能讓網絡數據包體積變小,從而減小資源消耗、提升響應速度。

分析成本變高

一條SQL在執行前都會經過分析器解析,當使用時,解析器需要先去解析出當前要查詢的表上表示哪些字段,因此會額外增加解析成本。

如果明確寫出了查詢字段,分析器則不會有這一步解析*的開銷。

內存占用變高

當查詢一條數據時都會將其結果集放入到BufferPool的數據緩沖頁中,如果每次用*來查詢數據,查到的結果集自然會更大,占用的內存也會越大

單個結果集的數據越大,整個內存緩沖池中能存下的數據也就越少

當其他SQL操作時,在內存中找不到數據,又會去觸發磁盤IO,最終導致MySQL整體性能下降。

維護性變差

正常情況下,我們都使用半ORM框架Mybatis進行開發【針對java】,而一般為了對應查詢結果與實體對象的關系,通常都需要配置resultMap來聲明表字段和對象屬性的映射關系

如果每次使用*來查詢數據,當表結構發生變更時,就算變更的字段結構在當前業務中用不到,也需要去維護已經配置好的resultMap,所以會導致維護性變差。但聲明了需要的字段時,配置的resultMap和查詢字段相同,因此當變更的表結構不會影響當前業務時,也無需變更當前的resultMap。

1.2:連表查詢時盡量不要關聯太多表

一旦關聯太多的表,就會導致執行效率變慢,執行時間變長,原因如下:

  • 數據量會隨表數量呈直線性增長,數據量越大檢索效率越低。
  • 當關聯的表數量過多時,無法控制好索引的匹配,涉及的表越多,索引不可控風險越大。

交互型業務和后臺型業務

  • 交互型的業務中,關聯的表數量應當控制在5張表之內

  • 后臺型的業務由于不考慮用戶體驗感,有時候業務比較復雜,又需要關聯十多張表做查詢,此時可以這么干,但按照《高性能MySQL》上的推薦,最好也要控制在16~18張表之內(阿里開發規范中要求控制在3張表以內)。

1.3:多表查詢時一定要以小驅大

所謂的以小驅大即是指用小的數據集去驅動大的數據集,說簡單一點就是先查小表,再用小表的結果去大表中檢索數據

其實在MySQL的優化器也會有驅動表的優化,當執行多表聯查時,MySQL的關聯算法為Nest Loop Join

該算法會依照驅動表的結果集作為循環基礎數據,然后通過該結果集中一條條數據,作為過濾條件去下一個表中查詢數據,最后合并結果得到最終數據集,MySQL優化器選擇驅動表的邏輯如下:

  • 如果指定了連接條件,滿足查詢條件的小數據表作為驅動表。
  • 如果未指定連接條件,數據總行數少的表作為驅動表。

如果在做連表查詢時,你不清楚具體用誰作為驅動表,哪張表去join哪張表,這時可以交給MySQL優化器自己選擇

但有時候優化器不一定能夠選擇正確,因此寫SQL時最好自己去選擇驅動表,小表放前,大表放后!

1.4:like不要使用左模糊或者全模糊

如若like關鍵字以%號開頭會導致索引失效,從而導致SQL觸發全表查詢,因此需要使用模糊查詢時,千萬要避免%xxx、%xxx%這兩種情況出現

實在需要使用這兩類模糊查詢時,可以適當建立全文索引來代替,數據量較大時可以使用ES、Solr…這類搜索引擎來代替。

1.5:查詢時盡量不要對字段做空值判斷
select * from xxx where yyy is null;
select * from xxx where yyy not is null;

當出現基于字段做空值判斷的情況時,會導致索引失效,因為判斷null的情況不會走索引,因此切記要避免這樣的情況

一般在設計字段結構的時候,請使用not null來定義字段

同時如果想為空的字段,可以設計一個0、""這類空字符代替:

  • 一方面要查詢空值時可通過查詢空字符的方式走索引檢索
  • 另一方面也能避免MyBatis注入對象屬性時觸發空指針異常。
1.6:不要在條件查詢=前對字段做任何運算
select * from users where user_id * 2 = 8;
select * from users where trim(user_name) = "張三";

users用戶表中user_id、user_name字段上都創建了索引,但上述這類情況都不會走索引

因為MySQL優化器在生成執行計劃時,發現這些=前面涉及到了邏輯運算,因此就不會繼續往下走了,會將具體的運算工作留到執行時完成

也正是由于優化器沒有繼續往下走,因此不會為運算完成后的字段選擇索引,最終導致索引失效走全表查詢。

所以不要在條件查詢=前對字段做任何運算

1.7:!=、!<>、not in、or…要慎用

總之,就是各種可能導致索引失效的寫法要慎用,在實際過程中可以使用其他的一些語法代替,比如or可以使用union all來代替:

select user_name from zz_users where user_id=1 or user_id=2;
-- 可以替換成:
select user_name from zz_users where user_id=1
union all
select user_name from zz_users where user_id=2;
1.8:必要情況下可以強制指定索引

在表中存在多個索引時,有些復雜SQL的情況下,或者在存儲過程中,必要時可強制指定某條查詢語句走某個索引

因為MySQL優化器面對存儲過程、復雜SQL時并沒有那么智能,有時可能選擇的索引并不是最好的,這時我們可以通過force index,如下:

select * from users force index(unite_index) where user_name = "張三";

這樣就能夠100%強制這條SQL走某個索引查詢數據

🎉 這種強制指定索引的方式,一定要建立在對索引結構足夠熟悉的情況下,否則效果會適得其反。

1.9:避免頻繁創建、銷毀臨時表

臨時表是一種數據緩存,對于一些常用的查詢結果可以為其建立臨時表,這樣后續要查詢時可以直接基于臨時表來獲取數據

MySQL默認會在內存中開辟一塊臨時表數據的存放空間,所以走臨時表查詢數據是直接基于內存的,速度會比走磁盤檢索快上很多倍。

但一定要切記一點,只有對于經常查詢的數據才對其建立臨時表,不要盲目的去無限制創建,否則頻繁的創建、銷毀會對MySQL造成不小的負擔。

1.10:盡量將大事務拆分為小事務執行

一個事務在執行事,如果其中包含了寫操作,會先獲取鎖再執行,直到事務結束后MySQL才會釋放鎖。

而一個事務占有鎖之后,會導致其他要操作相同數據的事務被阻塞

如果當一個事務比較大時,會導致一部分數據的鎖定周期較長,在高并發情況下會引起大量事務出現阻塞,從而最終拖垮整個MySQL系統。

show status like ‘innodb_log_waits’;查看是否有大事務由于redo_log_buffer不足,而在等待寫入日志。

大事務也會導致日志寫入時出現阻塞,這種情況下會強制觸發刷盤機制

大事務的日志需要阻塞到有足夠的空間時,才能繼續寫入日志到緩沖區,這也可能會引起線上出現阻塞。

1.11:從業務設計層面減少大量數據返回的情況

如果一次性返回的數據量過于巨大時,就會引起網絡阻塞、內存占用過高、資源開銷過大的各類問題出現

因此如果項目中存在這類業務,一定要記住拆分掉它,比如分批返回給客戶端。

分批查詢的方式也被稱之為增量查詢,每次基于上次返回數據的界限,再一次讀取一批數據返回給客戶端,這也就是經典的分頁場景

通過分頁的思想能夠提升單次查詢的速度,以及避免大數據量帶來的一系列后患問題。

1.12:盡量避免深分頁的情況出現

分頁雖然比較好,但也依舊存在問題,也就是深分頁問題,如下:

select xx,xx,xx from yyy limit 100000,10; 

上述語句在MySQL的實際執行過程中,會先查詢出100010條數據,然后丟棄前面的10W條數據,將最后10條數據返回,這個過程無異極其浪費資源。

對于深分頁,有下面兩種方式解決

  • 如果查詢出的結果集,存在遞增且連續的字段,可以基于有序字段來進一步做篩選后再獲取分頁數據
select xx,xx,xx from yyy where 有序字段 >= nnn limit 10; -- 例如
-- 第一頁
select xx,xx,xx from yyy where 有序字段 >= 1 limit 10; 
-- 第二頁
select xx,xx,xx from yyy where 有序字段 >= 11 limit 10; 
-- 第N頁.....-- 第10000頁
select xx,xx,xx from yyy where 有序字段 >= 100001 limit 10; 
  • 在業務上限制深分頁的情況,以百度為例

在這里插入圖片描述
一般用戶最多看前面30頁,如果還未找到他需要的內容,基本上就會換個更精準的關鍵詞重新搜索。

如果業務必須要求展現所有分頁數據,此時又不存在遞增的連續字段咋辦?

  • 要么選擇之前哪種很慢的分頁方式
  • 要么就直接拋棄所有!每次隨機十條數據出來給用戶,如果不想重復的話,每次新的分頁時,再對隨機過的數據加個標識即可。
1.13:SQL務必要寫完整,不要使用縮寫法

在寫的時候為了圖簡單,都會將一些能簡寫的SQL就簡寫,但其實這種做法也略微有些問題

因為隱式的這種寫法,在MySQL底層都需要做一次轉換,將其轉換為完整的寫法

因此簡寫的SQL會比完整的SQL多一步轉化過程,如果你考慮極致程度的優化,也切記將SQL寫成完整的語法。

1.14:基于聯合索引查詢時請務必確保字段的順序性

最左前綴原則,不再贅述

雖然8.0版本中推出索引跳躍掃描機制,但會存在較大的開銷,同時還有很強的局限性,所以最好在寫SQL時,依舊遵循索引的最左前綴原則撰寫。

1.15:客戶端的一些操作可以批量化完成

批量新增某些數據、批量修改某些數據的狀態…,這類需求在一個項目中也比較常見,一般的做法如下:

for (xxObject obj : xxObjs) {xxDao.insert(obj);
}/*** xxDao.insert(obj)對應的SQL如下:* insert into tb_xxx values(......);
**/

這種情況確實可以實現批量插入的效果,但是每次都需要往MySQL發送SQL語句,會帶來額外的網絡開銷以及耗時,因此上述實現可以更改為如下:

xxDao.insertBatch(xxObjs);/*** xxDao.insertBatch(xxObjs)對應的SQL如下:* insert into tb_xxx values(......),(......),(......),(......),.....;
**/

這樣會組合成一條SQL發送給MySQL執行,能夠在很大程度上節省網絡資源的開銷,提升批量操作的執行效率。

🎉 這樣的方式同樣適用于修改場景

1.17:明確僅返回一條數據的語句可以使用limit 1
select * from users where user_name = "張三";
select * from users where user_name = "張三" limit 1;

加上limit 1關鍵字后,當程序匹配到一條數據時就會停止掃描,如果不加的情況下會將所有數據都掃描一次。

所以一般情況下,如果確定了只需要查詢一條數據,就可以加上limit 1提升性能。

2:業內標準

2.1:3秒原則和5秒原則
  • 客戶端訪問時,能夠在1s內得到響應,用戶會覺得系統響應很快,體驗非常好。
  • 客戶端訪問時,1~3秒內得到響應,處于可以接受的階段,其體驗感還算不錯。
  • 客戶端訪問時,需要等待3~5秒時才可響應,這是用戶就感覺比較慢了,體驗有點糟糕。
  • 客戶端訪問時,一旦響應超過5秒,用戶體驗感特別糟糕,通常會選擇離開或刷新重試。

上述這四條是用戶體驗感的四個等級,一般針對于C端業務而言,基本上都需要將接口響應速度控制到第二等級,即最差也要三秒內給用戶返回響應

否則會導致體驗感極差,從而讓用戶對產品留下不好的印象。

所謂的三秒原則通常是基于C端業務而言的,對于B端業務來說,通常用戶的容忍度會高一些,也包括B端業務的業務邏輯會比C端更為復雜一些,所以可將響應速度控制到第三等級,也就是5s內能夠得到響應。

針對于一些特殊類型的業務,如后臺計算型的業務,好比跑批對賬、定時調度…等,這類因為本身業務就特殊,因此可不關注其響應速度。

2.2:mysql的500ms原則

用戶感受到的響應速度會由多方面的耗時組成,如下:

在這里插入圖片描述

所謂給用戶的響應時間其實會包含各方面的耗時,也就是這所有的過程加一塊兒,必須要在1~3s內給出響應

而SQL耗時屬于「系統耗時→數據操作耗時」這部分,因此留給SQL語句執行的時間最多只能有500ms

一般在用戶量較大的門戶網站中,甚至要求控制在10ms、30ms、50ms以內

二:MySQL索引優化

1:explain分析工具

在之前的’正確建立和使用索引‘簡單的說了一下這個工具,是自帶的一個執行分析工具,可使用于select、insert、update、delete、repleace等語句上,需要使用時只需在SQL語句前加上一個explain關鍵字即可,然后MySQL會對應語句的執行計劃列出

在這里插入圖片描述

1.1:id字段

這是執行計劃的ID值,一條SQL語句可能會出現多步執行計劃,所以會出現多個ID值,這個值越大,表示執行的優先級越高,同時還會出現四種情況:

  • ID相同:當出現多個ID相同的執行計劃時,從上往下挨個執行。
  • ID不同時:按照ID值從大到小依次執行。
  • ID有相同又有不同:先從大到小依次執行,碰到相同ID時從上往下執行。
  • ID為空:ID=null時,會放在最后執行。
1.2:select_type字段

當前執行的select語句其具體的查詢類型,有如下取值:

  • SIMPLE:簡單的select查詢語句,不包含union、子查詢語句。
  • PRIMARY:union或子查詢語句中,最外層的主select語句。
  • SUBQUEPY:包含在主select語句中的第一個子查詢,如select … xx = (select …)。
  • DERIVED:派生表,指包含在from中的子查詢語句,如select … from (select …)。
  • DEPENDENT SUBQUEPY:復雜SQL中的第一個select子查詢(依賴于外部查詢的結果集)。
  • UNCACHEABLE SUBQUERY:不緩存結果集的子查詢語句。
  • UNION:多條語句通過union組成的查詢中,第二個以及更后面的select語句。
  • UNION RESULT:union的結果集。
  • DEPENDENT UNION:含義同上,但是基于外部查詢的結果集來查詢的。
  • UNCACHEABLE UNION:含義同上,但查詢出的結果集不會加入緩存。
  • MATERIALIZED:采用物化的方式執行的包含派生表的查詢語句。

這個字段主要是說明當前查詢語句所屬的類型,以及在整條大的查詢語句中,當前這個查詢語句所屬的位置。

1.3:table字段

表示當前這個執行計劃是基于哪張表執行的,這里會寫出表名,但有時候也不一定是物理磁盤中存在的表名,還有可能出現如下格式:

  • <derivenN>:基于id=N的查詢結果集,進一步檢索數據。
  • <unionM,N>:會出現在查詢類型為UNION RESULT的計劃中,表示結果由id=M,N…的查詢組成。
  • <subqueryN>:基于id=N的子查詢結果,進一步進行數據檢索。
  • <tableName>:基于磁盤中已創建的某張表查詢。

一句話總結就是:這個字段會寫明,當前的這個執行計劃會基于哪個數據集查詢,有可能是物理表、有可能是子查詢的結果、也有可能是其他查詢生成的派生表。

1.4:partitions字段

這個字段在早版本的explain工具中不存在,這主要是用來顯示分區的,因為后續版本的MySQL中支持表分區,該列的值表示檢索數據的分區。

1.5:type字段

該字段表示當前語句執行的類型,可能出現的值如下:

  • all:全表掃描,基于表中所有的數據,逐行掃描并過濾符合條件的數據。
  • index:全索引掃描,和全表掃描類似,但這個是把索引樹遍歷一次,會比全表掃描要快。
  • range:基于索引字段進行范圍查詢,如between、<、>、in…等操作時出現的情況。
  • index_subquery:和上面含義相同,區別:這個是基于非主鍵、唯一索引字段進行in操作。
  • unique_subquery:執行基于主鍵索引字段,進行in操作的子查詢語句會出現的情況。
  • index_merge:多條件查詢時,組合使用多個索引來檢索數據的情況。
  • ref_or_null:基于次級(非主鍵)索引做條件查詢時,該索引字段允許為null出現的情況。
  • fulltext:基于全文索引字段,進行查詢時出現的情況。
  • ref:基于非主鍵或唯一索引字段查找數據時,會出現的情況。
  • eq_ref:連表查詢時,基于主鍵、唯一索引字段匹配數據的情況,會出現多次索引查找。
  • const:通過索引一趟查找后就能獲取到數據,基于唯一、主鍵索引字段查詢數據時的情況。
  • system:表中只有一行數據,這是const的一種特例。
  • null:表中沒有數據,無需經過任何數據檢索,直接返回結果。

這個字段的值很重要,它決定了MySQL在執行一條SQL時,訪問數據的方式,性能從好到壞依次為:

  • 完整的性能排序:null → system → const → eq_ref → ref → fulltext → ref_or_null → index_merge → unique_subquery → index_subquery → range → index → all
  • 常見的性能排序:system → const → eq_ref → ref → fulltext → range → index → all

一般在做索引優化時,一般都會要求最好優化到ref級別,至少也要到range級別,也就是最少也要基于次級索引來檢索數據,不允許出現index、all這類全掃描的形式。

1.6:possible_keys字段

這個字段會顯示當前執行計劃,在執行過程中可能會用到哪些索引來檢索數據

?? 可能會用到并不代表一定會用,在某些情況下,就算有索引可以使用,MySQL也有可能放棄走索引查詢。

1.7:key字段

前面的possible_keys字段表示可能會用到的索引,而key這個字段則會顯示具體使用的索引

一般情況下都會從possible_keys的值中,綜合評判出一個性能最好的索引來進行查詢,但也有兩種情況會出現key=null的這個場景:

  • possible_keys有值,key為空:多半是由于表中數據不多,因此MySQL會放棄索引,選擇走全表查詢,也有可能是因為SQL導致索引失效。
  • possible_keys、key都為空:表示當前表中未建立索引、或查詢語句中未使用索引字段檢索數據。

默認情況下,possible_keys有值時都會從中選取一個索引,但這個選擇的工作是由MySQL優化器自己決定的

如果你想讓查詢語句執行時走固定的索引,則可以通過force index、ignore index的方式強制指定。

1.8:key_len字段

這個表示對應的執行計劃在執行時,使用到的索引字段長度,一般情況下都為索引字段的長度,但有三種情況例外:

  • 如果索引是前綴索引,這里則只會使用創建前綴索引時,聲明的前N個字節來檢索數據。
  • 如果是聯合索引,這里只會顯示當前SQL會用到的索引字段長度,可能不是全匹配的情況。
  • 如果一個索引字段的值允許為空,key_len的長度會為:索引字段長度+1。
1.9:ref字段

顯示索引查找過程中,查詢時會用到的常量或字段:

  • const:如果顯示這個,則代表目前是在基于主鍵字段值或數據庫已有的常量(如null)查詢數據。
    • select … where 主鍵字段 = 主鍵值;
    • select … where 索引字段 is null;
  • 顯示具體的字段名:表示目前會基于該字段查詢數據。
  • func:如果顯示這個,則代表當與索引字段匹配的值是一個函數,如:
    • select … where 索引字段 = 函數(值);
1.10:rows字段

這一列代表執行時,預計會掃描的行數

這個數字對于InnoDB表來說,其實有時并不夠準確,但也具備很大的參考價值

如果這個值很大,在執行查詢語句時,其效率必然很低,所以該值越小越好。

1.11:filtered字段

這個字段在早版本中也不存在,它是一個百分比值,意味著表中不會掃描的數據百分比

該值越小則表示執行時會掃描的數據量越大,取值范圍是0.00~100.00。

1.12:extra字段

該字段會包含MySQL執行查詢語句時的一些其他信息,這個信息對索引調優而言比較重要,可以帶來不小的參考價值

這個字段會出現的值有很多種,如下:

  • Using index:表示目前的查詢語句,使用了索引覆蓋機制拿到了數據。
  • Using where:表示目前的查詢語句無法從索引中獲取數據,需要進一步做回表去拿表數據。
  • Using temporary:表示MySQL在執行查詢時,會創建一張臨時表來處理數據。
  • Using filesort:表示會以磁盤+內存完成排序工作,而完全加載數據到內存來完成排序。
  • Select tables optimized away:表示查詢過程中,對于索引字段使用了聚合函數。
  • Using where;Using index:表示要返回的數據在索引中包含,但并不是索引的前導列,需要做回表獲取數據。
  • NULL:表示查詢的數據未被索引覆蓋,但where條件中用到了主鍵,可以直接讀取表數據。
  • Using index condition:和Using where類似,要返回的列未完全被索引覆蓋,需要回表。
  • Using join buffer (Block Nested Loop):連接查詢時驅動表不能有效的通過索引加快訪問速度時,會使用join-buffer來加快訪問速度,在內存中完成Loop匹配。
  • Impossible WHERE:where后的條件永遠不可能成立時提示的信息,如where 1!=1。
  • Impossible WHERE noticed after reading const tables:基于唯一索引查詢不存在的值時出現的提示。
  • const row not found:表中不存在數據時會返回的提示。
  • distinct:去重查詢時,找到某個值的第一個值時,會將查找該值的工作從去重操作中移除。
  • Start temporary, End temporary:表示臨時表用于DuplicateWeedout半連接策略,也就是用來進行semi-join去重。
  • Using MRR:表示執行查詢時,使用了MRR機制讀取數據。
  • Using index for skip scan:表示執行查詢語句時,使用了索引跳躍掃描機制讀取數據。
  • Using index for group-by:表示執行分組或去重工作時,可以基于某個索引處理。
  • FirstMatch:表示對子查詢語句進行Semi-join優化策略。
  • No tables used:查詢語句中不存在from子句時提示的信息,如desc table_name;。

🎉 基于Extra字段做個性能排序:Using index → NULL → Using index condition → Using where → Using where;Using index → Using join buffer → Using filesort → Using MRR → Using index for skip scan → Using temporary → Strart temporary,End temporary → FirstMatch

2:索引優化參考項

在做索引優化時,值得咱們參考的幾個字段為:

  • key:如果該值為空,則表示未使用索引查詢,此時需要調整SQL或建立索引。
  • type:這個字段決定了查詢的類型,如果為indexall就需要進行優化。
  • rows:這個字段代表著查詢時可能會掃描的數據行數,較大時也需要進行優化。
  • filtered:這個字段代表著查詢時,表中不會掃描的數據行占比,較小時需要進行優化。
  • Extra:這個字段代表著查詢時的具體情況,在某些情況下需要根據對應信息進行優化。

在explain語句后面緊跟著show warings語句,可以得到優化后的查詢語句,從而看出優化器優化了什么。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/68097.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/68097.shtml
英文地址,請注明出處:http://en.pswp.cn/web/68097.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

langchain教程-12.Agent/工具定義/Agent調用工具/Agentic RAG

前言 該系列教程的代碼: https://github.com/shar-pen/Langchain-MiniTutorial 我主要參考 langchain 官方教程, 有選擇性的記錄了一下學習內容 這是教程清單 1.初試langchain2.prompt3.OutputParser/輸出解析4.model/vllm模型部署和langchain調用5.DocumentLoader/多種文檔…

如何實現網頁不用刷新也能更新

要實現用戶在網頁上不用刷新也能到下一題&#xff0c;可以使用 前端和后端交互的技術&#xff0c;比如 AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;、Fetch API 或 WebSocket 來實現局部頁面更新。以下是一個實現思路&#xff1a; 1. 使用前端 AJAX 或 Fetch…

在ubuntu22.04上先部署docker,再編譯安裝kamailio,附詳細操作流程及docker和makailio的版本號

以下是在Ubuntu 22.04上部署Docker并編譯安裝Kamailio的詳細操作流程&#xff0c;包含版本號信息&#xff1a; 一、部署Docker&#xff08;版本&#xff1a;24.0.7&#xff09; 更新系統包 sudo apt update && sudo apt upgrade -y安裝依賴工具 sudo apt install -y ap…

大模型中提到的超參數是什么

在大模型中提到的超參數是指在模型訓練之前需要手動設置的參數&#xff0c;這些參數決定了模型的訓練過程和最終性能。超參數與模型內部通過訓練獲得的參數&#xff08;如權重和偏置&#xff09;不同&#xff0c;它們通常不會通過訓練自動學習&#xff0c;而是需要開發者根據任…

位運算及常用技巧

涉及位運算的運算符如下表所示&#xff1a; 位運算的運算律&#xff1a; 負數的位運算 首先&#xff0c;我們要知道&#xff0c;在計算機中&#xff0c;運算是使用的二進制補碼&#xff0c;而正數的補碼是它本身&#xff0c;負數的補碼則是符號位不變&#xff0c;其余按位取反…

組合總和III(力扣216)

這道題在回溯的基礎上加入了剪枝操作。回溯方面我就不過多贅述&#xff0c;與組合(力扣77)-CSDN博客 大差不差&#xff0c;主要講解一下剪枝(下面的代碼也有回溯操作的詳細注釋)。我們可以發現&#xff0c;如果我們遞歸到后面&#xff0c;可能集合過小&#xff0c;無法滿足題目…

hot100(8)

71.10. 正則表達式匹配 - 力扣&#xff08;LeetCode&#xff09; 動態規劃 題解&#xff1a;10. 正則表達式匹配題解 - 力扣&#xff08;LeetCode&#xff09; 72.5. 最長回文子串 - 力扣&#xff08;LeetCode&#xff09; 動態規劃 1.dp數組及下標含義 dp[i][j] : 下標i到…

二進制/源碼編譯安裝httpd 2.4,提供系統服務管理腳本并測試

方法一&#xff1a;使用 systemd 服務文件 安裝所需依賴 yum install gcc make apr-devel apr-util-devel pcre-devel 1.下載源碼包 wget http://archive.apache.org/dist/httpd/httpd-2.4.62.tar.gz 2.解壓源碼 tar -xf httpd-2.4.62.tar.gz cd httpd-2.4.62 3.編譯安裝 指定…

Java 中 LinkedList 的底層源碼

在 Java 的集合框架中&#xff0c;LinkedList是一個獨特且常用的成員。它基于雙向鏈表實現&#xff0c;與數組結構的集合類如ArrayList有著顯著差異。深入探究LinkedList的底層源碼&#xff0c;有助于我們更好地理解其工作原理和性能特點&#xff0c;以便在實際開發中做出更合適…

Level2逐筆成交逐筆委托數據分享下載:20250127

Level2逐筆成交逐筆委托數據分享下載 采用Level2逐筆成交與逐筆委托的毫秒級數據&#xff0c;可以揭露眾多有用信息&#xff0c;如莊家策略、偽裝交易&#xff0c;讓所有交易行為透明化。這對于交易高手的策略分析極為有用&#xff0c;對人工智能領域的機器學習也極為合適&…

金蝶云星空k3cloud webapi報“java.lang.Class cannot be cast to java.lang.String”的錯誤

最近在對接金蝶云星空k3cloud webapi時&#xff0c;報一個莫名其妙的轉換異常&#xff0c;具體如下&#xff1a; 同步部門異常! ERP接口登錄異常&#xff1a;java.lang.Class cannot be cast to java.lang.String at com.jkwms.k3cloudSyn.service.basics.DeptK3CloudService.…

【Android】jni開發之導入opencv和libyuv來進行圖像處理

做視頻圖像處理時需要對其進行水印的添加&#xff0c;放在應用層調用工具性能方面不太滿意&#xff0c;于是當下采用opencvlibyuv方法進行處理。 對于Android的jni開發不是很懂&#xff0c;我的需求是導入opencv方便在cpp中調用&#xff0c;但目前找到的教程都是把opencv作為模…

【MySQL】centos 7 忘記數據庫密碼

vim /etc/my.cnf文件&#xff1b; 在[mysqld]后添加skip-grant-tables&#xff08;登錄時跳過權限檢查&#xff09; 重啟MySQL服務&#xff1a;sudo systemctl restart mysqld 登錄mysql&#xff0c;輸入mysql –uroot –p&#xff1b;直接回車&#xff08;Enter&#xff09; 輸…

國產編輯器EverEdit - 自定義標記使用詳解

1 自定義標記使用詳解 1.1 應用場景 當閱讀日志等文件&#xff0c;用于調試或者檢查問題時&#xff0c;往往日志中會有很多關鍵性的單詞&#xff0c;比如&#xff1a;ERROR, FATAL等&#xff0c;但由于文本模式對這些關鍵詞并沒有突出顯示&#xff0c;造成檢查問題時&#xff…

Golang 并發機制-6:掌握優雅的錯誤處理藝術

并發編程可能是提高軟件系統效率和響應能力的一種強有力的技術。它允許多個工作負載同時運行&#xff0c;充分利用現代多核cpu。然而&#xff0c;巨大的能力帶來巨大的責任&#xff0c;良好的錯誤管理是并發編程的主要任務之一。 并發代碼的復雜性 并發編程增加了順序程序所不…

數據庫并發策略

并發控制是數據庫管理中的一個重要方面&#xff0c;它確保多個事務能夠正確地訪問和修改數據&#xff0c;同時保持數據的一致性和完整性。樂觀鎖、悲觀鎖和時間戳是并發控制的三種主要方法。以下是對這三種方法的詳細解析&#xff0c;并結合實踐進行分析&#xff1a; 一、樂觀…

JVM 四虛擬機棧

虛擬機棧出現的背景 由于跨平臺性的設計&#xff0c;Java的指令都是根據棧來設計的。不同平臺CPU架構不同&#xff0c;所以不能設計為基于寄存器的。優點是跨平臺&#xff0c;指令集小&#xff0c;編譯器容易實現&#xff0c;缺點是性能下降&#xff0c;實現同樣的功能需要更多…

鼠標拖尾特效

文章目錄 鼠標拖尾特效一、引言二、實現原理1、監聽鼠標移動事件2、生成拖尾元素3、控制元素生命周期 三、代碼實現四、使用示例五、總結 鼠標拖尾特效 一、引言 鼠標拖尾特效是一種非常酷炫的前端交互效果&#xff0c;能夠為網頁增添獨特的視覺體驗。它通常通過JavaScript和C…

6-圖像金字塔與輪廓檢測

文章目錄 6.圖像金字塔與輪廓檢測(1)圖像金字塔定義(2)金字塔制作方法(3)輪廓檢測方法(4)輪廓特征與近似(5)模板匹配方法6.圖像金字塔與輪廓檢測 (1)圖像金字塔定義 高斯金字塔拉普拉斯金字塔 高斯金字塔:向下采樣方法(縮小) 高斯金字塔:向上采樣方法(放大)…

RNN/LSTM/GRU 學習筆記

文章目錄 RNN/LSTM/GRU一、RNN1、為何引入RNN&#xff1f;2、RNN的基本結構3、各種形式的RNN及其應用4、RNN的缺陷5、如何應對RNN的缺陷&#xff1f;6、BPTT和BP的區別 二、LSTM1、LSTM 簡介2、LSTM如何緩解梯度消失與梯度爆炸&#xff1f; 三、GRU四、參考文獻 RNN/LSTM/GRU …