一、SQL執行順序以及常見SQL的join查詢
sql執行順序:
手寫
SELECT DISTINCT
<select_list>
FROM
<left table> <join type>
JOIN <right_table> ON <join_codition>
WHERE
<where_condition>
HAVING
<having_condition>
ORDER BY
< order_by_condition>
LIMIT < limit number>
機讀順序
1 FROM <left_table>
2 ON <join_condition>
3 <join_type> JOIN <right_table>
4 WHERE <where_condition>
5 GROUP BY <group by_list>
6 HAVING <having_condition>
7 SELECT
8 DISTINCT <select_list>
9 ORDER BY <order_by_condition>
10 LIMIT <limit_number>
- sql機器執行順序
- 七種join關係
二、索引
1、什麼是索引
索引是幫助MYSQL高效獲取數據的數據結構–>排好序的快速查找數據結構
我們平時所說的索引,沒有特別指明,都是指B樹(多路搜索樹,不一定是二叉)
結構組織的索引。其中聚集索引,次要索引,覆蓋索引,複合索引,前綴索引,唯一索引默認都是使用B+樹索引,統稱索引,除了B+樹這種類型的索引外,還有哈希索引等。
2、優勢:
類似大學圖書館書目索引,提高數據檢索效率,降低數據庫的io成本
通過索引列對數據進行排序,降低數據排序的成本,降低了CPU的消耗
3、劣勢:
實際上索引也是一張表,該表保存了主鍵與索引字段,並指向實體表的記錄,所以索引列也是要佔用空間的
雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對錶進行INSERTE,UPDATE,和DELETE。因爲更新表時,MYSQL不僅要保存數據,還要保存一下索引文件每次更新添加了索引列的字段,都會調整因爲更新所帶來的鍵值變化後的索引信息。(維護B+樹索引結構)
索引只是提高效率的一個因素,如果你的MYSQL有大數據量的表,就需要花時間研究建立最優秀的索引,或優化查詢語句
4、索引分類:
單值索引:即一個索引只包含單個列,一個表可以有多個單列索引
唯一索引:索引列的值必須唯一,但允許有空值
複合索引:即一個索引包含多個列
5、基本語法:
創建:
CREATE [UNIQUE] INDEX indexName ON myTable(clumn name(length));
使用ALTER命令創建:
1、添加主鍵(意味着索引值必須唯一,且不能爲NULL)
ALTER TABLE mytable ADD PRIMARY KEY(column_list)
2、創建唯一索引(索引值唯一,可以爲NULL,爲NULL可重複出現)
ALTER TABLE mytable ADD UNIQUE index_name (column_list)
3、添加普通索引(索引值可以出現多次)
ALTER TABLE mytable ADD INDEX index_name(column_list)
4、指定索引爲FULLTEXT,用於全文索引
ALTER TABLE mytable ADD FULL TEXT index_name(column_list)
刪除:
DROP INDEX [indexName] ON mytable;
查看:
SHOW INDEX FROM table_name
6、索引結構原理:
BTREE索引:
淺藍色的塊—>磁盤塊
黃色的塊------>指針
深藍色的塊----->數據項
P1表示小於17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大於35的磁盤塊
真實的數據庫都存在與葉子節點,非葉子節點不存儲真實的數據,只存儲指引搜索方向的數據項
查找過程:
如果要查找數據項29,那麼首先會把磁盤塊1由磁盤加載到內存,此時發生一個IO,在內存中用二分繼續查找確定19在17和35之間,鎖定磁盤塊1的P2指針,內存實踐相比磁盤IO可忽略不計。通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次IO,二分確定29在26和30之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內存,發生第三次IO,同時在內存中二分查找到29,結束,總計三次io
2、HASH索引
3、full-text全文索引
4、R-TREE索引
哪些情況需要創建索引?
1、主鍵自動建立唯一索引
2、頻繁作爲查詢條件的字段應該創建索引
3、查詢中與其他表關聯的字段,外鍵關係建立索引
4、頻繁更新的字段不適合創建索引(因爲每次更新都要維護索引結構)
5、where條件裏用不到的字段不創建索引
6、在高併發下傾向創建組合索引
7、查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度
8、查詢中統計或者分組字段
哪些情況下不適合創建索引
1、表記錄太少
2、經常增刪改的表
3、數據重複且分佈平均的表字段,因此應該只爲最經常查詢和最經常排序的數據列建立索引。(如果某個數據列包含許多重複的內容,爲它建立索引就沒有太大的實際效果)
三、 sql性能分析:
1、Sql性能下降原因:
1、查詢語句寫的太爛
2、索引失效
3、關聯查詢包含太多的join
4、服務器調優及各個參數的設置(緩衝、線程數等)
2、explain關鍵字:
定義
使用EXPLAIN關鍵字可以模擬優化器執行SQL查詢語句,從而知道MYSQL是如何處理你的SQL語句的。分析你的查詢語句或是表結構的性能瓶頸
作用
1、能夠獲取表的讀取順序
2、能夠獲取數據讀取操作的操作類型
3、能夠獲取哪些索引可以使用
4、能夠獲取哪些索引被實際是使用
5、能夠獲取表之間的引用
6、能夠獲取每張表有多少行被優化器查詢
命令
explain sql語句;
使用explain所獲取到的執行計劃包含的信息:
執行計劃信息各字段解釋
id
含義:select查詢的序列號,包含一組數字,表示查詢中執行select子句或操作表的順序
作用:解釋表的讀取順序
三種情況:
1、id相同,執行順序由上至下
2、id不同,如果是子查詢,id序號會遞增,id值越大優先級越高,越先被執行
3、id有相同有不同,優先級越大的越先執行,相同的自上而下執行
select_type
含義:查詢的類型,主要用於區別普通查詢、聯合查詢、子查詢等複雜查詢
作用:解釋數據讀取操作的操作類型
類型:
- SIMPLE:簡單的select查詢,查詢中不包含子查詢或者UNION
- PRIMARY:查詢中包含任何複雜的子部分,最外層查詢被標記爲PEIMARY(即最後加載執行的表)
- SUBQUERY:在SELECT或WHERE列表中包含的子查詢
- DERIVED:在FROM列表中包含的子查詢被標記爲DERIVED(衍生) MYSQL會遞歸執行這些子查詢,把結果放在臨時表中
- UNION:若第二個SELECT出現在UNION之後,則被標記爲UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標記爲DERIVED
- UNION RESULT:從UNION表獲取結果的SELECT
table
作用:標註數據來源哪張表
type
作用:顯示查詢使用了何種類型
類型性能排序:system > const > eq_ref >ref >range >index > ALL
一般情況保證查詢至少達到range級別
類型解讀:
system:表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現,這個可以忽略不計
const
表示通過索引一次就找到了,const用於比較primary key或者unique索引。因爲只匹配一行數據,所以很快。如將主鍵置於where條件查詢中,MYSQL就能將該查詢轉換爲一個常量
eq_ref
唯一性索引掃描,對於每個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或唯一索引掃描
ref
非唯一性掃描,返回匹配某個獨有值得所有行。本質上也是一種索引訪問,它返回所有匹配某個單獨值得行。
range
只檢索給定範圍得行,使用一個索引來選擇行。key列顯示了使用了哪個索引。一般就是在你的where語句中出現了between ,<, >, in等得查詢
index
FULL INDEX SCAN ,index與ALL區別爲index類型只遍歷索引樹。這通常比ALL塊,因爲索引文件通常比數據文件小。
ALL
FULL TABLE SCAN 將遍歷全表找到匹配得行
possible_keys
作用:顯示可能應用在這張表中得索引,一個或多個。查詢涉及到得字段上若存在索引,則該索引將被列出。但不一定被實際查詢中用到
key
作用 :表明實際查詢中用到得索引
情況:
NULL:沒有使用索引(要麼沒建索引,要麼沒用索引,要麼用了索引失效)
注意:如果使用了覆蓋索引:則possible_keys爲null,而key有值
覆蓋索引:即查詢得字段得順序與個數與建立得複合索引一致
key_len
含義:表示索引中使用得字節數,可通過該列計算查詢中使用得索引得長度。在不損失精確性得情況下,長度越短越好。key_len顯示得值爲索引字段得最大可能長度,並非實際使用長度。即key_len是根據表定義計算而得,不是通過表內檢索出得
ref
含義:顯示索引得哪一列被使用了,如果可能得話,是一個常數。哪些列或常量被用於查找索引列上得值
rows
含義:根據表統計信息及索引選用大致估算找到所需記錄所需要讀取得行數
Extra
含義:包含不適合在其他列中顯示但是又十分重要得額外信息
取值
-
Using filesort:說明MySQL會對數據使用一個外部得索引排序,而不是按照表內得索引順序進行讀取。即MySQL中無法利用索引完成得排序操作稱爲”文件排序“ (絕對避免)
-
Using temporary: 使用了臨時表保存中間結果,Mysql在對查詢結果排序時使用臨時表。常見於排序order by 和分組查詢group by (不可以有)
-
USING index:表示相應得select操作中使用了覆蓋索引,避免訪問了表得數據行,效率不錯。如果同時出現using where表命索引被用來執行索引鍵值得查找;如果沒有出現using where 表命索引用來讀取數據而非執行查找動作。(好現象)
-
Using where:表明使用了where過濾
-
using join buffer:表明使用了連接緩存
-
impossible where : where子句得值總爲false,不能獲取到任何元組
-
select tables optimized away
-
distinct:優化distinct操作,在找到第一匹配得元組後即停止找同樣得動作
join語句優化總結:
-
儘可能減少join語句中得NestedLoop得循環總次數:“永遠用小結果驅動大的數據集”
優先優化NestedLoop得內層循環 -
保證join語句中被驅動表上join條件字段已經被索引
-
當無法保證被驅動表得join條件字段被索引且內存資源充足得前提下,不要吝嗇joinBuffer得設置
兩表關聯查詢:
左連接,索引建在右表;右連接,索引建在左表
三表關聯查詢:
左連接,索引建在右邊兩張表;右連接,索引建在左邊兩張表
四、 索引優化(解決or避免索引失效)
1.最佳左前綴法則:如果索引了多列(複合索引),要遵守最左前綴法則。指的是查詢從複合索引的最左列開始並且不跳過複合索引中得列(防止索引失效)
2.不要再索引列上做任何操作(計算、函數、(自動or手動)類型轉型),會導致索引失效而轉向全表掃描
3.存儲引擎不能使用索引中範圍條件右邊的列。即複合索引中若複合索引中某個列參與了範圍條件則該列後的所有列都會索引失效
例:複合索引—>(column1,column2,column3),若有條件查詢 where cloumn1 = value1 and cloumn2>1 and column3=values3 則column3將失效
4.儘量使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致)),避免select *
5…mysql在使用不等於(!= 或者<>)的時候會導致索引失效而全表掃描
6.is null 或者 is not null 都會導致索引失效
7.like以通配符開始(’%abc%’)MySQL索引會失效而導致全表掃描。但是通配符只在右邊出現不會導致索引失效(即通配符不可以出現在最左邊)
解決like '%字符串…'索引失效問題:使用覆蓋索引,或者查詢複合索引中部分列
8.字符串不加單引號會導致索引失效
9.少用or,用它連接時會導致索引失效
五、查詢截取分析
查詢優化
1.切記小表驅動大表
- in 和 exist用法場景區分:
select * from A where A.id in (select id from B)
當B表數據集小於A表數據集時,用in 優與exist
select * from A where exist (select 1 from B where B.id = A.id)
當A表數據集小於B表數據集時,用exist優與in
2.order by 關鍵字優化
mysql排序使用index和filesort兩種方式。儘量使用using Index,避免出現using filesort
order by在滿足下列條件會使用index方式排序:
- order by 語句使用索引最左前列
- 使用Where子句和order by子句條件列組合滿足索引最左前列
如果order by字段不在索引列上,filesort有兩種算法:
雙路排序:mysql4.1之前的算法
單路排序:mysql4.1之後出現。從磁盤讀取查詢需要的所有列,按照order by 列在buffer對它們進行排序,然後掃描排序後的列表進行輸出。
3.group by 關鍵字優化
group by 實質是先排序後進行分組,遵照索引鍵的最佳左前綴,where高於having能寫在where限定的條件就不要使用having了
六、 慢查詢日誌
含義:
MySQL的慢查詢日誌是MySQL提供的一種日誌記錄,它用來記錄在MySQL中相應實踐超過閾值的語句,具體指運行時間超過long_query_time值得SQL,則會被記錄到慢查詢日誌中
具體指運行時間超過long_query_time值的SQL,則會被記錄到慢查詢日誌中。long_query_time的默認值爲10s
通過自定義long_query_time收集追星shi的sql語句,結合explain進行分析調優
默認情況下,MySQL數據庫沒有開啓慢查詢日誌。如果不需要調優,不建議啓動慢查詢日誌。
使用
查看是否開啓以及日誌路勁:SHOW VARIABLES LIKE ‘%slow_query_log%’;
開啓:set global slow_query_log =1;
查看long_query_time:SHOW VARIABLES LIKE ‘long_query_time%’;
更改long_query_time: SET global long_query_time = 閾值 ;單位 秒
注意:這裏設置後不會立馬看出變化,重新連接就可以看到最新設置
查詢當前系統有多少條慢查詢記錄:SHOW global status like ‘%Slow_queries%’;
以上配置在數據庫重啓將會失效,若要永久有效則在[mysqlId]下配置
slow_query_log = 1;
slow_query_log_file = log file path
long_query_time=3;
log_output=FILE
日誌分析工具:mysqldumpslow
使用參數(可通過mysqldumpslow --help查看)
s:表示按照何種方式排序
c:訪問次數
l:鎖定時間
r:返回記錄
t:查詢時間
al:平均鎖定時間
ar:平均返回記錄數
at:平均查詢時間
t:返回前面多少條數據
g: 正則匹配
常用參考:
1.得到返回記錄集最多的10個sql
mysqldumpslow -s r -t 10 日誌文件路徑
2.得到訪問次數最多的10個sql
mysqldumpslow -s c -t 10 日誌文件路徑
3 得到按照時間排序的前10條含有左連接的查詢sql
mysqldumpslow -s t -t 10 -g “left join” 日誌文件路徑
由於可能數據過多,建議使用以上命令與more和管道|結合使用
七、 Show Profile
是什麼
是MySQL提供可以用來分析當前會話中語句執行的資源消耗情況,可用於SQL的調優的測量。
默認情況下,參數處於關閉狀態,並保存最近15次的運行結果。
分析步驟
1.查看當前MySQL版本是否支持:SHOW variables like ‘profiling’ 默認爲關閉
2.開啓功能:set profiling = on;
3.運行SQL
4.查看結果:show profiles
5.診斷SQL:show profile cpu,block io for query 語句query_ID
可選參數:
ALL 顯示所有開銷信息
BLOCK IO 顯示塊IO相關開銷
CONTEXT SWITHES 上下文切換相關開銷
CPU 顯示CPU相關開銷信息
IPU 顯示發送和接收相關開銷
MEMORY 顯示內存相關開銷信息
PAGE FAULTS 顯示頁面錯誤相關開銷信息
SOURCE 顯示和Source_function,Source_file ,Source_line相關開銷
SWAPS 顯示交換次數相關開銷信息
常出現的危險status:
converting HEAP to MyISAM ----- 查詢結果太大,內存不夠用了往磁盤上加
Creating tmp table ---- 創建臨時表
Coping to tmp table on disk ---- 把內存中臨時表複製到磁盤
locked
八、 Mysql鎖機制
定義
鎖是計算機協調多個進程或線程併發訪問某一資源的機制
在數據庫中,除傳統的計算資源(CPU,RAM,I/O等)的爭用以外,數據也是一種供許多用戶共享的資源。如何保證數據兵法訪問的一致性、有效性是所有數據庫必須解決的一個問題,鎖衝突也是影響數據庫兵法訪問性能的一個重要因素。從這個角度來說,鎖對數據庫而言顯得尤其重要也更加複雜。
鎖的分類
-
從對數據操作的類型上分爲讀鎖和寫鎖
讀鎖(共享鎖):針對同一份數據,多個讀操作可以同時進行而不會互相影響
寫鎖(排他鎖):當前寫操作沒有完成前,它會阻斷其他寫鎖和讀鎖。 -
從對數據操作的粒度分爲表鎖和行鎖
1、表鎖
**特點:**偏向MyISAM存儲引擎,開銷小,加速塊;無死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低。
命令:
加鎖: lock table 表名1 read/write,表名2 read/write…
查看錶加鎖情況:show open tables;有鎖時In_user = 1
釋放表鎖:unlock tables
**讀鎖:**表被某一會話加上讀鎖後,大家都可以讀數據,但是不可以寫(包括加鎖者,且加鎖者會話不可以再操作其他表),其他會話發起寫數據請求將被阻塞到表鎖被釋放。
**寫鎖:**表被某一會話加上寫鎖後,加鎖者會話可以對此表進行讀操作,但不可以再操作其他表。而其他會話 對此表進行寫操作,讀操作將被阻塞至寫鎖被釋放。
**總結:**讀鎖會阻塞寫,但是不會阻塞讀;而寫鎖 會阻塞讀和寫
2、行鎖
特點:偏向InnoDB存儲引擎,開銷大,加鎖慢;會出現思索;鎖定力度最小,發生鎖衝突的概率最低,併發度也最高
注意:當索引失效或者無索引時時會導致行鎖變爲表鎖
3、間隙鎖
定義
當我們用範圍條件而不是相等條件檢索數據,並請求共享或排他鎖時,InnoDB會給符合條件的已有數據記錄的索引項加鎖;對於鍵值在條件範圍內但不存在的記錄,叫做:“間隙(GAP)”
InnoDB也會對這個間隙鎖加鎖
危害:
因爲Query執行過程中通過範圍查找的話,他會鎖定整個範圍內所有的索引鍵值,即使這個鍵值不存在。
間隙鎖有一個比較致命的弱點,就是當鎖定一個範圍鍵值之後,及時某些不存在鍵也會被無辜鎖定,而造成在鎖定的時候無法插入鎖定鍵值範圍內的任何數據。在某些場景下這可能會對性能造成很大的危害
優化建議
1.儘可能讓所有數據檢索都通過索引來完成,避免無索引行鎖升級爲表鎖
2.合理設計索引,儘量縮小鎖的範圍
3.儘可能減少檢索條件,避免間隙鎖
4.儘量控制事物大小,減少鎖定資源量和時間長度
5.儘可能低級別事物隔離
寫在最後:
歡迎大家關注我新開通的公衆號【風平浪靜如碼】,海量Java相關文章,學習資料都會在裏面更新,整理的資料也會放在裏面。
覺得寫的還不錯的就點個贊,加個關注唄!點關注,不迷路,持續更新!!!