日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

教你如何定位及优化SQL语句的性能问题

發布時間:2023/12/3 数据库 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 教你如何定位及优化SQL语句的性能问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自? ?教你如何定位及優化SQL語句的性能問題

在現如今的軟件開發中,關系型數據庫是做數據存儲最重要的工具。無論是Oracale還是Mysql,都是需要通過SQL語句來和數據庫進行交互的,這種交互我們通常稱之為CRUD。在CRUD操作中,最最常用的也就是Read操作了。而對于不同的表結構,采用不同的SQL語句,性能上可能千差萬別。本文,就基于MySql數據庫,來介紹一下如何定位SQL語句的性能問題。

對于低性能的SQL語句的定位,最重要也是最有效的方法就是使用執行計劃。

一、執行計劃

我們知道,不管是哪種數據庫,或者是哪種數據庫引擎,在對一條SQL語句進行執行的過程中都會做很多相關的優化,對于查詢語句,最重要的優化方式就是使用索引。

而執行計劃,就是顯示數據庫引擎對于SQL語句的執行的詳細情況,其中包含了是否使用索引,使用什么索引,使用的索引的相關信息等。

基本語法

explain?select?...

mysql的explain 命令可以用來分析select 語句的運行效果。

除此之外,explain 的extended 擴展能夠在原本explain的基礎上額外的提供一些查詢優化的信息,這些信息可以通過mysql的show warnings命令得到。

mysql> explain extended select * from account; ******** 1. row ***************************id: 1 select_type: SIMPLEtable: accounttype: ALL possible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: 1filtered: 100.00Extra: 1 row in set, 1 warning (0.00 sec)mysql> show warnings; *************1. row *************************** Level: NoteCode: 1003 Message: select?`dbunit`.`account`.`id`?AS?`id`,`dbunit`.`account`.`name`?AS?`name`?from?`dbunit`.`account` 1 row in set (0.00 sec)

另外,對于分區表的查詢,需要使用partitions命令。

explain?partitions?select?...

?

二、執行計劃包含的信息

不同版本的Mysql和不同的存儲引擎執行計劃不完全相同,但基本信息都差不多。mysql執行計劃主要包含以下信息:

id

由一組數字組成。表示一個查詢中各個子查詢的執行順序;

  • id相同執行順序由上至下。

  • id不同,id值越大優先級越高,越先被執行。

  • id為null時表示一個結果集,不需要使用它查詢,常出現在包含union等查詢語句中。

select_type

每個子查詢的查詢類型,一些常見的查詢類型。

idselect_typedescription
1SIMPLE不包含任何子查詢或union等查詢
2PRIMARY包含子查詢最外層查詢就顯示為?PRIMARY
3SUBQUERY在select或?where字句中包含的查詢
4DERIVEDfrom字句中包含的查詢
5UNION出現在union后的查詢語句中
6UNION RESULT從UNION中獲取結果集,例如上文的第三個例子

?

table

查詢涉及到的數據表。

如果查詢使用了別名,那么這里顯示的是別名,如果不涉及對數據表的操作,那么這顯示為null,如果顯示為尖括號括起來的<derived N>就表示這個是臨時表,后邊的N就是執行計劃中的id,表示結果來自于這個查詢產生。如果是尖括號括起來的<union M,N>,與<derived N>類似,也是一個臨時表,表示這個結果來自于union查詢的id為M,N的結果集。

?

type

訪問類型

  • ALL?? 掃描全表數據

  • index?遍歷索引

  • range?索引范圍查找

  • index_subquery?在子查詢中使用 ref

  • unique_subquery?在子查詢中使用 eq_ref

  • ref_or_null?對Null進行索引的優化的 ref

  • fulltext?使用全文索引

  • ref?? 使用非唯一索引查找數據

  • eq_ref?在join查詢中使用PRIMARY KEYorUNIQUE NOT NULL索引關聯。

  • const?使用主鍵或者唯一索引,且匹配的結果只有一條記錄。

  • system const?連接類型的特例,查詢的表為系統表。

性能從好到差依次為:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL,除了ALL之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一個索引。

所以,如果通過執行計劃發現某張表的查詢語句的type顯示為ALL,那就要考慮添加索引,或者更換查詢方式,使用索引進行查詢。

?

possible_keys

可能使用的索引,注意不一定會使用。查詢涉及到的字段上若存在索引,則該索引將被列出來。當該列為?NULL時就要考慮當前的SQL是否需要優化了。

?

key

顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示為NULL。

TIPS:查詢中若使用了覆蓋索引(覆蓋索引:索引的數據覆蓋了需要查詢的所有數據),則該索引僅出現在key列表中。

select_type為index_merge時,這里可能出現兩個以上的索引,其他的select_type這里只會出現一個。

?

key_length

索引長度 char()、varchar()索引長度的計算公式:

(Character?Set:utf8mb4=4,utf8=3,gbk=2,latin1=1) * 列長度 +?1(允許null) +?2(變長列)

其他類型索引長度的計算公式: ex:

CREATE?TABLE?`student`?(`id`?int(11)?unsigned?NOT?NULL?AUTO_INCREMENT,`name`?varchar(128)?NOT?NULL?DEFAULT?'',`age`?int(11),PRIMARY?KEY?(`id`),UNIQUE?KEY?`idx`?(`name`),KEY?`idx_age`?(`age`) )?ENGINE=InnoDB?AUTO_INCREMENT=2?DEFAULT?CHARSET=utf8mb4;

name 索引長度為: 編碼為utf8mb4,列長為128,不允許為NULL,字段類型為varchar(128)。key_length = 128 * 4 + 0 + 2 = 514;

age 索引長度:int類型占4位,允許null,索引長度為5。

?

ref

表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值

如果是使用的常數等值查詢,這里會顯示const,如果是連接查詢,被驅動表的執行計劃這里會顯示驅動表的關聯字段,如果是條件使用了表達式或者函數,或者條件列發生了內部隱式轉換,這里可能顯示為func

?

rows

返回估算的結果集數目,注意這并不是一個準確值。

?

extra

extra的信息非常豐富,常見的有:?

  • Using index 使用覆蓋索引

  • Using where 使用了用where子句來過濾結果集

  • Using filesort 使用文件排序,使用非索引列進行排序時出現,非常消耗性能,盡量優化。

  • Using temporary 使用了臨時表。

  • ?

    一些SQL優化建議

    1、SQL語句不要寫的太復雜。

    一個SQL語句要盡量簡單,不要嵌套太多層。

    2、使用『臨時表』緩存中間結果。

    簡化SQL語句的重要方法就是采用臨時表暫存中間結果,這樣可以避免程序中多次掃描主表,也大大減少了阻塞,提高了并發性能。

    3、使用like的時候要注意是否會導致全表掃

    有的時候會需要進行一些模糊查詢比如

    select?id?from?table?where?username?like?‘%hollis%’

    關鍵詞%hollis%,由于hollis前面用到了“%”,因此該查詢會使用全表掃描,除非必要,否則不要在關鍵詞前加%,

    4、盡量避免使用!=或<>操作符

    在where語句中使用!=或<>,引擎將放棄使用索引而進行全表掃描。

    5、盡量避免使用?or?來連接條件

    在?where?子句中使用?or?來連接條件,引擎將放棄使用索引而進行全表掃描。

    可以使用select?id?from?t?where?num=10 union?all select?id?from?t?where?num=20替代 select?id?from?t?where?num=10?or?num=20

    6、盡量避免使用in和not in

    在?where?子句中使用?in和not in,引擎將放棄使用索引而進行全表掃描。

    可以使用select?id?from?t?where?num?between?10?and?20替代 select?id?from?t?where?num?in?(10,20)

    7、可以考慮強制查詢使用索引

    select?*?from?table?force?index(PRI)?limit?2;(強制使用主鍵)select?*?from?table?force?index(hollis_index)?limit?2;(強制使用索引"hollis_index")select?*?from?table?force?index(PRI,hollis_index)?limit?2;(強制使用索引"PRI和hollis_index")

    8、盡量避免使用表達式、函數等操作作為查詢條件

    9、盡量避免大事務操作,提高系統并發能力。

    10、盡量避免使用游標

    11、任何地方都不要使用?select?*?from?t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。

    12、盡可能的使用?varchar/nvarchar?代替?char/nchar

    13、盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型,這會降低查詢和連接的性能,并會增加存儲開銷。

    14、索引并不是越多越好,索引固然可以提高相應的?select?的效率,但同時也降低了?insert?及?update?的效率

    15、并不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引

    總結

    以上是生活随笔為你收集整理的教你如何定位及优化SQL语句的性能问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。