1. 程式人生 > >mysql資料庫查詢優化

mysql資料庫查詢優化

總結:
儘可能減少掃表的行數,達到目的
查詢執行的基礎
一.基礎
當希望mysql能夠以更高的效能執行查詢時,最好的辦法就是弄清楚mysql是如何優化和執行查詢的,基本可以從以下3點開始瞭解:
1.客戶端和mysql伺服器的互動過程
在這裡插入圖片描述
(1)客戶端傳送一條查詢給伺服器
(2)伺服器先檢查查詢快取(第二次查詢的SQL和第一次查詢的SQL完全相同),如果命中快取,則立即返回儲存在快取中結果,否則進入下一階段
(3)伺服器進行SQL解析,預處理,再由優化器生成對應的執行計劃
(4)Mysql根據優化器生成執行計劃,呼叫儲存引擎的API來執行查詢
(5)將結果返回客戶端
2.SQL語句關鍵字的執行順序
從一條複雜語句看

執行順序		SQL語句
(7)     	SELECT
(8)     	DISTINCT <select_list>
(1)     	FROM <left_table>
(3)     	<join_type> JOIN <right_table>
(2)     	ON <join_condition>
(4)     	WHERE <where_condition>
(5)     	GROUP BY <group_by_list>
(6)     	HAVING <having_condition
>
(9) ORDER BY <order_by_condition> (10) LIMIT <limit_number>

3.where條件執行順序
例如: film 表中有50000條資訊
優化前:
select * from film where film_name regexp ‘J’ and date<=2018-12-20 and date>=2018-01-01 //正則regexp 'J’作用於50000行資料
優化後:
select * from film date<=2018-12-20 and date>=2018-01-01 and film_name regexp ‘J’ //只有匹配上了時間才會進行正則校驗

索引
是資料庫儲存引擎用於快速找到記錄的一種資料結構,良好的索引可以很好的提升查詢速率,不恰當的索引會導致效能急劇下降,不同儲存引擎的索引工作方式不一樣,也不是所有的儲存引擎都支援所有型別的索引,即使多個儲存引擎支援同一種類型的索引,其底層的實現也可能不同。

一.B-Tree索引
一般說的索引,基本說的就是B-Tree索引,以下是B-Tree索引結構:
在這裡插入圖片描述
該索引對如下型別查詢有效:
1.全值匹配
指和索引中的所有列進行匹配,例如查詢姓名Cuba Allen,出生於1960-01-01的人
2.匹配最左字首
例如可以用於查詢姓為Allen的人,只使用索引的第一列
3.匹配列字首
也可以值匹配索引某一列的值的開頭部分,例如查詢所有以J開頭為姓的人。
4.匹配範圍值
例如查詢姓在Allen和Barrymore之間的人.
5.精確匹配某一列並範圍匹配另外一列
例如可以查詢姓為Allen,並且名字為字母K開頭的人
6.只訪問索引查詢

B-Tree索引的限制:
1.如果不是按照索引最左開始匹配,則無法使用索引,也就是無法跳過索引中列
比如查詢名為Bill的人(這裡沒有使用姓,所以無法使用索引)
2.如果索引查詢中有某個列的範圍查詢,則其右邊所有列都無法使用索引優化查詢
比如查詢 where last_name=‘Smith’ AND first Like ‘J%’ AND dob=‘1976-12-23’,那麼索引只作用於前2個。
所以有時候可以使用相同的列但順序不同的索引來滿足不同型別的查詢要求。

二.雜湊索引
基於雜湊表實現,只有精確匹配索引(=,In(),<=>符號)所有列才有效
雜湊表的資料結構:
在這裡插入圖片描述
例如 select * from testhash where fname=‘Peter’
因為雜湊f(‘Peter’)=8784,則直接找到第三行

因為hash可能會產生撞詞,所以為了提升查詢效率和精確,可以使用以下語句
比如資料庫存有URL,和URL的CRC32的hashcode as url_crc。則有如下:
select * from url where url_crc=CRC32(‘http://www.mysql.com’) and url=“http://www.mysql.com
這樣就會先匹配hashcode,然後相同的再字元逐一比較
CRC32為32位,也可以擴充套件使用64位FNV64()

三.空間資料索引(R-Tree)
可以用做地理資料儲存

四.全文索引
全文索引是一種特殊型別的索引,它查詢的是文字中的關鍵字,而不是直接比較索引中的值,全文索引更類似
於搜尋引擎做的事,適用於Match Against,而不是簡單的where條件語句.

五.高效能索引策略
1.索引列不能是表示式的一部分,始終將索引列單獨放在比較符的一邊。
比如select * from actor where actorid+1 = 5,//導致mysql不會使用索引
應為:select * from actor where actorid = 5-1
2.使用字首索引
有時候索引的列是很長的字串,這會讓索引變得大且慢,一個解決辦法是使用雜湊索引,但有時還不夠,
這樣通常可以使用字首幾個字元作為索引。那如何選擇字首幾個字元作為索引呢?
可以通過計算索引選擇性值,索引選擇性值越高,表明查詢效率就越高。
索引選擇性值 = 不重複的索引值個數/資料表的記錄總數,0-1之間,1表示查詢效率最好
比如:使用城市名列作為索引,可以使用城市名的前3個字元作為索引。
3.多列索引
很多人對多列索引的理解不夠,一個常見的錯誤就是為每個列建立索引,或者按照錯誤的順序建立多列索引。
在建立索引時,儘量遵循“3星系統”或者建立一個全覆蓋索引。
“3星系統”,評價一個索引是否合適某個查詢:
1.索引將相關記錄放在一起則獲得一星
2.索引中的資料順序和查詢中的排列順序一致獲得二星
3.索引中的列包含了查詢中需要的全部列則獲得三星
全覆蓋索引:
一個索引包含所有需要查詢欄位的值
比如:有一個多列索引(store_id,film_id),執行語句select store_id,film_id from film,這樣就可以使用
索引獲取資料,不需要讀取表中的資料行。

其它查詢效能優化
1.不要使用select *語句,因為會讓優化器無法完成索引覆蓋掃描這類優化,還會為伺服器帶來額外的IO,記憶體,CPU消耗。
2.使用索引可以減少資料庫掃描資料的行數
比如:select film_name from film where film_id=1,film_id為索引,則使用EXPLAIN檢視,發現掃描的行數為10行,刪掉索引,發現掃描的行數為5073行
3.如果在sql中用到where條件,則好壞依次為:
(1)在索引中使用where條件來過濾不匹配的記錄,這是在儲存引擎層完成
(2)使用索引覆蓋掃描來返回記錄,直接從索引中過濾不需要的記錄並返回命中結果,這是在MySql伺服器層來完成。
(3)從資料表返回資料,然後過濾不滿足條件的記錄,在mysql伺服器層完成,mysql需要先從資料庫表讀出記錄然後過濾。
4.切分查詢
比如:將一次性刪除一張10W資料量的表,可以分為10次每次刪除1W資料量的表,可以降低對伺服器的影響,還可以減少刪除時鎖的持有時間
5.分解關聯查詢
優點:可以讓快取的效率的更高,有時也可以適當減少掃描的資料量。
6.排序優化
如果不能通過索引生成排序結果,那麼如果排序的資料量小於“排序緩衝區”,那麼mysql使用記憶體進行排序,如果記憶體不夠
排序,那麼會進行檔案排序,那麼mysql會先將資料分塊,對每個獨立的塊使用“快速排序”進行排序。然後將各塊排序結果存放磁碟上,然後將各個排好序的塊進行合併,最後返回結果。
7.在關聯查詢和關聯子查詢,關聯子查詢未必效能就差,可以先測試,再選擇使用哪個。
8.如果查詢資料時只想獲取前20項,那麼這個limit的位置可以先考量後再放在最佳位置,可以提升效率
9.可以使用雜湊關聯,MariaDB支援
10.查詢最大MAX()值和最小值MIN(),mysql會進行全表掃描,可以使用比如:select * from film use index(primary) where name=‘penelope’ limit 1
11.count()有兩種不同的作用
(1)它可以統計某個列值的數量,在統計時要求列值為非空(不統計NULL)
(2)count(),統計行數,萬用字元並不會像我們猜想的那樣擴充套件成所有列,而是會忽略所有列而直接統計所有行數。
12.使用近似值,有些時候某些值並不需要多麼的精確,比如線上人數,可以使用EXPLAIN來代替,它不會真正去執行SQL查詢,所以成本很低.
13.group by,order by,如果沒有通過order by顯示的指定排序列,當查詢使用使用Group by的時候,結果集會自動按照分組的欄位進行排序,如果不關心結果集的排序,而這種預設排序又導致了需要檔案排序。則可以使用Order by NULL。