優化數據訪問mysql
1.是否向數據庫請求了不須要的數據算法
解決方式:sql
A. 查詢後加limit數據庫
B. Select後寫須要的列而不是*緩存
2. 是否掃描了額外的數據服務器
數據庫的訪問方式速度由慢到快:全表掃描,索引掃描,範圍掃描,惟一索引查詢,常數引用ide
MYSQL Explain命令 的type(數據庫引擎訪問表的方式):Const > ref > range > index > all函數
1. const 常數引用oop
若是是根據主鍵查詢,將會將查詢轉化爲一個常數,只取出肯定的一行數據。是最快的一種。性能
2. Ref
查找條件列使用了索引並且不爲主鍵和unique(值容許重複),只取出肯定值的數據,可能多行。
3. ref_eq 惟一索引查詢
ref_eq 與 ref相比,這種類型的查找結果集只有一個
4. range 範圍掃描
索引或主鍵,在某個範圍內時
4. index 索引掃描
僅僅只有索引被掃描
5. all 全表掃描
通常mysql應用where條件的方式由好到壞:
1. 在索引中使用where條件過濾,這是在存儲引擎層完成;
2. 使用索引覆蓋掃描,直接從索引中過濾不須要的數據並返回結果,這是在mysql服務器層完成,無需再回表查詢(在extra中出現using index)
3. 從數據表中返回數據,而後過濾不知足條件的數據,在服務器層完成,mysql須要先從數據表讀出記錄而後過濾(在extra中出現using where)
好的索引可讓查詢使用合適的訪問類型,減小掃描的數據行數。
執行查詢的基礎:
1. 客戶端發送一條查詢給服務器
2. 服務器先檢查緩存,若是命中緩存,馬上返回結果
3. 服務器進行sql解析,預處理,再由優化器生成對應執行計劃
4. Mysql根據優化器生成的執行計劃,調用存儲引擎API執行查詢計劃
5. 將結果返回給客戶端
第一步(客戶端發送一條查詢給服務器):
Mysql客戶端與服務器之間的通訊是半雙工的,要麼由服務器向客戶端發送數據,要麼由客戶端向服務器發送數據,不能同時進行;
因此爲了進行流量控制,客戶端發送查詢語句過長時,超過max_allowed_packet參數,服務器會拋出相應錯誤。
客戶端從服務器獲取數據時,多數鏈接mysql的庫函數均可以得到所有結果集並緩存到內存裏,mysql須要等全部數據都發給客戶端才能釋放這條查詢所佔用的資源;
第三步(服務器進行sql解析、預處理、查詢優化):
首先,經過關鍵字將sql語句進行解析,生成一顆「解析樹」;
解析器驗證語法規則;
預處理器檢查解析樹是否合法,驗證權限;
查詢優化器使用優化策略生成一個最優的執行計劃:
1. 從新定義關聯表的順序
2. 將外鏈接轉化爲內鏈接
3. 優化count(),min(),max()(根據b-tree只讀取第一條或最後一條數據)
4. 預估並轉化爲常數表達式
5. 提早終止查詢
6. 列表in()的比較(將in列表的數據先排序,經過二分查找肯定值是否知足條件)
生成一個執行計劃——指令樹:由於mysql的關聯從一張表開始嵌套,因此執行計劃是一顆左側深度優先的樹。
第四步(調用存儲引擎API執行查詢計劃)
查詢優化器在服務器層,而統計信息(每一個表或索引有多少頁,每一個表的每一個索引的基數是多少,數據行和索引長度,索引的分佈信息等)在存儲引擎層;
MYSQL執行關聯查詢方式:
Mysql認爲任何一次查詢都是一次關聯,並不只僅一次查詢關係到兩張表時。
在MySQL 中,只有一種 Join 算法,就是 Nested Loop Join嵌套迭代。
Simple Nested-Loop Join簡單嵌套循環:從驅動表中取出R1匹配S表全部列,而後R2,R3,直到將R表中的全部數據匹配完,而後合併數據,能夠看到這種算法要對S表進行RN次訪問,雖然簡單,可是相對來講開銷仍是太大了。
Index Nested-Loop Join索引嵌套循環:因爲非驅動表上有索引,因此比較的時候再也不須要一條條記錄進行比較,而能夠經過索引來減小比較,從而加速查詢。
優化:
選擇記錄數少的做爲驅動表;
優先優化NestedLoop的內層循環;
保證被驅動表上Join條件字段已經被索引
Mysql查詢優化器的侷限性
1.關聯子查詢
使用in加子查詢,性能很是糟糕
//未完
2. 最大值和最小值
對於max()和min()查詢,mysql的優化並很差,如:
Select min(actor_id) from sakila.actor where first_name = 「pene」;
由於first_name字段上沒有索引,因此mysql會進行一次全表掃描;
一個優化辦法是:(使mysql進行主鍵掃描)
select actor_id from sakila.actor use index(primary) where first_name = 「pene」 limit 1;
用主建索引查詢,由於b-tree是按照主鍵順序排序,因此limit 1 = min(actor_id),查找索引直到複合where條件的第一條數據