mysql的鎖機制
1、MySQL鎖的基本介紹
鎖是計算機協調多個進程或線程併發訪問某一資源的機制。在數據庫中,除傳統的 計算資源(如CPU、RAM、I/O等)的爭用以外,數據也是一種供許多用戶共享的資源。如何保證數據併發訪問的一致性、有效性是所有數據庫必須解決的一 個問題,鎖衝突也是影響數據庫併發訪問性能的一個重要因素。從這個角度來說,鎖對數據庫而言顯得尤其重要,也更加複雜。
相對其他數據庫而言,MySQL的鎖機制比較簡單,其最 顯著的特點是不同的存儲引擎支持不同的鎖機制。比如,MyISAM和MEMORY存儲引擎採用的是表級鎖(table-level locking);InnoDB存儲引擎既支持行級鎖(row-level locking),也支持表級鎖,但默認情況下是採用行級鎖。
表級鎖:開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低。
行級鎖:開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。
從上述特點可見,很難籠統地說哪種鎖更好,只能就具體應用的特點來說哪種鎖更合適!僅從鎖的角度 來說:表級鎖更適合於以查詢爲主,只有少量按索引條件更新數據的應用,如Web應用;而行級鎖則更適合於有大量按索引條件併發更新少量不同數據,同時又有 併發查詢的應用,如一些在線事務處理(OLTP)系統。
2、MyISAM表鎖
MySQL的表級鎖有兩種模式:表共享讀鎖(Table Read Lock)和表獨佔寫鎖(Table Write Lock)。
對MyISAM表的讀操作,不會阻塞其他用戶對同一表的讀請求,但會阻塞對同一表的寫請求;對 MyISAM表的寫操作,則會阻塞其他用戶對同一表的讀和寫操作;MyISAM表的讀操作與寫操作之間,以及寫操作之間是串行的!
建表語句:
CREATE TABLE `mylock` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`NAME` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('1', 'a');
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('2', 'b');
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('3', 'c');
INSERT INTO `mylock` (`id`, `NAME`) VALUES ('4', 'd');
MyISAM寫鎖阻塞讀的案例:
當一個線程獲得對一個表的寫鎖之後,只有持有鎖的線程可以對錶進行更新操作。其他線程的讀寫操作都會等待,直到鎖釋放爲止。
session1 | session2 |
---|---|
獲取表的write鎖定 lock table mylock write; |
|
當前session對錶的查詢,插入,更新操作都可以執行 select * from mylock; insert into mylock values(5,‘e’); |
當前session對錶的查詢會被阻塞 select * from mylock; |
釋放鎖: unlock tables; |
當前session能夠立刻執行,並返回對應結果 |
MyISAM讀阻塞寫的案例:
一個session使用lock table給表加讀鎖,這個session可以鎖定表中的記錄,但更新和訪問其他表都會提示錯誤,同時,另一個session可以查詢表中的記錄,但更新就會出現鎖等待。
session1 | session2 |
---|---|
獲得表的read鎖定 lock table mylock read; |
|
當前session可以查詢該表記錄: select * from mylock; |
當前session可以查詢該表記錄: select * from mylock; |
當前session不能查詢沒有鎖定的表 select * from person Table ‘person’ was not locked with LOCK TABLES |
當前session可以查詢或者更新未鎖定的表 select * from mylock insert into person values(1,‘zhangsan’); |
當前session插入或者更新表會提示錯誤 insert into mylock values(6,‘f’) Table ‘mylock’ was locked with a READ lock and can’t be updated update mylock set name=‘aa’ where id = 1; Table ‘mylock’ was locked with a READ lock and can’t be updated |
當前session插入數據會等待獲得鎖 insert into mylock values(6,‘f’); |
釋放鎖 unlock tables; |
獲得鎖,更新成功 |
注意:
MyISAM在執行查詢語句之前,會自動給涉及的所有表加讀鎖,在執行更新操作前,會自動給涉及的表加寫鎖,這個過程並不需要用戶干預,因此用戶一般不需要使用命令來顯式加鎖,上例中的加鎖時爲了演示效果。
MyISAM的併發插入問題
MyISAM表的讀和寫是串行的,這是就總體而言的,在一定條件下,MyISAM也支持查詢和插入操作的併發執行
session1 | session2 |
---|---|
獲取表的read local鎖定 lock table mylock read local |
|
當前session不能對錶進行更新或者插入操作 insert into mylock values(6,‘f’) Table ‘mylock’ was locked with a READ lock and can’t be updated update mylock set name=‘aa’ where id = 1; Table ‘mylock’ was locked with a READ lock and can’t be updated |
其他session可以查詢該表的記錄 select* from mylock |
當前session不能查詢沒有鎖定的表 select * from person Table ‘person’ was not locked with LOCK TABLES |
其他session可以進行插入操作,但是更新會阻塞 update mylock set name = ‘aa’ where id = 1; |
當前session不能訪問其他session插入的記錄; | |
釋放鎖資源:unlock tables | 當前session獲取鎖,更新操作完成 |
當前session可以查看其他session插入的記錄 |
可以通過檢查table_locks_waited和table_locks_immediate狀態變量來分析系統上的表鎖定爭奪:
mysql> show status like 'table%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Table_locks_immediate | 352 |
| Table_locks_waited | 2 |
+-----------------------+-------+
--如果Table_locks_waited的值比較高,則說明存在着較嚴重的表級鎖爭用情況。
InnoDB鎖
1、事務及其ACID屬性
事務是由一組SQL語句組成的邏輯處理單元,事務具有4屬性,通常稱爲事務的ACID屬性。
原子性(Actomicity):事務是一個原子操作單元,其對數據的修改,要麼全都執行,要麼全都不執行。
一致性(Consistent):在事務開始和完成時,數據都必須保持一致狀態。
隔離性(Isolation):數據庫系統提供一定的隔離機制,保證事務在不受外部併發操作影響的“獨立”環境執行。
持久性(Durable):事務完成之後,它對於數據的修改是永久性的,即使出現系統故障也能夠保持。
2、併發事務帶來的問題
相對於串行處理來說,併發事務處理能大大增加數據庫資源的利用率,提高數據庫系統的事務吞吐量,從而可以支持更多用戶的併發操作,但與此同時,會帶來一下問題:
髒讀: 一個事務正在對一條記錄做修改,在這個事務並提交前,這條記錄的數據就處於不一致狀態;這時,另一個事務也來讀取同一條記錄,如果不加控制,第二個事務讀取了這些“髒”的數據,並據此做進一步的處理,就會產生未提交的數據依賴關係。這種現象被形象地叫做“髒讀”
不可重複讀:一個事務在讀取某些數據已經發生了改變、或某些記錄已經被刪除了!這種現象叫做“不可重複讀”。
幻讀: 一個事務按相同的查詢條件重新讀取以前檢索過的數據,卻發現其他事務插入了滿足其查詢條件的新數據,這種現象就稱爲“幻讀”
上述出現的問題都是數據庫讀一致性的問題,可以通過事務的隔離機制來進行保證。
數據庫的事務隔離越嚴格,併發副作用就越小,但付出的代價也就越大,因爲事務隔離本質上就是使事務在一定程度上串行化,需要根據具體的業務需求來決定使用哪種隔離級別
髒讀 | 不可重複讀 | 幻讀 | |
---|---|---|---|
read uncommitted | √ | √ | √ |
read committed | √ | √ | |
repeatable read | √ | ||
serializable |
可以通過檢查InnoDB_row_lock狀態變量來分析系統上的行鎖的爭奪情況:
mysql> show status like 'innodb_row_lock%';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| Innodb_row_lock_current_waits | 0 |
| Innodb_row_lock_time | 18702 |
| Innodb_row_lock_time_avg | 18702 |
| Innodb_row_lock_time_max | 18702 |
| Innodb_row_lock_waits | 1 |
+-------------------------------+-------+
--如果發現鎖爭用比較嚴重,如InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值比較高
3、InnoDB的行鎖模式及加鎖方法
共享鎖(s):又稱讀鎖。允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖。若事務T對數據對象A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。
排他鎖(x):又稱寫鎖。允許獲取排他鎖的事務更新數據,阻止其他事務取得相同的數據集共享讀鎖和排他寫鎖。若事務T對數據對象A加上X鎖,事務T可以讀A也可以修改A,其他事務不能再對A加任何鎖,直到T釋放A上的鎖。
mysql InnoDB引擎默認的修改數據語句:update,delete,insert都會自動給涉及到的數據加上排他鎖,select語句默認不會加任何鎖類型,如果加排他鎖可以使用select …for update語句,加共享鎖可以使用select … lock in share mode語句。所以加過排他鎖的數據行在其他事務種是不能修改數據的,也不能通過for update和lock in share mode鎖的方式查詢數據,但可以直接通過select …from…查詢數據,因爲普通查詢沒有任何鎖機制。
InnoDB行鎖實現方式
InnoDB行鎖是通過給索引上的索引項加鎖來實現的,這一點MySQL與Oracle不同,後者是通過在數據塊中對相應數據行加鎖來實現的。InnoDB這種行鎖實現特點意味着:只有通過索引條件檢索數據,InnoDB才使用行級鎖,否則,InnoDB將使用表鎖!
1、在不通過索引條件查詢的時候,innodb使用的是表鎖而不是行鎖
create table tab_no_index(id int,name varchar(10)) engine=innodb;
insert into tab_no_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
session1 | session2 |
---|---|
set autocommit=0 select * from tab_no_index where id = 1; |
set autocommit=0 select * from tab_no_index where id =2 |
select * from tab_no_index where id = 1 for update | |
select * from tab_no_index where id = 2 for update; |
session1只給一行加了排他鎖,但是session2在請求其他行的排他鎖的時候,會出現鎖等待。原因是在沒有索引的情況下,innodb只能使用表鎖。
2、創建帶索引的表進行條件查詢,innodb使用的是行鎖
create table tab_with_index(id int,name varchar(10)) engine=innodb;
alter table tab_with_index add index id(id);
insert into tab_with_index values(1,'1'),(2,'2'),(3,'3'),(4,'4');
session1 | session2 |
---|---|
set autocommit=0 select * from tab_with_indexwhere id = 1; |
set autocommit=0 select * from tab_with_indexwhere id =2 |
select * from tab_with_indexwhere id = 1 for update | |
select * from tab_with_indexwhere id = 2 for update; |
3、由於mysql的行鎖是針對索引加的鎖,不是針對記錄加的鎖,所以雖然是訪問不同行的記錄,但是如果是使用相同的索引鍵,是會出現衝突的。
alter table tab_with_index drop index id;
insert into tab_with_index values(1,'4');
session1 | session2 |
---|---|
set autocommit=0 | set autocommit=0 |
select * from tab_with_index where id = 1 and name=‘1’ for update | |
select * from tab_with_index where id = 1 and name=‘4’ for update 雖然session2訪問的是和session1不同的記錄,但是因爲使用了相同的索引,所以需要等待鎖 |
總結
對於MyISAM的表鎖,主要討論了以下幾點:
(1)共享讀鎖(S)之間是兼容的,但共享讀鎖(S)與排他寫鎖(X)之間,以及排他寫鎖(X)之間是互斥的,也就是說讀和寫是串行的。
(2)在一定條件下,MyISAM允許查詢和插入併發執行,我們可以利用這一點來解決應用中對同一表查詢和插入的鎖爭用問題。
(3)MyISAM默認的鎖調度機制是寫優先,這並不一定適合所有應用,用戶可以通過設置LOW_PRIORITY_UPDATES參數,或在INSERT、UPDATE、DELETE語句中指定LOW_PRIORITY選項來調節讀寫鎖的爭用。
(4)由於表鎖的鎖定粒度大,讀寫之間又是串行的,因此,如果更新操作較多,MyISAM表可能會出現嚴重的鎖等待,可以考慮採用InnoDB表來減少鎖衝突。
對於InnoDB表,本文主要討論了以下幾項內容:
(1)InnoDB的行鎖是基於索引實現的,如果不通過索引訪問數據,InnoDB會使用表鎖。
(2)在不同的隔離級別下,InnoDB的鎖機制和一致性讀策略不同。
在瞭解InnoDB鎖特性後,用戶可以通過設計和SQL調整等措施減少鎖衝突和死鎖,包括:
- 儘量使用較低的隔離級別; 精心設計索引,並儘量使用索引訪問數據,使加鎖更精確,從而減少鎖衝突的機會;
- 選擇合理的事務大小,小事務發生鎖衝突的機率也更小;
- 給記錄集顯式加鎖時,最好一次性請求足夠級別的鎖。比如要修改數據的話,最好直接申請排他鎖,而不是先申請共享鎖,修改時再請求排他鎖,這樣容易產生死鎖;
- 不同的程序訪問一組表時,應儘量約定以相同的順序訪問各表,對一個表而言,儘可能以固定的順序存取表中的行。這樣可以大大減少死鎖的機會;
- 儘量用相等條件訪問數據,這樣可以避免間隙鎖對併發插入的影響; 不要申請超過實際需要的鎖級別;除非必須,查詢時不要顯示加鎖;
- 對於一些特定的事務,可以使用表鎖來提高處理速度或減少死鎖的可能。
mysql讀寫分離
1、讀寫分離的介紹
MySQL讀寫分離基本原理是讓master數據庫處理寫操作,slave數據庫處理讀操作。master將寫操作的變更同步到各個slave節點。
MySQL讀寫分離能提高系統性能的原因在於:
1、物理服務器增加,機器處理能力提升。拿硬件換性能。
2、主從只負責各自的讀和寫,極大程度緩解X鎖和S鎖爭用。
3、slave可以配置myiasm引擎,提升查詢性能以及節約系統開銷。
4、master直接寫是併發的,slave通過主庫發送來的binlog恢復數據是異步。
5、slave可以單獨設置一些參數來提升其讀的性能。
6、增加冗餘,提高可用性。
2、讀寫分離的配置
1、硬件配置
master 192.168.85.11
slave 192.168.85.12
proxy 192,168.85.14
2、首先在master和slave上配置主從複製
3、進行proxy的相關配置
#1、下載mysql-proxy
https://downloads.mysql.com/archives/proxy/#downloads
#2、上傳軟件到proxy的機器
直接通過xftp進行上傳
#3、解壓安裝包
tar -zxvf mysql-proxy-0.8.5-linux-glibc2.3-x86-64bit.tar.gz
#4、修改解壓後的目錄
mv mysql-proxy-0.8.5-linux-glibc2.3-x86-64bit mysql-proxy
#5、進入mysql-proxy的目錄
cd mysql-proxy
#6、創建目錄
mkdir conf
mkdir logs
#7、添加環境變量
#打開/etc/profile文件
vi /etc/profile
#在文件的最後面添加一下命令
export PATH=$PATH:/root/mysql-proxy/bin
#8、執行命令讓環境變量生效
source /etc/profile
#9、進入conf目錄,創建文件並添加一下內容
vi mysql-proxy.conf
添加內容
[mysql-proxy]
user=root
proxy-address=192.168.85.14:4040
proxy-backend-addresses=192.168.85.11:3306
proxy-read-only-backend-addresses=192.168.85.12:3306
proxy-lua-script=/root/mysql-proxy/share/doc/mysql-proxy/rw-splitting.lua
log-file=/root/mysql-proxy/logs/mysql-proxy.log
log-level=debug
daemon=true
#10、開啓mysql-proxy
mysql-proxy --defaults-file=/root/mysql-proxy/conf/mysql-proxy.conf
#11、查看是否安裝成功,打開日誌文件
cd /root/mysql-proxy/logs
tail -100 mysql-proxy.log
#內容如下:表示安裝成功
2019-10-11 21:49:41: (debug) max open file-descriptors = 1024
2019-10-11 21:49:41: (message) proxy listening on port 192.168.85.14:4040
2019-10-11 21:49:41: (message) added read/write backend: 192.168.85.11:3306
2019-10-11 21:49:41: (message) added read-only backend: 192.168.85.12:3306
2019-10-11 21:49:41: (debug) now running as user: root (0/0)
4、進行連接
#mysql的命令行會出現無法連接的情況,所以建議使用客戶端
mysql -uroot -p123 -h192.168.85.14 -P 4040
mysql執行計劃
在企業的應用場景中,爲了知道優化SQL語句的執行,需要查看SQL語句的具體執行過程,以加快SQL語句的執行效率。
可以使用explain+SQL語句來模擬優化器執行SQL查詢語句,從而知道mysql是如何處理sql語句的。
官網地址: https://dev.mysql.com/doc/refman/5.5/en/explain-output.html
1、執行計劃中包含的信息
Column | Meaning |
---|---|
id | The SELECT identifier |
select_type | The SELECT type |
table | The table for the output row |
partitions | The matching partitions |
type | The join type |
possible_keys | The possible indexes to choose |
key | The index actually chosen |
key_len | The length of the chosen key |
ref | The columns compared to the index |
rows | Estimate of rows to be examined |
filtered | Percentage of rows filtered by table condition |
extra | Additional information |
id
select查詢的序列號,包含一組數字,表示查詢中執行select子句或者操作表的順序
id號分爲三種情況:
1、如果id相同,那麼執行順序從上到下
explain select * from emp e join dept d on e.deptno = d.deptno join salgrade sg on e.sal between sg.losal and sg.hisal;
2、如果id不同,如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
explain select * from emp e where e.deptno in (select d.deptno from dept d where d.dname = 'SALES');
3、id相同和不同的,同時存在:相同的可以認爲是一組,從上往下順序執行,在所有組中,id值越大,優先級越高,越先執行
explain select * from emp e join dept d on e.deptno = d.deptno join salgrade sg on e.sal between sg.losal and sg.hisal where e.deptno in (select d.deptno from dept d where d.dname = 'SALES');
select_type
主要用來分辨查詢的類型,是普通查詢還是聯合查詢還是子查詢
select_type Value |
Meaning |
---|---|
SIMPLE | Simple SELECT (not using UNION or subqueries) |
PRIMARY | Outermost SELECT |
UNION | Second or later SELECT statement in a UNION |
DEPENDENT UNION | Second or later SELECT statement in a UNION, dependent on outer query |
UNION RESULT | Result of a UNION. |
SUBQUERY | First SELECT in subquery |
DEPENDENT SUBQUERY | First SELECT in subquery, dependent on outer query |
DERIVED | Derived table |
UNCACHEABLE SUBQUERY | A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query |
UNCACHEABLE UNION | The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY) |
--sample:簡單的查詢,不包含子查詢和union
explain select * from emp;
--primary:查詢中若包含任何複雜的子查詢,最外層查詢則被標記爲Primary
explain select staname,ename supname from (select ename staname,mgr from emp) t join emp on t.mgr=emp.empno ;
--union:若第二個select出現在union之後,則被標記爲union
explain select * from emp where deptno = 10 union select * from emp where sal >2000;
--dependent union:跟union類似,此處的depentent表示union或union all聯合而成的結果會受外部表影響
explain select * from emp e where e.empno in ( select empno from emp where deptno = 10 union select empno from emp where sal >2000)
--union result:從union表獲取結果的select
explain select * from emp where deptno = 10 union select * from emp where sal >2000;
--subquery:在select或者where列表中包含子查詢
explain select * from emp where sal > (select avg(sal) from emp) ;
--dependent subquery:subquery的子查詢要受到外部表查詢的影響
explain select * from emp e where e.deptno in (select distinct deptno from dept);
--DERIVED: from子句中出現的子查詢,也叫做派生類,
explain select staname,ename supname from (select ename staname,mgr from emp) t join emp on t.mgr=emp.empno ;
--UNCACHEABLE SUBQUERY:表示使用子查詢的結果不能被緩存
explain select * from emp where empno = (select empno from emp where deptno=@@sort_buffer_size);
--uncacheable union:表示union的查詢結果不能被緩存:sql語句未驗證
table
對應行正在訪問哪一個表,表名或者別名,可能是臨時表或者union合併結果集
1、如果是具體的表名,則表明從實際的物理表中獲取數據,當然也可以是表的別名
2、表名是derivedN的形式,表示使用了id爲N的查詢產生的衍生表
3、當有union result的時候,表名是union n1,n2等的形式,n1,n2表示參與union的id
type
type顯示的是訪問類型,訪問類型表示我是以何種方式去訪問我們的數據,最容易想的是全表掃描,直接暴力的遍歷一張表去尋找需要的數據,效率非常低下,訪問的類型有很多,效率從最好到最壞依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般情況下,得保證查詢至少達到range級別,最好能達到ref
--all:全表掃描,一般情況下出現這樣的sql語句而且數據量比較大的話那麼就需要進行優化。
explain select * from emp;
--index:全索引掃描這個比all的效率要好,主要有兩種情況,一種是當前的查詢時覆蓋索引,即我們需要的數據在索引中就可以索取,或者是使用了索引進行排序,這樣就避免數據的重排序
explain select empno from emp;
--range:表示利用索引查詢的時候限制了範圍,在指定範圍內進行查詢,這樣避免了index的全索引掃描,適用的操作符: =, <>, >, >=, <, <=, IS NULL, BETWEEN, LIKE, or IN()
explain select * from emp where empno between 7000 and 7500;
--index_subquery:利用索引來關聯子查詢,不再掃描全表
explain select * from emp where emp.job in (select job from t_job);
--unique_subquery:該連接類型類似與index_subquery,使用的是唯一索引
explain select * from emp e where e.deptno in (select distinct deptno from dept);
--index_merge:在查詢過程中需要多個索引組合使用,沒有模擬出來
--ref_or_null:對於某個字段即需要關聯條件,也需要null值的情況下,查詢優化器會選擇這種訪問方式
explain select * from emp e where e.mgr is null or e.mgr=7369;
--ref:使用了非唯一性索引進行數據的查找
create index idx_3 on emp(deptno);
explain select * from emp e,dept d where e.deptno =d.deptno;
--eq_ref :使用唯一性索引進行數據查找
explain select * from emp,emp2 where emp.empno = emp2.empno;
--const:這個表至多有一個匹配行,
explain select * from emp where empno = 7369;
--system:表只有一行記錄(等於系統表),這是const類型的特例,平時不會出現
possible_keys
顯示可能應用在這張表中的索引,一個或多個,查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢實際使用
explain select * from emp,dept where emp.deptno = dept.deptno and emp.deptno = 10;
key
實際使用的索引,如果爲null,則沒有使用索引,查詢中若使用了覆蓋索引,則該索引和查詢的select字段重疊。
explain select * from emp,dept where emp.deptno = dept.deptno and emp.deptno = 10;
key_len
表示索引中使用的字節數,可以通過key_len計算查詢中使用的索引長度,在不損失精度的情況下長度越短越好。
explain select * from emp,dept where emp.deptno = dept.deptno and emp.deptno = 10;
ref
顯示索引的哪一列被使用了,如果可能的話,是一個常數
explain select * from emp,dept where emp.deptno = dept.deptno and emp.deptno = 10;
rows
根據表的統計信息及索引使用情況,大致估算出找出所需記錄需要讀取的行數,此參數很重要,直接反應的sql找了多少數據,在完成目的的情況下越少越好
explain select * from emp;
extra
包含額外的信息。
--using filesort:說明mysql無法利用索引進行排序,只能利用排序算法進行排序,會消耗額外的位置
explain select * from emp order by sal;
--using temporary:建立臨時表來保存中間結果,查詢完成之後把臨時表刪除
explain select ename,count(*) from emp where deptno = 10 group by ename;
--using index:這個表示當前的查詢時覆蓋索引的,直接從索引中讀取數據,而不用訪問數據表。如果同時出現using where 表名索引被用來執行索引鍵值的查找,如果沒有,表面索引被用來讀取數據,而不是真的查找
explain select deptno,count(*) from emp group by deptno limit 10;
--using where:使用where進行條件過濾
explain select * from t_user where id = 1;
--using join buffer:使用連接緩存,情況沒有模擬出來
--impossible where:where語句的結果總是false
explain select * from emp where empno = 7469;
mysql主從複製原理
0、爲什麼需要主從複製?
1、在業務複雜的系統中,有這麼一個情景,有一句sql語句需要鎖表,導致暫時不能使用讀的服務,那麼就很影響運行中的業務,使用主從複製,讓主庫負責寫,從庫負責讀,這樣,即使主庫出現了鎖表的情景,通過讀從庫也可以保證業務的正常運作。
2、做數據的熱備
3、架構的擴展。業務量越來越大,I/O訪問頻率過高,單機無法滿足,此時做多庫的存儲,降低磁盤I/O訪問的頻率,提高單個機器的I/O性能。
1、什麼是mysql的主從複製?
MySQL 主從複製是指數據可以從一個MySQL數據庫服務器主節點複製到一個或多個從節點。MySQL 默認採用異步複製方式,這樣從節點不用一直訪問主服務器來更新自己的數據,數據的更新可以在遠程連接上進行,從節點可以複製主數據庫中的所有數據庫或者特定的數據庫,或者特定的表。
2、mysql複製原理
原理:
(1)master服務器將數據的改變記錄二進制binlog日誌,當master上的數據發生改變時,則將其改變寫入二進制日誌中;
(2)slave服務器會在一定時間間隔內對master二進制日誌進行探測其是否發生改變,如果發生改變,則開始一個I/OThread請求master二進制事件
(3)同時主節點爲每個I/O線程啓動一個dump線程,用於向其發送二進制事件,並保存至從節點本地的中繼日誌中,從節點將啓動SQL線程從中繼日誌中讀取二進制日誌,在本地重放,使得其數據和主節點的保持一致,最後I/OThread和SQLThread將進入睡眠狀態,等待下一次被喚醒。
也就是說:
- 從庫會生成兩個線程,一個I/O線程,一個SQL線程;
- I/O線程會去請求主庫的binlog,並將得到的binlog寫到本地的relay-log(中繼日誌)文件中;
- 主庫會生成一個log dump線程,用來給從庫I/O線程傳binlog;
- SQL線程,會讀取relay log文件中的日誌,並解析成sql語句逐一執行;
注意:
1–master將操作語句記錄到binlog日誌中,然後授予slave遠程連接的權限(master一定要開啓binlog二進制日誌功能;通常爲了數據安全考慮,slave也開啓binlog功能)。
2–slave開啓兩個線程:IO線程和SQL線程。其中:IO線程負責讀取master的binlog內容到中繼日誌relay log裏;SQL線程負責從relay log日誌裏讀出binlog內容,並更新到slave的數據庫裏,這樣就能保證slave數據和master數據保持一致了。
3–Mysql複製至少需要兩個Mysql的服務,當然Mysql服務可以分佈在不同的服務器上,也可以在一臺服務器上啓動多個服務。
4–Mysql複製最好確保master和slave服務器上的Mysql版本相同(如果不能滿足版本一致,那麼要保證master主節點的版本低於slave從節點的版本)
5–master和slave兩節點間時間需同步
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-JqbjGUTC-1593568641510)(e:\lian\oracle\mysql\主從原理.png)]
具體步驟:
1、從庫通過手工執行change master to 語句連接主庫,提供了連接的用戶一切條件(user 、password、port、ip),並且讓從庫知道,二進制日誌的起點位置(file名 position 號); start slave
2、從庫的IO線程和主庫的dump線程建立連接。
3、從庫根據change master to 語句提供的file名和position號,IO線程向主庫發起binlog的請求。
4、主庫dump線程根據從庫的請求,將本地binlog以events的方式發給從庫IO線程。
5、從庫IO線程接收binlog events,並存放到本地relay-log中,傳送過來的信息,會記錄到master.info中
6、從庫SQL線程應用relay-log,並且把應用過的記錄到relay-log.info中,默認情況下,已經應用過的relay 會自動被清理purge
3、mysql主從形式
(一)一主一從
(二)主主複製
(三)一主多從
(四)多主一從
(五)聯級複製
4、mysql主從同步延時分析
mysql的主從複製都是單線程的操作,主庫對所有DDL和DML產生的日誌寫進binlog,由於binlog是順序寫,所以效率很高,slave的sql thread線程將主庫的DDL和DML操作事件在slave中重放。DML和DDL的IO操作是隨機的,不是順序,所以成本要高很多,另一方面,由於sql thread也是單線程的,當主庫的併發較高時,產生的DML數量超過slave的SQL thread所能處理的速度,或者當slave中有大型query語句產生了鎖等待,那麼延時就產生了。
解決方案:
1.業務的持久化層的實現採用分庫架構,mysql服務可平行擴展,分散壓力。
2.單個庫讀寫分離,一主多從,主寫從讀,分散壓力。這樣從庫壓力比主庫高,保護主庫。
3.服務的基礎架構在業務和mysql之間加入memcache或者redis的cache層。降低mysql的讀壓力。
4.不同業務的mysql物理上放在不同機器,分散壓力。
5.使用比主庫更好的硬件設備作爲slave,mysql壓力小,延遲自然會變小。
6.使用更加強勁的硬件設備
mysql5.7之後使用MTS並行複製技術,永久解決複製延時問題------自學