- 一. SQL解析及優化
1 . SQL解析
SQL進入引擎的流程
Eg:select XXX from ….join …on …where ….group by …having …order by …limit
解析順序:from …on..join … where …group by …having …select …order by .limit
1.1 sql在MySQL服務上的執行流程
參考:www.cnblogs.com/annsshadow/p/5037667.html
dev.mysql.com/doc/refman/5.7/en/memory-use.html
2. 優化工具:
-
- Explain 執行計劃使用方法
2.1.1. explain 結果參數說明
Eg:優化前SQL:
explain select a.account_id ,a.user_id ,a.course_id
from study_right_logger_11 a join user b on a.user_id = b.user_id
where a.account_id = '60258144' or a.course_id= '124162' ;
備註:study_right_logger_11 建立符合索引順序:`account_id`, `course_id`, `user_id`
(1).
結果參數 |
參數類型 |
作用 |
含義 |
id |
Id值相同:從上往下順序執行,數據少的表優先查詢 |
Sql中table的執行順序 |
表的執行順序因表的行數的變化而改變:笛卡爾積 |
Id值不同越大越優先查詢(有子查詢時) |
|
|
|
Select_type |
Primary: |
包含子查詢SQL的主查詢,最外層 |
|
Subquery: |
包含子查詢SQL的子查詢,非最外層 |
|
|
Simple: |
不包含:子查詢和union |
|
|
Derived:衍生查詢 |
使用了臨時表
|
|
|
Union: |
衍生表,如下圖1 |
|
|
Table |
Derived + id(衍生表) |
|
|
|
|
|
|
|
|
|
|
Type |
system |
理想情況,實際達不到。只有一條數據的系統表或衍生表只有一條數據的主查詢.eg:select * from ( Select * from test1)t where tid =1; test1中只有一條數據 |
索引類型 |
const |
僅能查到一條數據是SQL 用於primary key 或unique索引 |
結果僅有一條數據 |
|
eq_ref |
唯一性索引,對於每個索引鍵的查詢,返回匹配唯一行數據,有且只有1個不能爲0( 如果表中的索引列有沒查詢出來的數據則認爲是0 ,即全部索引列必須全部查詢出來,基本很難滿足)。 即索引列的每個值都是唯一的,eg:name 全是唯一的,且是索引列 |
結果是多條數據,但每條數據唯一 |
|
ref |
非唯一性索引,對於每個索引鍵的查詢返回匹配的所有行。 |
結果是多條,(0 或者多條) |
|
range |
查詢指定範圍的行,where後面是一個範圍查詢(between,< ,> ,in 有時會失效,轉爲無索引) |
|
|
Index |
查詢全部索引數據
|
|
|
all |
查詢全部表中的數據,全表掃描 |
|
|
Index_merge |
MySQL5.0之前,一個表一次只能使用一個索引,無法同時使用多個索引分別進行條件掃描。但是從5.1開始,引入了 index merge 優化技術,對同一個表可以使用多個索引分別進行條件掃描
|
index merge 之intersect
|
|
Possible_keys |
具體索引列 |
|
表示可能用到的索引,是一種預測 |
|
Null |
沒有使用索引 |
|
key |
|
|
實際使用到的索引 |
|
|
|
|
Key_len |
索引的長度 |
如果長度是0 ,則該索引列未被使用,用於判斷符合索引是否完全被使用 ( a,b,c )三個列的符合索引 符合索引如果要使用後面的列的索引則必然前面是索引也要使用 |
Utf-8:1個字符佔用3個字節 A.如果列 是char(10 )則該列佔3 * 10 B.如果索引字段可以爲null,則會使用1個字節用於標識 C.如果類型是varchar 則除了有一位null的標識,還會用2個字節標識可變長度。即最後多出3位 C. int型佔用4個字節,索引中只包含了1列,所以,key_len是4
D . |
ref |
Const |
|
當前表所參照的字段 |
|
|
|
|
|
|
|
|
rows |
整數 |
|
通過索引查詢到的數據行數 |
|
|
|
|
extra |
(一) Using filesout |
性能消耗很大,SQL需要優化 |
|
Eg:select * from table1 where a1 = XX order by a2 ; 即:using filesout. |
|||
A.對於單索引,如果排序和查詢的列是同一個字段則不會出現using filesout ;如果排序和查詢不是同一個字段,則需要額外查詢,則是using filesout |
|
|
|
B.複合索引:不能跨列 |
|||
Eg:( a1,a2,a3)複合索引列 Select * from table where a1=XX order by a3; a1跟a3跨列了, Select * from table where a2=XX order by a3; a1被跨了,同樣是using filesout |
|||
|
Where 和orderby 按照複合索引的順序使用,不要跨列 |
||
|
(二) Using temporary:同樣性能損耗很大,用到了臨時表,常出現在group by Eg:select a1 from table where a1 in( 1,2,3 ) group by a2; 查詢的a1 但是根據a2分組,會導致MySQL再創建臨時表查詢結果 則extra 就是Using temporary,所以要查詢和排序列一致 注:解析過程 From..on..join..where..group by..having..select distinct ..orderby limit… Eg:select * from table where a2=2 and a4=4 group by a2,a4 ;--沒有using temporary
Select * from table where a2 =2 and a4=4 group by a3;using temporary
|
||
|
(三) Using index :性能提升的標識—索引覆蓋 說明當前的SQL不讀取原文件,只從索引文件獲取數據,不需要回表查詢 只要查詢的列全部都在索引中就會是using index Eg:複合索引( a1, a2,a3 ) Select a1,a2 from table where a1 =XX and a2=XXX 上面的SQL就會使用using index
|
||
|
(四) Using where :需要回表查詢 Eg:a1 是索引列 Select a1,a2 from table where a1=XX 上面是SQL必須回原表查詢a2
也有特殊情況,MySQL底層的優化器也會幫助優化SQL語句 Eg:複合索引:a1,a2,a3 Select a1,a2,a3 from table where a2=X and a1=x and a3=xx; 上面雖然跟複合索引順序不一致,但也是using index 是因爲SQL優化器的結果
Eg:複合索引:a1,a2,a3 Select a1,a2,a3 from table where a1=1 and a3=3 order by a2; 結果是:Using index + Using where A1在索引中可以直接查詢,但a3無效因爲跨列了,則需要回表查詢(using where )
|
||
|
五. using index condition:查找使用了索引,但是需要回表查詢數據
|
||
|
六. using intersect:表示使用and的各個索引的條件時,該信息表示是從處理結果獲取交集 using union:表示使用or連接各個使用索引的條件時,該信息表示從處理結果獲取並集 using sort_union和using sort_intersection:與前面兩個對應的類似,只是他們是出現在用and和or查詢信息量大時,先查詢主鍵,然後進行排序合併後,才能讀取記錄並返回。 |
||
|
七.using join buffer: mysql 引擎使用了連接緩存,說明SQL質量很差
|
||
|
|
2.2 profile
從 mysql5.0.3版本以後纔開放的。但是在mysql5.7之後,profile信息將逐漸被廢棄,mysql推薦使用performance schema
2.2.1. 開啓使用
可以定位SQL執行過程中對CPU和io的消耗
(1)方法一
A.查看是否啓用:SELECT @@profiling;
開啓profile :SET profiling = 1; //臨時打開,而不是全局打開
當打開後,所有的SQL語句全部記錄
B. 查看記錄 :query :show profile for query 1; // 數字表示查詢的ID
備註:在使用profile查看執行過程記錄之前要先把profile關閉掉,即:
SET profiling = 0;
C. show profile cpu,block io,memory,swaps for query 查詢ID;
D.用show profiles;可以查詢之前操作SQL對應的ID值
缺點:消耗性能,在生產環境是關閉的
(2)方法二:查詢全局日誌,記錄了開啓後的全部SQL日誌
查看命令:show variables like '%general_log%';
打開全局日誌命令:set global general_log=1; 或等2
文件會記錄:mysql.general_log ( mysql 庫的general_log 表 )
2.2.2 查詢參數
備註:使用select @@ mysql的配置參數名稱,就可以查詢出該參數對應的具體值
Eg:
如果IO的in和out 都是0 說明數據都已經被緩存在內存中了。
2.3.performance_schema 系統級存儲引擎
2.3.1. 介紹
A.MySQL的performance schema 用於監控MySQL運行過程中的資源消耗、資源等待等情況。主要關注數據庫運行過程中的性能相關的數據,與information_schema不同,information_schema主要關注server運行過程中的元數據信息
B.提供了一種在數據庫運行時實時檢查server的內部執行情況的方法。performance_schema 數據庫中的表使用performance_schema存儲引擎。該數據庫主要關注數據庫運行過程中的性能相關的數據
C.對server內部活動中所做的任何事情以及對應的時間消耗
D.performance_schema中的事件只記錄在本地server的performance_schema中,其下的 這些表中數據發生變化時不會被寫入binlog中,也不會通過複製機制被複制到其他server中
E.performance_schema的表中的數據不會持久化存儲在磁盤中,而是保存在內存中,一旦服務器重啓,這些數據會丟失
2.3.2. 使用介紹
2.3.2.1.查詢當前MySQL的實例是否支持,
命令:show engines;
2.3.2.2.performance_schema被視爲存儲引擎
查看是否支持命令:
SELECT * FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE ='PERFORMANCE_SCHEMA';
2.3.2.3.啓用方法
performance_schema在5.7.x及其以上版本中默認啓用(5.6.x及其以下版本默認關閉),如果要顯式啓用或關閉時,我們需要使用參數performance_schema=ON|OFF設置,並在my.cnf中進行配置:
[mysqld]
performance_schema = ON # 注意:該參數爲只讀參數,需要在實例啓動之前設置才生效
2.3.2.4.查詢是否開啓,
命令:SHOW VARIABLES LIKE 'performance_schema';
2.3.2.5.查詢引擎涉及到的所有表:
performance_schema引擎相關的元數據來了解在performance_schema下存在着哪些表:
命令:SELECT * FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA ='performance_schema' and engine='performance_schema';
2.3.3. performance_schema表的分類
performance_schema庫下的表可以按照監視不同的緯度進行了分組,例如:或按照不同數據庫對象進行分組,或按照不同的事件類型進行分組,或在按照事件類型分組之後,再進一步按照帳號、主機、程序、線程、用戶等
2.3.3.1. 事務相關
事務事件記錄表,記錄事務相關的事件的表,與語句事件類型的相關記錄表類似:
A.查詢語句:show tables like 'events_transaction%';
B.作用:
2.3.3.2.內存相關
A.查詢語句: show tables like 'events_transaction%';
2.3.3.3. 等待事件記錄相關
A.查詢語句:show tables like 'events_wait%';
+-----------------------------------------------+
| Tables_in_performance_schema (%wait%) |
+-----------------------------------------------+
| events_waits_current |
| events_waits_history |
| events_waits_history_long |
| events_waits_summary_by_account_by_event_name |
| events_waits_summary_by_host_by_event_name |
| events_waits_summary_by_instance |
| events_waits_summary_by_thread_by_event_name |
| events_waits_summary_by_user_by_event_name |
| events_waits_summary_global_by_event_name
2.3.3.4. 階段事件記錄相關
A.查詢語句:show tables like 'events_stage%';
都是events_stages_* 開頭的表
2.3.4. 運行時配置
2.3.4.1. 開啓配置
A.在引擎啓動時並非所有表instruments(事件採集項,在採集項的配置表中每一項都有一個開關字段YES和NO)和consumers(與採集項類似, YES就表示對應的表保存性能數據,爲NO就表示對應的表不保存性能數據)都啓用了。需要手動開啓收集配置。
B.打開等待事件的採集器配置項開關,需要修改setup_instruments 配置表中對應的採集器配置項
開啓語句:UPDATE setup_instruments SET ENABLED = 'YES', TIMED = 'YES' where name like 'wait%';
C.打開等待事件的保存表配置開關,修改修改setup_consumers 配置表
開啓語句:UPDATE setup_consumers SET ENABLED = 'YES' where name like '%wait%';
D.其他事件都類似
2.3.5. 應用:監控查詢例子
2.3.5.1.查詢連接數據庫實例的線程連接數量及賬號
select * from performance_schema.accounts;
- current_connections :當前連接數
- total_connections:總連接數
2.3.5.2.查詢SQL執行時長的歷史記錄
SELECT EVENT_ID, TRUNCATE(TIMER_WAIT/1000000000000,6) as Duration, SQL_TEXT FROM performance_schema.events_statements_current where SQL_TEXT IS NOT NULL AND SQL_TEXT <> 'BEGIN';