課程目的:寫出高質量SQL語句,數據庫參數調優,建立使用索引
1.MySQL架構介紹
高級內容包括:內核可以優化改寫,服務器配置文件可以優化改寫,參數常量優化,sql優化,主從復制,軟硬件升級,容災備份,sql編程
linux安裝mysql:儲存位置
Mysql配置文件
log-bin:二進制日志,用于主從復制
log-error:默認關閉,記錄嚴重的警告和錯誤信息
log:默認關閉,記錄查詢的sql語句,用于查詢分析
數據文件:
- /var/lib/mysql 或用語句查詢 ls -lF | grep ^d
- frm文件:存放一個數據庫的表結構
- myd文件:數據
- myi文件:數據索引
如何配置:win:my.ini linux:/etc/my.cnf
Mysql邏輯架構
- 連接層
- 服務層
- 引擎層
- 存儲層
Parser:將SQL語句重組過濾,從from開始解析( 轉化為關系代數表達式?)
optimizer:優化器。找到更好的等價的關系代數表達式。僅僅優化為mysql自己認為好的,可導致索引失效
cache & buffer:緩存緩沖。
存儲引擎:可插拔式的存儲引擎將查詢處理和其他的系統任務以及數據存儲提取相隔離。常用的是MyISAM和InnoDB。
存儲引擎介紹
InnoDB支持事務,行鎖,表鎖,外鍵
MyISAM關注讀
InnoDB關注寫
2.索引優化分析
性能下降
四個原因:
- 查詢語句寫的爛
- 索引失效
- 關聯查詢太多join(設計缺陷或不得已的需求)
- 服務器調優及各個參數的設置(緩沖、線程數等)
join相關
SQL執行順序
手寫順序:
機讀順序:
總結:
七種JOIN理論
注:Mysql不支持FULL OUTER全連接查詢。要得到這個結果需要使用UNION(能把兩個查詢結果并起來而且去重)
select 語句1 UNION select 語句2
索引
官方定義:幫助MySQL高效獲取數據的數據結構。
即:
排好序的快速查找數據結構(兩大功能:查的塊,排好序)
類比于字典 :如果要查找”mysql“這個單詞,先定位到m字母,再往下找到y,再找到剩下的sql。
索引會影響到:
- where后面的條件
- order by 后面的排序字段
數據庫系統維護著滿足特定查找算法的數據結構,這種數據結構以某種方式指向數據。
二叉查找樹的每一個節點包含 索引鍵值 和 一個指向對應數據記錄物理地址的指針。這就能快速地檢索符合要求的記錄。
我們平常說的索引,如果沒有特別指明,都是指B樹(多路搜索樹,不一定是二叉的)結構組織的索引。其中聚集索引、次要索引、覆蓋索引、復合索引、前綴索引、唯一索引默認都是用B+數。此外還有哈希索引。
索引優勢:
- 提高數據庫檢索效率,降低數據庫IO成本
- 通過索引列對數據進行排序,降低數據排序成本,降低了CPU消耗
索引劣勢:
- 實際上索引也是一張表,此表保存了主鍵和索引字段,并指向實體表的記錄,所以索引列也是要占空間的
- 降低了表的更新速度,如insert、updata、delete。因為不僅要保存數據,還要改動索引文件。
- 索引只是提高效率的一個因素,如果有大數據量的表,需要花時間研究建立最優秀的索引。
索引分類
單值索引:一個索引只包含單個列,一個表可以有多個單列索引(復合索引優于單值索引)(一張表索引不要超過5個)(一次查詢只能用一個索引)
唯一索引:索引列的值必須唯一,但允許有空值
復合索引:一個索引包含多個列
-
基本語法:
- 創建:create [unique] index indexName ON mytable(columnName(length)); alter mytable add [unique] index [indexName] ON (columnName(length));
- 刪除:drop index [indexName] on mytable;
- 查看:show index from table_name;
索引結構
四種索引結構:BTree索引、Hash索引、full-text全文索引、R-TREE索引
BTREE:
需要與不需要建立索引的情況
需要建立:
- 主鍵自動作為唯一索引
- 頻繁作為查找條件的字段
- 查詢中與其他表關聯的字段,外鍵關系建立索引。
- 頻繁更新的字段不應該建立索引
- where條件里用不到的字段不適合建立索引
- 高并發情況應該建立組合索引
- 查詢中排序的字段。(排序字段通過索引去訪問能大大提高排序速度)
- 查詢中統計和分組的字段(分組之前必須排序)
不需要建立:
- 表記錄太少(三百萬以上效率就開始下降)
- 經常增刪改的表。
- 數據重復且分布平均的字段。(如果某個數據列包含太多重復的內容,建立索引沒太大效果)
- 索引的選擇性:索引列中不同值的數目與表中記錄數的比。越接近1,索引效率就越高。
性能分析
優化器模塊的作用: 通過計算分析系統中收集到的統計信息,為客戶端請求的Query提供它認為最優的執行計劃
MySQL常見瓶頸:
- CPU:CPU飽和經常發生在數據裝入內存或從磁盤讀取數據的時候
- IO:IO瓶頸發生在裝入數據量遠大于內存的時候
- 服務器硬件性能瓶頸:用top、free、iostat和vmstat來查看系統的性能狀態
explain(查看執行計劃):模擬優化器執行sql查詢語句,從而知道mysql是如何處理sql語句的,分析性能瓶頸。
能查出:
- 表的讀取順序:id
- 數據讀取操作的操作類型:select_type
- 哪些索引可以使用:possible_keys
- 哪些索引被實際使用:key
- 表之間的引用:ref
- 每張表有多少行被優化器查詢:rows(越小越好)
- id:序列號,表示查詢中執行select子句或操作表的順序
- id相同,執行順序由上至下
- 如果是子查詢,id的序號會遞增,id越大優先級越高,越先被執行
- id如果相同,可以認為是一組,從上往下執行。所有組中,id越大,優先級越高。
- select_type:查詢類型
- SIMPLE:簡單的select查詢,不包含子查詢或者UNION
- PRIMARY:****最外層的查詢(包含復雜子查詢的情況)
- SUBQUERY:在Select或where列表中包含了子查詢
- DERIVED:在from中包含的子查詢被標記為“衍生”,mysql會遞歸地執行這些子查詢,把結果放在臨時表里。后面的數字,指的是前面的id序列號。
- UNION: 若第二個select出現在union后,則被標記為union。若union包含在from子句的子查詢中,外層的select將被標記為:DERIVED。
- UNION RESULT:從UNION獲取的result
- table : 顯示這一行數據是關于哪張表的。
- type:訪問類型,顯示查詢使用了何種類型。最好到最差依次是:system >const>eq_ref>range>index >ALL.
- 大查詢至少達到range級別,最好能達到ref
- system:表只有一行記錄,等于系統表,const類型的特例
- const:表示通過索引一次就找到了。用于比較primary key或者unique索引。因為只匹配一行數據,所以很快。如將主鍵置于where列表中,mysql就能將該查詢轉化為一個常量。
- eq_ref:唯一性索引掃描,對于每個索引鍵,表中只有一條記錄與之匹配。常見于 主鍵索引或唯一索引掃描。
- ref:非唯一性索引掃描。返回匹配某個單獨值的所有行。(希望達到的級別)
- range:檢索給定范圍的列,使用一個索引來選擇行。key顯示使用了哪個索引。一般就是在where語句里出現了 between、<>、in等的查詢。它開始于索引的某一點,結束語另一點,不用掃描全部索引。
- index:只遍歷索引樹,通常比all全表查快。
- all:遍歷全表。超過百萬就明顯慢了。
- possible_keys:顯示可能應用到這個表上的索引,可能有一個或多個。但該索引不一定被使用
- key:實際使用的索引。如果為null,則沒有使用索引。 查詢中若使用了覆蓋索引,則該索引僅出現在key列表中,possible_keys里沒有。( 覆蓋索引:所查的字段正好與索引字段個數、順序一致,或者where條件字段加上所查字段正好是復合索引字段,直接從索引里讀數據)
- key_len:表示索引中使用的字節數,可通過該列計算查詢中使用的索引長度。在不損失精確性的情況下,長度越短越好。為最大可能長度,并非實際使用長度。通過表定義計算得到,非通過表內檢索找到。
- ref:顯示索引的哪一列被使用了,如果可能的話,是一個常數。 哪些列或者常量被用于查找索引列上的值。
- rows:根據表的統計信息和索引選用情況,大致估計出找到所需記錄所需要讀取的行數。越小越好!!
- Extra:其他重要的信息。
- Using filesort:表示mysql會對數據使用一個外部的索引排序,而不是用表內的索引順序。表示排序時沒有用上索引!!! 常見于:建了組合索引,order by或group by 沒有全部用上索引的字段。
- Using temporary:使用臨時表保存了中間結果。常見于order by 和group by。絕對不好!!!
- Using index:表示相應的select操作使用了覆蓋索引,避免了訪問表的數據行, 效率不錯! 如果同時出現了using where 表示索引被用來執行索引鍵值的查找;如果沒有同時出現using where,表明索引用來讀取數據而非執行查找。
- Using where:使用了where
- Using join buffer:使用了連接緩存
- impossible where:where子句的值總是false 不能用于獲取值
索引優化
單表優化:
題目:查詢category_id為1且comments大于1的情況下,views最多的article_id
建立索引1:針對category_id、comments、views建立復合索引
結果1:type變為range,key字段顯示了索引,但Extra出現了Using filesort,說明針對views排序時,索引失效。
原理1:按照B樹工作原理,先排序category_id,遇到相同時再排序comments,相同時再排序views。當comments字段在聯合索引中處于中間位置時,因comments>1是一個范圍條件(range),Mysql無法里利用索引再對后面的views部分進行檢索,即range類型查詢字段后的索引失效。
建立索引2:只針對category_id、views建立索引
結果2:type變為ref,Extra中的using filesort也消失了,結果理想
兩表優化:
題目:左連接的時候,索引應該加在左表的id列還是右表的id列?
結果1:加在右表,右表的type變成ref,rows變成了1,結果理想
結果2:加在左表,左表的type變成index,row還是沒變,結果不理想
原理:這是由左連接的特性決定的,left join條件用來決定如何從右表搜索行,左邊一定都有,左表一定都是all。所以右表是關鍵點,一定要在右表建立索引。
同理,right join on 條件用于確定如何從左表搜索行,右邊一定都有。所以索引一定要建在左表上。
三表優化:
結論:**如多個left join 并列 ,則在兩個右表上建立索引。 ** 永遠用小表驅動大表,因為主表全掃描是不可避免的。
原則:
- 減少join嵌套的次數,用小表驅動大表
- 優化嵌套的內層循環
- 保證join語句中被驅動表上的條件字段已經被索引
- 當無法保證被驅動表上的條件字段被索引時,不要太吝惜于joinbuffer的設置
避免索引失效
1.確保搜索條件與索引全值匹配。杜絕“空中樓閣”
2.最佳左前綴法則:如果使用了復合索引,查詢從索引的最左前列開始并且不跳過索引中的列。
3.不要在索引列上做任何操作(計算,函數,類型轉換)
4.范圍條件后面(> \ < \ like)的索引字段會失效。(但是like 左邊沒有百分號的,后面的索引不會失效)
5.盡量使用覆蓋索引(索引列和查詢列一致)
6.使用不等于的時候無法使用索引
7.is null 或 is not null 無法使用索引
-
8.like 以 通配符開頭(“%..”)會導致索引失效(最好在右邊寫通配符)
如果一定要使用通配符開頭,用覆蓋索引來彌補。(建的索引和所查字段個數、順序上一致)
例子:在建立(name,age)復合索引的情況下,以下都用到了索引:
SELECT id FROM t WHRER name like "%aa%" (id 是自帶的主鍵索引)
SELECT name, age FROM t WHRER name like "%aa%"
SELECT name FROM t WHRER name like "%aa%"
SELECT age FROM t WHRER name like "%aa%"
SELECT id,name, age FROM t WHRER name like "%aa%"
(當查詢字段超過name和age,或者用* 的時候 索引失效)
9.字符串不加單引號會導致索引失效
10.少用or,用它連接時會導致索引失效
注意:
一般情況下 where和order by 的條件要遵循最佳左前綴法則,才能用的上索引。但有個特殊情況,當order by的條件字段有一個常量時,雖然順序不對,仍然能用索引排序,不會filesort。
例如:對c1,c2,c3建立索引,select * from table where c1="a1" and c2="a2" order by c3, c2。雖然order by的順序亂了,但是c2等于一個常量,order by c2 其實就對一個值排序,等于沒排序。所以order by c3仍然能用索引,沒有文件內排序。
group by 分組之前必排序,索引規則等同于order by。如果不用索引,會有臨時表的產生。
使用覆蓋索引能變快的原因:索引表中字段少了,儲存得更加緊密,雖然總得行數和全表一樣,但是儲存的塊少了,導致需要的IO變少,所以速度會快一點。
對于選擇率低的字段,比如性別,建立一個索引,統計一個性比的人數時會有一倍的提升。因為索引表中,男女分開,只用讀一半的數據就能統計出人數。但是一般只有提速10倍,才算不錯的索引。
針對一個字段是不是要建索引,要在實際業務中,看一天的修改該字段的事物占(修改事務+查詢事務)之比,大于20%就不要建索引。