MySQL 事務主要用於處理操做量大,複雜度高的數據。好比說,在一個商城系統中,用戶執行購買操做,那麼用戶訂單中應該加一條,庫存要減一條,若是這兩步因爲意外只進行了其中一步那麼就會發生很大的問題。而事務能夠很好的解決這個問題。
事務是數據庫處理操做,其中執行就好像它是一個單一的一組有序的工做單元。換言之在組內每一個單獨的操做是成功的,那麼一個事務纔是完整的。若是事務中的任何操做失敗,整個事務將失敗。
事務性質:
-
原子性:確保工做單位中全部操做都成功完成;不然,事務被停止,在失敗時會回滾到事務操做之前的狀態。
-
一致性:可確保數據庫在正確的更改狀態進行一個成功的提交事務。
-
隔離性:使事務相互獨立的操做。
-
持久性:確保了提交事務的結果或系統故障狀況下仍然存在做用。
TCL(事務控制語言):
begin; 操做; commit; BEGIN或START TRANSACTION; #顯式地開啓一個事務 COMMIT;或COMMIT WORK; #兩者等階。COMMIT會提交事務並使已對數據庫進行的全部修改爲爲永久性的。未COMMIT的操做都存放在內存中,僅當前客戶端能夠查看到,其餘客戶端看不到,當前客戶端關閉後就清空了 ROLLBACK;或ROLLBACK WORK; #兩者等階。回滾會結束用戶的事務,並撤銷正在進行的全部未提交的修改 SET AUTOCOMMIT=0 #禁止自動提交 隱式開啓事務 SET AUTOCOMMIT=1 #開啓自動提交
事務併發的問題:mysql
1.髒讀:事務A讀取了事務B更新的數據,而後B回滾操做,那麼A讀取到的數據是髒數據sql
2.不可重複讀:事務A屢次讀取同一數據,事務B在事務A屢次讀取過程當中,對數據做了更新並提交 ,致使事務A屢次讀取同一數據時結果不一致數據庫
3.幻讀:系統管理員A將數據庫中全部學生的成績從具體分數改成ABCDE等級,可是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條沒有改過來,就好像發生了幻覺同樣緩存
各個隔離級別狀況:session
#查看隔離級別 select @@session.tx_isolation; #設置隔離級別 set session transaction isolation level read uncommitted
隔離級別 | 髒讀可能性 | 不可重複讀可能性 | 幻讀可能性 |
未提交讀 READ UNCOMMITED | 是 | 是 | 是 |
不可重複讀 READ COMMITED | 否 | 是 | 是 |
可重複讀 REPEATABLE READ | 否 | 否 | 是 |
串行化 SERIALIZABLE | 否 | 否 | 否 |
數據庫鎖
mysql不一樣存儲引擎支持不一樣鎖機制,innodb支持錶行級鎖默認行級鎖,memory採用表級鎖,bdb採用頁面鎖支持表級鎖。mysql優化
表級鎖:開銷小,加鎖快,不會出現死鎖;鎖定粒度大,發生鎖衝突的機率最高,併發度最低。不支持事務。架構
頁面鎖:開銷和加鎖時間介於先後者之間,會出現死鎖;鎖定粒度介於先後者之間,併發度通常。併發
行級鎖:開銷大,加鎖慢,會出現死鎖;鎖定粒度小,發生鎖的衝突機率最低,併發度也最高。負載均衡
表級鎖:兩種模式 共享鎖(讀鎖)與獨佔鎖(寫鎖,排他鎖),表級鎖引擎:MyISAM MEMORY函數
- 共享鎖:在讀的時候上鎖,全部人均可以訪問不阻塞其餘用戶對同一表讀請求,但阻塞同一表的寫操做包括本身;本身若是加了讀鎖,更新訪問其餘表會提示錯誤;加了讀鎖以後不能再加寫鎖
- 獨佔鎖:上鎖以後其餘人不能訪問,阻塞其餘用戶對同一表的讀和寫操做,獨佔鎖優先級別高於共享鎖;本身加了寫鎖能夠讀寫表中記錄,但更新訪問其餘表都會提示錯誤
MyISAM在執行查詢語句時會自動給涉及的全部表加讀鎖,在執行更新操做前加寫鎖,這個過程通常不須要用戶干預。
#加鎖 lock tables table_name read [local];lock tables table_name write [local]; #多表加鎖 lock tables table_name [table_name] read [local];lock tables table_name [table_name] write [local]; #釋放鎖 unlock tables; #查詢表級鎖爭用狀況 show status like 'table%'; show status like '%lock%';當waited immediate值比較大是說明阻塞嚴重 show processlist; #查看哪些sql在在等待鎖 show open tables; #當前被鎖住的表以及鎖的次數 #併發插入 myisam存儲引擎有一個系統變量concurrent_insert.專門用以控制其併發插入行爲,其值爲NEVER0、AUTO1(默認)、ALAWAYS2。
0:不容許併發插入 ,1:若是表中沒有空洞(表中沒有被刪除的行)myisam容許在一個進程讀表的同時,另外一個進程從表尾插入記錄,2:不管表中有沒有空洞,都容許在表尾插入記錄 #讀寫鎖優先級 max_write_lock_count=1 #設置寫鎖的最屢次數,當系統處理一個寫操做後就會暫停寫操做給讀操做執行機會 #下降寫操做優先級,給讀操做更高優先級 low_priority_updates=1 sql_low_priority_updates=1 在用寫操做時要加low_priority關鍵字#視場景而定,讀場景更重要或更多時如此設置
如何優化表所? concurrent_insert設置2,老是容許併發插入,可是要按期OPTIMIZE TABLE整理空間碎片;視狀況設置寫優先級;視狀況設置寫內存,解決批量插入數據(如新聞系統更新)場景中。
行級鎖:引擎InnoDB,模式包含 共享鎖(S),排它鎖(X),意向共享鎖(IS),意向排它鎖(IX) 若是一個事務請求的鎖模式與當前的鎖兼容,innoDB就將請求的鎖授予該事物;反之,若是二者不兼容,該事物就要等待鎖釋放
行級鎖特色:innoDB行鎖是經過給索引上的索引項加鎖來實現的,只有經過索引條件(例如id)檢索數據,innoDB才使用行級鎖,佛則將使用表鎖;意向鎖是innoDB自動加的,不須要用戶干預,對於寫操做(insert update delete)innodb會自動給涉及數據加排它鎖,對於select InnoDB不會加任何鎖
排它鎖(X) | 意向排它鎖(IX) | 共享鎖(S) | 意向共享鎖(IS) | |
---|---|---|---|---|
排它鎖(X) | 衝突 | 衝突 | 衝突 | 衝突 |
意向排它鎖(IX) | 衝突 | 兼容 | 衝突 | 兼容 |
共享鎖(S) | 衝突 | 衝突 | 兼容 | 兼容 |
意向共享鎖(IS) | 衝突 | 兼容 | 兼容 | 兼容 |
#加鎖 SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE #主動添加共享鎖(S) SELECT * FROM table_name WHERE ... FOR UPDATE #主動添加獨佔鎖(X) #釋放鎖 commit;或 rollback;
- 當使用行排他鎖寫數據時,其餘人沒法操做本條數據;
- 當給一條數據添加了排它鎖,其餘人對這條數據沒有任何權限,但並不影響其餘人對其餘數據操做;
- 在InnoDB默認的隔離方式下,操做者不提交,操做數據只保存在內存裏,另外一用戶能夠查詢,查詢到的是舊值;
- 即便字段家裏索引在使用時本身變了類型,索引失效會加表鎖;
間隙鎖:好比有124三個數據,操做>1的數據,此時添加3或者5都是不能夠的,因此要明確範圍防止間隙鎖
如何優化行級鎖:
- 儘可能使用較低的隔離級別(新手忽略);精心設計索引,並儘可能使用索引訪問數據,使加鎖更精確從而減小鎖衝突的機會
- 選擇合理的事務大小,小事務發生鎖衝突的概率也小
- 給記錄集手動加鎖時,最好一次性請求足夠級別的鎖
- 儘可能使用相等條件訪問數據,這樣能夠避免間隙鎖對併發插入的影響
- 對於一些特定事務,可使用表鎖提升速度並減小死鎖可能
數據庫優化操做
優化成本 硬件>系統配置>數據庫表結構>SQL語句及索引
優化效果 SQL語句及索引<數據庫表結構<系統配置<硬件
MySQL邏輯架構:
客戶端->鏈接線程處理->查詢緩存、分析器、優化器->存儲引擎
索引底層實現:B樹
myisam存儲是數據的地址 innodb存儲的是索引值,因此索引不宜過長
explain參數詳解:
select語句執行順序:執行順序:先where...group by ... having 再 select ... from ... 再 distinct ... order by ... limit ...
#使用方式: explain select * from demo; #參數: #id 執行順序 id相同時順序從被查詢表數據量少至多(都同樣的話按照書寫順序),子查詢時id由外到裏自增,先執行大的 #select_type 查詢中每一個select子句的類型 SIMPLE:簡單SELECT(不使用UNION或子查詢) PRIMARY:最外面的SELECT UNION:UNION中的第二個或後面的SELECT語句 DEPENDENT UNION:UNION中的第二個或後面的SELECT語句,取決於外面的查詢 UNION RESULT:UNION 的結果 SUBQUERY:子查詢中的第一個SELECT DEPENDENT SUBQUERY:子查詢中的第一個SELECT,取決於外面的查詢 DERIVED:派生表(FROM子句的子查詢) #table 本次查詢的表名,或派生表 #type mysql在表中的訪問類型 ALL: 遍歷全表,目標不帶索引 < index: 遍歷全表索引樹 < range: 檢索給定範圍的有索引的行,between、<、>,不能用in會使索引失效 < ref: 檢索給定具體值並有索引的行 < eq_ref: 檢索給定具體值並是惟一索引的行 < const: 表最多有一個匹配行,它將在查詢開始時被讀取。由於僅有一行,在這行的列值可被優化器剩餘部分認爲是常數 < system: 衍生查詢中只有一條數據 < NULL #possible_keys 本查詢可能用的索引 #key 本查詢真實用的索引 #key_len 索引在內存中佔的長度(輕易不要給varchar加索引) #ref 指定的條件類型 #rows 當前語句查到的行數 #Extra Distinct:MySQL發現第1個匹配行後,中止爲當前的行組合搜索更多的行。 Not exists:MySQL可以對查詢進行LEFT JOIN優化,發現1個匹配LEFT JOIN標準的行後,再也不爲前面的的行組合在該表內檢查更多的行。 range checked for each record (index map: ):MySQL沒有發現好的可使用的索引,但發現若是來自前面的表的列值已知,可能部分索引可使用。 Using filesort:MySQL須要額外的一次傳遞,以找出如何按排序順序檢索行。 Using index:從只使用索引樹中的信息而不須要進一步搜索讀取實際的行來檢索表中的列信息,表明性能不錯 Using temporary:爲了解決查詢,MySQL須要建立一個臨時表來容納結果。 Using where:WHERE 子句用於限制哪個行匹配下一個表或發送到客戶,性能通常 Using sort_union(...), Using union(...), Using intersect(...):這些函數說明如何爲index_merge聯接類型合併索引掃描。 Using index for group-by:相似於訪問表的Using index方式,Using index for group-by表示MySQL發現了一個索引,能夠用來查 詢GROUP BY或DISTINCT查詢的全部列,而不要額外搜索硬盤訪問實際的表。 IMPOSSIBLE :不可能的where語句如where id=1 and id=2
mysql優化方法:
- 經過使用explain命令分析sql語句的運行效率
- 經過開啓慢查詢日誌查看效率慢的sql語句
單多表sql優化手段:
- 給使用頻繁的字段加索引,調整索引順序最佳左前綴原則,刪除多餘干擾索引,調整查詢條件對索引有干擾的語句放最後
多表sql額外優化手段:
- 小表驅動大表(小表在左邊,where小表.x=大表.y)
- left join 給左邊表加索引,right join 給右邊表加索引
注意:
- 不要將索引做爲函數參數或表達式的一部分,這樣會讓索引失效;索引不要進行類型轉化不然失效
- 複合索引應該遵循最佳左前綴,不要用or,in,!= < >關鍵字不然失效
- 及時刪除冗長,不經常使用的索引
- like查詢時儘可能不要使用左邊%引發索引失效
系統級別優化:
- 主從複製,讀寫分離,負載均衡
其餘優化:
- 選儘可能小的數據類型,列設置not null,加unsigned不容許加正負這樣可使正數上線多一倍,存儲時間最好用TIMESTAMP使用4個字節存儲,大多數狀況下沒有枚舉類型的必要,表的列不要太不要超過10個字段多影響內存數據類型小而簡單