mysql專欄爲你彌補這塊的短板
後續我會在這塊給大家帶來mysql方面的知識,分享我在這塊的經驗。
mysql學習是一個漫長的過程,我希望大家能夠不要浮躁,靜下心來好好的學習基礎知識,先把心法學會了,招式就是千變萬化。平時我們使用數據庫,看到的通常是一個整體。比如,你有一個最簡單的表,表裏有一個字段X、下面有一個執行語句:
mysql>select * from mytable where X=?;
或者更加複雜的語句。。。我這裏就不在舉例了。
我們看到給出一個語句,如果數據庫有數據就會返回相應的結果。卻不知道這條語句在MYSQL內部是如何執行的,我今天就給大家拆解一下MYSQL,希望這個拆解過程能讓你對MYSQL有更深入的理解,這樣我們遇到一些問題,或者異常我們能夠快速的定位並且解決問題。
先看一下MYSQL官方的架構:
連接器
第一步,你會先連接到數據庫,這個時候就是mysql連接器負責跟客戶端建立連接,獲取權限,管理連接。
linux命令連接mysql如下:
mysql -h&ip -P&port -u&username -p&password
不建議直接輸入密碼,存在安全隱患,最好直接-p enter 輸入你的密碼
在完成和服務器端TCP的三次握手後,就會驗證身份,如果用戶名和密碼不對就會提示ERROR 1045 (28000): Access denied for user ‘meiling’@‘yourip’ (using password: YES)
如果登錄成功後,我們在通過root權限對其修改權限,是不影響已經登錄後權限的限制。我就不列出來了,大家可以自己嘗試一下。
連接完成後,我們不操作任何命令,連接就處於空閒狀態,我們用show processlist看看情況。
可以看到狀態是 "sleep"就是空閒狀態客戶端很久都沒操作,連接器就會自動斷開。這個時間的參數可以看 wait_timeout,默認是8小時。
mysql> show variables like '%wait_timeout%';
+--------------------------+----------+
| Variable_name | Value |
+--------------------------+----------+
| innodb_lock_wait_timeout | 50 |
| lock_wait_timeout | 31536000 |
| wait_timeout | 28800 |
+--------------------------+----------+
3 rows in set
mysql>
我們可以看到是28800秒,換算成小時就是8個小時。你們可以自己看一下這個參數。
數據庫經典8小時問題,就是這個默認參數如果發現一個連接的空閒時間超過8小時,將會在數據庫端自動關閉這個連接。而數據源並不知道這個連接已經關閉了,當它將這個無用的連接返回給某個dao時,dao就會報無法獲取connection異常。
所以我們可以針對這個參數來防止線上問題的發生哦,這個比較隱患。
1.我們可以適當的調整timeout的大小。
2.通過應用層當有空閒的連接的時候,就去激活一下,免得過期造成連接丟失。
數據的連接我們儘量的減少連接次數,連接的過程非常的複雜,太耗費資源,基本上都是長連接。
案例:有一次我們線上的數據庫宕機了,發現非常多的連接導致內存漲的非常的快,長期累積的長連接導致我們內存佔用過大,被系統強制殺掉了mysql進程。
原因分析:就是因爲mysql在執行過程中使用的內存是在連接對象管理的,這些資源只會在連接斷開後纔會釋放。
1,我們就在應用程序裏面定期斷開長連接,具體的實現我會專門有一篇文章(如何斷開連接)
2,通過mysql_reset_connection方式來重置連接。下面是mysql官方提供的api說明
27.8.7.60 mysql_reset_connection()
int mysql_reset_connection(MYSQL *mysql)
說明
重置連接以清除會話狀態。
mysql_reset_connection() 具有類似於 mysql_change_user() 的效果或自動重新連接,但連接未關閉並重新打開,並且未執行重新認證。見 Section 27.8.7.3, “mysql_change_user()” )並參見 Section 27.8.20, “C API Automatic Reconnection Control” )。
與連接相關的狀態受影響如下:
回滾任何活動事務並重置自動提交模式。
釋放所有表鎖。
所有 TEMPORARY 表都已關閉(並已刪除)。
會話系統變量重新初始化爲相應的全局系統變量的值,包括由 SET NAMES 等語句隱式設置的系統變量。
用戶變量設置丟失。
準備好的聲明已經發布。
HANDLER 變量已關閉。
LAST_INSERT_ID() 的值重置爲0。
使用 GET_LOCK() 獲取的鎖定被釋放。
返回值
成功歸零。如果發生錯誤,則爲非零。
查詢緩存
這個很簡單,就是一個key-value的方式。
假如一條sql語句 select * from T where id=1;就會通過key是sql語句去map中查詢是否有這條語句,如果有就直接返回,沒有就執行後面的流程,把數據通過key-value的方式存儲。
查看mysql是否開啓緩存,執行如下命令:
mysql> show variables like '%query_cache_type%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| query_cache_type | ON |
+------------------+-------+
1 row in set (0.00 sec)
這個可以看到mysql是否開啓了緩存。
但是實際使用的我個人覺得沒什麼必要打開緩存,緩存命中非常的低,我們的業務經常在更改變化,如何一旦有表數據發生變化,緩存就會清除。所以實戰中我們是不會打開緩存的。
命令解析層
如果緩存沒有命中的話,就會分析當前的sql,分析當前的語句是查詢,還是ddl,還是其他的命令。
mysql>select * from mytable where X=?; //繼續解說這條
我們輸入的select 這個關鍵詞就會識別出來是查詢模塊,在分別把mytable識別成表名 mytable ,把字符串識X別成列X。
後面就會做語法的分析,如果語法不對就會提示你錯誤。
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘ad’ at line 1
我們只需要關注的是 "user near"的內容,基本上就可以知道是什麼錯誤了。
優化器
經過分析器後,mysql就知道你要做什麼了,在調用執行器錢,還要做一些優化的處理。
優化器就是選擇哪種方案去執行我們的sql。
簡單的使用 OPTIMIZER_TRACE
查看是否開啓優化器
mysql> show variables like '%optimizer_trace%';
+------------------------------+----------------------------------------------------------------------------+
| Variable_name | Value |
+------------------------------+----------------------------------------------------------------------------+
| optimizer_trace | enabled=off,one_line=off |
| optimizer_trace_features | greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on |
| optimizer_trace_limit | 1 |
| optimizer_trace_max_mem_size | 16384 |
| optimizer_trace_offset | -1 |
+------------------------------+----------------------------------------------------------------------------+
開啓優化器
mysql> set session optimizer_trace='enabled=on';
Query OK, 0 rows affected
mysql> show variables like '%optimizer_trace%';
+------------------------------+----------------------------------------------------------------------------+
| Variable_name | Value |
+------------------------------+----------------------------------------------------------------------------+
| optimizer_trace | enabled=on,one_line=off |
| optimizer_trace_features | greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on |
| optimizer_trace_limit | 1 |
| optimizer_trace_max_mem_size | 16384 |
| optimizer_trace_offset | -1 |
+------------------------------+----------------------------------------------------------------------------+
5 rows in set
//執行一條查詢語句
mysql> select * from oc_user where cid='e7cf68e15ba3480f';
+-----+------------------+----------+-----------+----------+-------------+---------+-------+-----------+------------+------------+--------+---------------------+------------+
| id | cid | nickname | username | password | phone | iconURL | email | ipaddress | devicetype | macaddress | frozen | createtime | updatetime |
+-----+------------------+----------+-----------+----------+-------------+---------+-------+-----------+------------+------------+--------+---------------------+------------+
| 129 | e7cf68e15ba3480f | NULL | ac_3Fhtni | NULL | 13966789831 | NULL | NULL | NULL | NULL | NULL | NULL | 2017-11-27 14:18:56 | NULL |
+-----+------------------+----------+-----------+----------+-------------+---------+-------+-----------+------------+------------+--------+---------------------+------------+
1 row in set
查看優化器如何執行的
mysql> select trace from information_schema.optimizer_trace;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| trace |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| {
"steps": [
{
"join_preparation": { //優化準備階段
"select#": 1,
"steps": [
{
//表示出來查詢的sql語句
"expanded_query": "/* select#1 */ select `oc_user`.`id` AS `id`,`oc_user`.`cid` AS `cid`,`oc_user`.`nickname` AS `nickname`,`oc_user`.`username` AS `username`,`oc_user`.`password` AS `password`,`oc_user`.`phone` AS `phone`,`oc_user`.`iconURL` AS `iconURL`,`oc_user`.`email` AS `email`,`oc_user`.`ipaddress` AS `ipaddress`,`oc_user`.`devicetype` AS `devicetype`,`oc_user`.`macaddress` AS `macaddress`,`oc_user`.`frozen` AS `frozen`,`oc_user`.`createtime` AS `createtime`,`oc_user`.`updatetime` AS `updatetime` from `oc_user` where (`oc_user`.`cid` = 'e7cf68e15ba3480f')"
}
]
}
},
{
"join_optimization": {//優化工作的主要階段,包括邏輯和物理的2個階段優化
"select#": 1,
"steps": [
{
"condition_processing": {//邏輯優化部分
"condition": "WHERE", //先看where條件,
"original_condition": "(`oc_user`.`cid` = 'e7cf68e15ba3480f')",
"steps": [
{
"transformation": "equality_propagation",//邏輯優化,條件優化,等式處理
"resulting_condition": "(`oc_user`.`cid` = 'e7cf68e15ba3480f')"
},
{
"transformation": "constant_propagation",//邏輯優化,條件優化,常量處理
"resulting_condition": "(`oc_user`.`cid` = 'e7cf68e15ba3480f')"
},
{
"transformation": "trivial_condition_removal",,//邏輯優化,條件簡化,條件去除
"resulting_condition": "(`oc_user`.`cid` = 'e7cf68e15ba3480f')"
}
]
}
},
{
//這裏是邏輯優化後 where條件優化結束
"substitute_generated_columns": {
}
},
{
"table_dependencies": [//邏輯優化,找出表之間的相互依賴關係,非直接可用的優化方式
{
"table": "`oc_user`",//有哪些表
"row_may_be_null": false,//是否可以不存在行數據
"map_bit": 0,//從0開始
"depends_on_map_bits": [
]
}
]
},
{
"ref_optimizer_key_uses": [//邏輯優化,找出備選的索引
{
"table": "`oc_user`",
"field": "cid", //這個是索引字段,下面的一樣
"equals": "'e7cf68e15ba3480f'",
"null_rejecting": false
}
]
},
{
"rows_estimation": [//邏輯優化, 估算每個表的元組個數. 單表上進行全表掃描和索引掃描的代價估算. 每個索引都估算索引掃描代價(估算行數)
{
"table": "`oc_user`", //表名
"rows": 1,//有多少行
"cost": 1,//代價,這個值越大,花費的代價越大
"table_type": "const", //表的類型
"empty": false//是否爲空
}
]
},
{
"condition_on_constant_tables": "('e7cf68e15ba3480f' = 'e7cf68e15ba3480f')",
"condition_value": true
},
{
"attaching_conditions_to_tables": {//邏輯優化,儘量吧條件綁定到對應的表上。
"original_condition": "('e7cf68e15ba3480f' = 'e7cf68e15ba3480f')",
"attached_conditions_computation": [
],
"attached_conditions_summary": [
]
}
},
{
"refine_plan": [
]
}
]
}
},
{
"join_execution": {
"select#": 1,
"steps": [
]
}
}
]
} |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set
執行器
mysql通過分析器知道了要做什麼,優化器該怎麼做,接下來就進入了執行器階段,開始執行語句。
在執行語句的時候,mysql還是要堅持一下執行是否有權限,如果沒有就會返回權限錯誤。
比如我們例子中的mytable表,字段X沒有索引,那麼執行器就是循環的調用InnoDb引擎接口獲取表的數據,然後在對比一下是否和我們傳入的值一樣,如果不是就繼續,是就直接存在結果集。直到取到表的最後一行數據,在把結果集返回給客戶端。
到此,語句執行完畢。