MySQL邏輯架構:mysql
第一層:客戶端層,鏈接處理,受權認證,安全等功能。sql
第二層:核心層,查詢解析,分析,優化,緩存,內置函數(時間,數學,加密),存儲過程,觸發器,視圖數據庫
第三層:存儲引擎。負責MySQL中數據的存儲和提取。緩存
MySQL查詢過程安全
緩存對系統的額外消耗也不只僅在寫操做,讀操做也不例外:性能優化
任何的查詢語句在開始以前都必須通過檢查,即便這條 SQL 語句永遠不會命中緩存。服務器
若是查詢結果能夠被緩存,那麼執行完成後,會將結果存入緩存,也會帶來額外的系統消耗。架構
基於此,咱們要知道並非什麼狀況下查詢緩存都會提升系統性能,緩存和失效都會帶來額外消耗,只有當緩存帶來的資源節約大於其本 身消耗的資源時,纔會給系統帶來性能提高。函數
最後的忠告是不要輕易打開查詢緩存,特別是寫密集型應用。若是你實在是忍不住,能夠將 query_cache_type 設置爲 DEMAND。工具
這時只有加入 SQL_CACHE 的查詢纔會走緩存,其餘查詢則不會,這樣能夠很是自由地控制哪些查詢須要被緩存。
解析語法,生成解析樹。進行合法校驗。
(不要聽信你看到的關於優化的「絕對真理」,包括本文所討論的內容,而應該是在實際的業務場景下經過測試來驗證你關於執行計劃以及響應時間的假設。)
1 學習使用EXPLAIN
2 建立正確的索引
數據庫的索引像書的索引同樣,他們的位置信息被保存,而且包含數據庫的主要信息。可使用EXPLAIN來查找
缺失的索引。
3 拒絕默認的設置:有三個關於MySQL性能優化的設置:
innodb_buffer_pool_size:數據和索引被用做緩存的緩衝池。當數據庫服務器有大量的系統內存時,能夠用。
這個設置不要過大,也不要頻繁的引發交換。
innodb_log_file_size:單個InnoDB日誌文件大小。
max_connections:最大鏈接數
4 將數據庫載入內存
將頻繁訪問的數據放入內存(好比30%的數據放入內存)
5 SSD存儲
6 橫向擴展??
縱向擴展
橫向擴展
7 追求可視化
數據庫受到流量負荷的影響,應用程序等致使的錯誤,爲了快速、有效的解決問題,須要有監控機制。
經常使用的監測工具: MySQL企業監控器 / Monyog / Percona
8 Scheme設計與數據類型優化
選擇數據類型只要遵循小而簡單的原則就好,越小的數據類型一般會更快,佔用更少的磁盤、內存,處理時須要的 CPU 週期也更少。好比,整型就比字符操做代價低,於是會使用整型來存儲 ip 地址,使用 DATETIME 來存儲時間,而不是使用字符串。
9 建立高性能索引
索引:一般說的索引時B-Tree索引。InnoDB用的是B+Tree.
平衡二叉樹: 若是想二叉樹的查詢性能高,須要二叉樹是平衡二叉樹。
爲何MYSQL不用平衡二叉樹,而是用B+Tree樹?隨着數據庫中數據的增長,索引自己大小隨之增長,不可能所有存儲在內存中,所以索引每每以索引文件的形式存儲在磁盤上。這樣的話,索引查找過程當中就要產生磁盤 I/O 消耗,相對於內存存取,I/O 存取的消耗要高几個數量級。能夠想象一下一棵幾百萬節點的二叉樹的深度是多少?若是將這麼大深度的一顆二叉樹放磁盤上,每讀取一個節點,須要一次磁盤的 I/O 讀取,整個查找的耗時顯然是不可以接受的。那麼如何減小查找過程當中的 I/O 存取次數?一種行之有效的解決方法是減小樹的深度,將二叉樹變爲 m 叉樹(多路搜索樹),而 B+Tree 就是一種多路搜索樹。
B+Tree樹特徵:
10 MySQL不使用索引的狀況:非獨立的列
「獨立的列」 :索引列不能是表達式的一部分,也不能是函數的參數。
11 前綴索引
列很長的狀況下,索引開始的部分字符,有效節約索引空間(須要前面的部分有必定的區分度)
12 多列索引和索引順序:
在多數狀況下,在多個列上創建獨立的索引並不能提升查詢性能,理由很是簡單,MySQL 不知道選擇哪一個索引的查詢效率更好(由於數據庫中有多個索引的B+Tree, MySQL只能選擇一個樹作索引)。
多個列之間用AND時:聯合索引優於獨立索引。
多個列之間用OR、uniton時:每每會不走索引。
這種狀況下,創建包含多個列的聯合索引更加高效。
建立聯合索引時, 把選擇性更高的放在前面(由於這樣,經過第一個過濾條件就能過濾掉大讀書數據)。
13 避免多個範圍條件
只能用其中一個索引。
14 覆蓋索引
若是一個索引包含或者說覆蓋全部須要查詢的字段的值(就是select 後面的列),那麼就沒有必要再回表查詢,這就稱爲覆蓋索引。
15 使用索引掃描來排序:
掃描索引自己很快,由於只須要從一條索引記錄移動到相鄰的下一條記錄。但若是索引自己不能覆蓋全部須要查詢的列,那麼就不得不每掃描一條索引記錄就回表查詢一次對應的行。
在設計索引時,若是一個索引既可以知足排序,又知足查詢,是最好的!!。只有當索引的列順序和 ORDER BY 子句的順序徹底一致,而且全部列的排序方向也同樣時,纔可以使用索引來對結果作排序。
若是查詢須要關聯多張表,則只有 ORDER BY 子句引用的字段所有爲第一張表時,才能使用索引作排序。
ORDER BY 子句和查詢的限制是同樣的,都要知足最左前綴的要求。
16 避免冗餘和重複索引
17 刪除長期未使用的索引
18 查詢優化
在關聯查詢的狀況下:Group By中的表達式只涉及到一個表中的列。這樣纔有可能使用索引優化。
A和B表用c類關聯時,不須要在A上創建索引,在B上建索引就OK(由於,A表不管是否有索引,都要遍歷,B表和C表則須要走索引去尋找匹配的記錄)。
19 優化LIMIT分頁
LIMIT 10000 20 這樣的查詢,MySQL 須要查詢 10020 條記錄而後只返回 20 條記錄,前面的 10000 條都將被拋棄,這樣的代價很是高。
優化這種查詢一個最簡單的辦法就是儘量的使用覆蓋索引掃描,而不是查詢全部的列。
20 優化UNION
除非確實須要服務器去重,不然就必定要使用 UNION ALL,若是沒有 ALL 關鍵字,MySQL 會給臨時表加上 DISTINCT 選項,這會致使整個臨時表的數據作惟一性檢查,這樣作的代價很是高。
21 假設有聯合索引 (user_name, sex, age), 如下三個查詢,其實謂詞的順序不重要,都會用到聯合索引的,這是由於MySQL作了優化。
可是聯合索引的順序卻很重要,看下面22和23
select * from test where user_name=’test1’ and sex>0 and age =10
select * from test where sex>0 and user_name=’test1’ and age =10
select * from test where age =10 and user_name='test1' and sex>0
22 最左原則
mysql創建多列索引(聯合索引)有最左前綴的原則,即最左優先,如:
若是有一個2列的索引(col1,col2),則已經對(col1)、(col1,col2)上創建了索引;
若是有一個3列索引(col1,col2,col3),則已經對(col1)、(col1,col2)、(col1,col2,col3)上創建了索引;
23 聯合索引總結
(一直在思考,對於select 後面的字段是否須要創建索引, 對於上面的a,b,c索引,不須要回表;對於a,b索引,還須要回表。)
24 like
%xx -- 不走索引; XX% -- 走索引;
25 OR
OR操做致使,不容易優化。
26 避免 select *
27 知道什麼時候使用臨時表
防止對大表查詢兩次。還可使用臨時表,大幅減小鏈接大表所需的處理能力。
若是你必須將一個錶鏈接到大表,該大表上又有條件,只需將大表中所需的那部分數據提取到臨時表中,而後再與該臨時錶鏈接,就能夠提高查詢性能(這個在實際項目中用到過,在表join以前,先把大表過濾掉儘量多的行)。
28 預暫存數據
若是你有一個報表或存儲過程(或一組)要對大表執行相似的鏈接操做,經過提早鏈接表,並將它們持久化存儲到一個表中來預暫存數據,就能夠對你大有幫助。
29 批量刪除和更新
30 避免嵌套視圖
31 不要使用逆向搜索
SELECT * FROMCustomers WHERE RegionID <> 3
索引與該查詢結合使用,由於它是逆向搜索,須要藉助表掃描來逐行比較。
優化方法:SELECT * FROM Customers WHERE RegionID<3 UNION ALL SELECT * FROM Customers WHERE RegionID >3
32 索引的使用原則
33 使用UNION all, 儘可能避免UNION(Union須要排序,而後去重)
34 避免對索引列加函數修飾
where trunc(create_date)=trunc(:date1)
原本create_date建索引了,可是加上trunc後,索引失效,改爲以下:
where create_date>=trunc(:date1) and create_date<trunc(:date1)+1< pre="">
where create_date between trunc(:date1) and trunc(:date1)+1-1/(24*60*60)
35 where子句中使用in, not in, or having.
使用exist , not exist代替in, not in
這個須要實踐的檢驗,待續
36 排序
帶有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL語句會啓動SQL引擎 執行,
耗費資源的排序(SORT)功能。 DISTINCT須要一次排序,其餘的至少兩次排序。
這個深有感觸,MySQL的order by效率及其低下。
37 應儘可能避開where子句中進行null值判斷:
select id from t where num is null 能夠在num上設置默認值0,確保表中num列沒有null值,而後這樣查詢: select id from t where num=0
38 並非全部索引對查詢都有效:
SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重複時,查詢可能不會去利用索引,如一表中有字段sex,male、female幾乎各一半,那麼即便在sex上建了索引也對查詢效率起不了做用。
39 索引並非越多越好,索引當然能夠提升相應的 select 的效率,但同時也下降了 insert 及 update 的效率
40 應儘量的避免更新索引數據列,由於索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將致使整個表記錄的順序的調整,會耗費至關大的資源。若應用系統須要頻繁更新索引數據列,那麼須要考慮是否應將該索引建爲索引。
41 儘可能使用數字型字段,若只含數值信息的字段儘可能不要設計爲字符型,這會下降查詢和鏈接的性能,並會增長存儲開銷。這是由於引擎在處理查詢和鏈接時會逐個比較字符串中每個字符,而對於數字型而言只須要比較一次就夠了。
42 儘量的使用 varchar/nvarchar 代替 char/nchar ,由於首先變長字段存儲空間小,能夠節省存儲空間,其次對於查詢來講,在一個相對較小的字段內搜索效率顯然要高些。
43 應儘可能避免在 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
44 應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。如: select id from t where num/2=100 應改成: select id from t where num=100*2
45 不少時候用 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)
46 儘可能使用 TINYINT
、 SMALLINT
、 MEDIUM_INT
做爲整數類型而非 INT
,若是非負則加上 UNSIGNED
47 VARCHAR
的長度只分配真正須要的空間
48 使用枚舉或整數代替字符串類型
49OR
改寫成 IN
: OR
的效率是n級別, IN
的效率是log(n)級別,in的個數建議控制在200之內