當前位置:首頁 » 編程語言 » mysql性能調優之sql查詢優化
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

mysql性能調優之sql查詢優化

發布時間: 2023-05-14 13:57:09

1. mysql調優的幾種方式

一、硬體調優,比如更新硬體,比如更新伺服器內存,更換硬碟來達到調整mysql性能的目的。
二、操作系統調優,比如修改操作系統參數,比如修改Linux的內核參數、關閉不必要的後台服務或者採用高性能的文件系統等。
三、MySQL服務調優,比如調整MySQL參察氏數,比如query_cache、innodb_buffer_pool_size,join_buffer_size或者sort_buffer_size等等,這些參數都是影響mysql性能的。
四、查詢優化,比如通過找出mysql中耗時查詢,對sql語句進行優化,來提升mysql的查詢性能,襪畢比如利用索引、改寫sql等等。
五、資料庫結構調整,比如調整資料庫的建表方敗好散式,比如分庫分表,比如拆分大表等等,來提高mysql的性能。
此外,還包括實施熱備份技術,即對資料庫的備份文件進行定期的備份,以防止出現意外數據損壞的情況,以及採用主從模式或者集群模式,來實現mysql的高可用,確保mysql資料庫在發生突發故障時不會受到嚴重影響。

2. MySQL——SQL優化

優化的目的就是讓sql語句使用索引,避免進行全文檢索,以此加速檢索的速度。在使用mysql的過程中,我們接觸最多的就是sql語句了。這是最容易優化也是最常優化的地方。

SQL優化有以下幾點:

explain模擬優化器執行SQL語句,在5.6以及以後的版本中,除過select,其他比如insert,update和delete均可以使用explain查看執行計劃,從而知道mysql是如何處理sql語句,分析查詢語句或者表結構的性能瓶頸。

explain的作用

3. Mysql怎麼樣避免全表掃描,sql查詢優化

1.應盡量避免在where子句中對欄位進行null值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:

selectidfromtwherenumisnull

NULL對於大多數資料庫都需要特殊處理,mysql也不例外,它需要更多的代碼,更多的檢查和特殊的索引邏輯,有些開發人員完全沒有意識到,創建表時NULL是默認值,但大多數時候應該使用NOTNULL,或者使用一個特殊的值,如0,-1作為默認值。


不能用null作索引,任何包含null值的列都將不會被包含在索引中。即使索引有多列這樣的情況下,只要這些列中有一列含有null,該列就會從索引中排除。也就是說如果某列存在空值,即使對該列建索引也不會提高性能。任何在where子句中使用isnull或isnotnull的語句優化器是不允許使用索引的。


此例可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢:

selectidfromtwherenum=0


2.應盡量避免在where子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。

MySQL只有對以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE。可以在LIKE操作中使用索引的情形是指另一個操作數不是以通配符(%或者_)開頭的情形。例如,「SELECTidFROMtWHEREcolLIKE'Mich%';」這個查詢將使用索引,但「SELECT
idFROMtWHEREcolLIKE'%ike';」這個查詢不會使用索引。

3.應盡量避免在where子句中使用or來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:

selectidfromtwherenum=10ornum=20

可以這樣查詢:selectidfromtwherenum==20

4.in和notin也要慎用,否則會導致全表掃描,如:

selectidfromtwherenumin(1,2,3)

對於連續的數值,能用between就不要用in了:5.下面的查詢也將導致全表掃描:
selectidfromtwherenamelike'%abc%'或者

selectidfromtwherenamelike'%abc'或者

若要提高效率,可以考慮全文檢索。

而selectidfromtwherenamelike'abc%'才用到索引

7.如果在where子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變數,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:

selectidfromtwherenum=@num

可以改為強制查詢使用索引:selectidfromtwith(index(索引名))wherenum=@num

8.應盡量避免在where子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:

selectidfromtwherenum/2=100

應改為:

selectidfromtwherenum=100*2

9.應盡量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:

selectidfromtwheresubstring(name,1,3)='abc'--name

selectidfromtwheredatediff(day,createdate,'2005-11-30')=0--『2005-11-30』生成的id應改為:

selectidfromtwherenamelike'abc%'

selectidfromtwherecreatedate>='2005-11-30'andcreatedate<'2005-12-1'


10.不要在where子句中的「=」左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。

11.在使用索引欄位作為條件時,如果該索引是復合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應盡可能的讓欄位順序與索引順序相一致。

12.不要寫一些沒有意義的查詢,如需要生成一個空表結構:

selectcol1,col2into#tfromtwhere1=0

這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:createtable#t(...)

13.很多時候用exists代替in是一個好的選擇:

selectnumfromawherenumin(selectnumfromb)

用下面的語句替換:
selectnumfromawhereexists(select1frombwherenum=a.num)

14.並不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。

15.索引並不是越多越好,索引固然可以提高相應的select的效率,但同時也降低了insert及update的效率,因為insert或update時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

16.應盡可能的避免更新clustered索引數據列,因為clustered索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新clustered索引數據列,那麼需要考慮是否應將該索引建為clustered索引。

17.盡量使用數字型欄位,若只含數值信息的欄位盡量不要設計為字元型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因為引擎在處理查詢和連接時會逐個比較字元串中每一個字元,而對於數字型而言只需要比較一次就夠了。

18.盡可能的使用varchar/nvarchar代替char/nchar,因為首先變長欄位存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的欄位內搜索效率顯然要高些。

19.任何地方都不要使用select*fromt,用具體的欄位列表代替「*」,不要返回用不到的任何欄位。

20.盡量使用表變數來代替臨時表。如果表變數包含大量數據,請注意索引非常有限(只有主鍵索引)。21.避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。

22.臨時表並不是不可使用,適當地使用它們可以使某些常式更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對於一次性事件,最好使用導出表。

23.在新建臨時表時,如果一次性插入數據量很大,那麼可以使用selectinto代替createtable,避免造成大量log,以提高速度;如果數據量不大,為了緩和系統表的資源,應先createtable,然後insert。

24.如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先truncatetable,然後droptable,這樣可以避免系統表的較長時間鎖定。

25.盡量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那麼就應該考慮改寫。26.使用基於游標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。

27.與臨時表一樣,游標並不是不可使用。對小型數據集使用FAST_FORWARD游標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括「合計」的常式通常要比使用游標執行的速度快。如果開發時間允許,基於游標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。

28.在所有的存儲過程和觸發器的開始處設置SETNOCOUNTON,在結束時設置SETNOCOUNTOFF。無需在執行存儲過程和觸發器的每個語句後向客戶端發送DONE_IN_PROC消息。

29.盡量避免大事務操作,提高系統並發能力。

30.盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。

4. mysql資料庫的優化方法

我們都知道,伺服器資料庫的開發一般都是通過java或者是PHP語言來編程實現的,而為了提高我們資料庫的運行速度和效率,資料庫優化也成為了我們每日的工作重點,今天,霍營IT培訓就一起來了解一下mysql伺服器資料庫的優化方法。



為什麼磨局要了解索引


真實案例


案例一:大學有段時間學習爬蟲,爬取了知乎300w用戶答題數據,存儲到mysql數據中。那時不了解索引,一條簡單的「根據用戶名搜索全部回答的sql「需要執行半分鍾左右,完全滿足不了正常的使用。


案例二:近線上應用的資料庫頻頻出現多條慢sql風險提示,而工作以來,對資料庫優化方面所知甚少。例如一個用戶數據頁面需要執行很多次資料庫查詢,性能很慢,通過增加超時時間勉強可以訪問,但是性能上需要優化。


索引的優點


合適的索引,可以大大減小mysql伺服器掃描的數據量,避免內存排序和臨時表,提高兄稿應用程序的查詢性能。


索引的類型


mysql數據中有多種索引類型,primarykey,unique,normal,但瞎塵讓底層存儲的數據結構都是BTREE;有些存儲引擎還提供hash索引,全文索引。


BTREE是常見的優化要面對的索引結構,都是基於BTREE的討論。


B-TREE


查詢數據簡單暴力的方式是遍歷所有記錄;如果數據不重復,就可以通過組織成一顆排序二叉樹,通過二分查找演算法來查詢,大大提高查詢性能。而BTREE是一種更強大的排序樹,支持多個分支,高度更低,數據的插入、刪除、更新更快。


現代資料庫的索引文件和文件系統的文件塊都被組織成BTREE。


btree的每個節點都包含有key,data和只想子節點指針。


btree有度的概念d>=1。假設btree的度為d,則每個內部節點可以有n=[d+1,2d+1)個key,n+1個子節點指針。樹的大高度為h=Logb[(N+1)/2]。


索引和文件系統中,B-TREE的節點常設計成接近一個內存頁大小(也是磁碟扇區大小),且樹的度非常大。這樣磁碟I/O的次數,就等於樹的高度h。假設b=100,一百萬個節點的樹,h將只有3層。即,只有3次磁碟I/O就可以查找完畢,性能非常高。


索引查詢


建立索引後,合適的查詢語句才能大發揮索引的優勢。


另外,由於查詢優化器可以解析客戶端的sql語句,會調整sql的查詢語句的條件順序去匹配合適的索引。


5. 如何進行SQL性能優化

這里分享下mysql優化的幾種方法。

1、首先在打開的軟體中,需要分別為每一個表創建 InnoDB FILE的文件。

6. 如何進行SQL性能優化

這里分享下mysql優化的幾種方法。

1、首先在打開的軟體中,需要分別為每一個表創建 InnoDB FILE的文件。

7. mysql 優化sql方法有哪些

1.對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。

2.應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。

3.應盡量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0

4.應盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20

5.下面的查詢也將導致全表掃描:
select id from t where name like '%abc%'
若要提高效率,可以考慮全文檢索。

6.in 和 not in 也要慎用,否則會導致全表掃描,如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3

7.如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變數,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
select id from t where num=@num
可以改為強制查詢使用索引:
select id from t with(index(索引名)) where num=@num

8.應盡量避免在 where 子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改為:
select id from t where num=100*2

9.應盡量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)='abc'--name以abc開頭的id
select id from t where datediff(day,createdate,'2005-11-30')=0--'2005-11-30'生成的id
應改為:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'

10.不要在 where 子句中的「=」左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。

11.在使用索引欄位作為條件時,如果該索引是復合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使用,並且應盡可能的讓欄位順序與索引順序相一致。

12.不要寫一些沒有意義的查詢,如需要生成一個空表結構:
select col1,col2 into #t from t where 1=0
這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(...)

13.很多時候用 exists 代替 in 是一個好的選擇:
select num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select 1 from b where num=a.num)

14.並不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有欄位sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。

15.索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。

8. mysql sql優化之 優化GROUP BY 和 DISTINCT

創建表tb_point 表

准備空的tb_box表

函數

編寫存儲過程,給tb_box表添加100萬條數據

修改關聯數據

好於

優於

在執行以下語句時會報錯:

前面在 https://www.jianshu.com/p/95e50fd017ea 文章中有提到這個問題,是直接修改sql_mode將 ONLY_FULL_GROUP_BY直接幹掉。但是在《高性能mysql》中有一段話是這樣的:

那麼既然指出不要直接修改 sql_mode,那麼我們應該如何讓沖突的GRUOPBY語句正確執行呢?

文中有提到,可以使用max()和min()函數來實現;但是這種方式使用max和min函數較真的人可能會說這樣寫的分組查詢有問題,確實如此。但是如果更加在乎查詢效率,這樣做也無可厚非。

如果,實在無法接受使用上面那種方式的話,可以這樣使用子查詢的方式來進行查詢:

書上對於這種方式有描述如下:
這樣寫更滿足關系理論,但是成本有點高,因為子查詢需要填充臨時表,而子查詢中創建的臨時表是沒有任何索引的。
作者認為這樣寫對性能有影響。

但是從我測得結果來看,子查詢的耗時反而更少。性能反而更佳。這個子查詢耗時0.4秒。而使用max方式耗時0.8秒。幾乎一倍。我的mysql版本是 5.7.22-log

為了解其中的原因,我們查看它的執行計劃:
可見,因為子查詢而產生了一層 DERIVED 臨時表,但是這個臨時表的Extra欄位有顯示 Using index、key裡面顯示自建索引。說明用到了索引。這是查詢性能可觀的一個重要原因吧;

另外我分別使用 SHOW PROFILE命令查看各部分耗時,對比之下。沒看到有哪部分耗時差別特別大,使用JOIN、MAX 耗時比上子查詢耗時都差不多是1倍

有些時候對一沒有建立索引的欄位,進行GRUOP BY時。會產生Using filesort 文件內排序。因為GRUOP BY是在排序的基礎上進行分組的。

如下面sql:

如果業務上不對排序有要求。那麼就可以禁止GRUOP BY的排序:

這樣就把Using filesort給幹掉了! 執行時間 1.237

當然,多數情況是多排序有要求的。此時也可以在GRUOP BY後面使用DESC和ASC關鍵字,使分組的結果集按需要的方向排序。如下:

分組查詢的一個變種就是要求mysql對分組結果再進行一次超級聚合。可以使用GROUP BY WITH ROLLUP 來實現這種邏輯,但可能性能不佳。因為通過查詢計劃分析出它是使用 Using temporary; Using filesort 來實現的。

使用WITH ROLLUP,查詢時間2.531秒。不使用0.774 秒。

1、所以,很多時候。我們在應用程序中做超級聚合是最好的!

2、當然也可使用UNION ALL 來實現:

3、還可以通過FROM子句嵌套使用子查詢:

9. 如何優化MySQL中查詢慢的SQL語句啊

MySQL查詢優化的5個好用方法
http://soft.chinabyte.com/database/254/11335754.shtml

原則上來說

FIND_IN_SET
typeid IN (35)
arcrank
加復合索引
在sortrank加索引