mysql啓動後(能夠把mysql類比爲一個後臺的服務器),等待客戶端請求,當請求到來後,mysql創建一個一個線程處理(線程池則分配一個空線程,固然也可以使用nio線程模型。),每一個線程獨立,擁有獨自內存空間。當請求爲select請求則沒有關係,可是請求爲update時,多線程同時修改一塊內存,就會引起一系列問題,由此引出 「鎖「的概念。mysql
查看mysql當前鏈接數:sql
show VARIABLES like '%max_connections%'數據庫
修改mysql鏈接數爲200
set GLOBAL max_connections = 200緩存
同時當客戶端鏈接到mysql服務器時,服務器會對其進行權限驗證,包括,ip,用戶名,密碼的驗證,同時還要驗證是否有對操做某一個庫,表的權限。服務器
show variables like '%query_cache_type%'session
SET GLOBAL query_cache_size = 188888888; 數據結構
是否打開mysql查詢結果緩存,默認關閉,打開後,mysql會對查詢出來的結果進行緩存,實際應用中業務數據通常不在db層緩存多線程
mysql默認打開sql解析緩存;平時咱們說的sql緩存,通常指的sql解析緩存。架構
mysql對客戶端傳入的sql語句會按照必定的規則進行sql解析,然後進行sql優化,最後執行優化過的sql語句。而不是直接執行。併發
show engines;查看存儲引擎
進入show VARIABLES like 'datadir' 查看mysql數據文件所在路徑,發現myisam引擎會生產三個數據文件,xxx.frm存儲表結構文件,全部引擎都有此文件,xxx.MYD存儲表數據文件,xxx.MYI存儲表索引文件
特性:
併發性
支持表級鎖,
支持全文檢索,
支持數據文件壓縮
試用場景:
只讀類應用;
非事物行應用(數據倉庫,報表,數據)
空間類應用(座標)
show VARIABLES like 'innodb_file_per_table' 查看innodb表空間類型
set global innodb_file_per_table=off 設置innodb使用系統表空間
mysql5.6之前默認使用系統表空間
系統表空間沒法簡單的收縮文件大小。
獨立表空能夠經過optimize table 收縮系統文件
系統表空間會產生io瓶頸
獨立表空間能夠同時向多個文件刷新數據
推薦使用獨立表空間
特性:
Innodb是一種事務性存儲引擎
徹底支持事物的acid特性
redo Log和Undo Log
Innodb支持行級鎖(併發度更高)
試用場景
適合大多數的oltp應用。
特色:
以csv格式進行數據存儲,
全部列都不能爲空,
不支持索引,
能夠直接對數據文件直接編輯(直接修改文本文件,達到修改表的目的)。
create table mycsv(id int not null,c1 VARCHAR(10) not null,c2 char(10) not null)
engine=csv;
insert into mycsv values(1,'aaa','bbb'),(2,'cccc','dddd');
修改文本數據
flush TABLES;
select * from mycsv
create index idx_id on mycsv(id)
應用場景:
須要頻繁導入導出表數據的場景,如財務報表類
應用場景:日誌以及數據採集。
show VARIABLES like 'max_heap_table_size' 查看memory引擎最大空間。
使用場景:
hash索引用於查找或者是映射表(郵編和地區對應)
用於保存數據分析中產生的中間表
用於緩存週期性聚合數據的結果表
memory數據容易丟失,因此要求數據可再生。
Ferderted
特色:提供了遠程訪問mysql服務器上表的方法
本地不存儲數據,數據所有放到遠程服務器上
本地須要保存表結構和遠程服務器的鏈接信息
使用場景:邊界數據庫,表 同步
該引擎默認禁止,啓用時需增長federated參數
代表,列名須要與遠程表相同
CREATE TABLE `local_fed` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`c1` varchar(10) NOT NULL DEFAULT '',
`c2` char(10) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=federated CONNECTION
='mysql://root:123456@127.0.0.1:3306/remote/remote_fed'
MyISAM表級鎖的兩種模式:table read lock 表共享讀鎖;table write Lock 表獨佔寫鎖;
加共享表級讀鎖: lock table 表名 read
1. lock table testmysam READ
啓動另一個session select * from
testmysam 能夠查詢
2. insert into testmysam value(2);
update testmysam set id=2 where id=1;
報錯
3.在另一個session中
insert into testmysam value(2); 等待
4.在同一個session中
insert into testdemo value(2,'2','3'); 報錯
select * from testdemo ; 報錯
5.在另一個session中
insert into testdemo value(2,'2','3'); 成功
6.加鎖在同一個session 中 select s.* from testmysam s 報錯
lock table 表名 as 別名 read;
查看 show status LIKE 'table_locks_waited' 表被鎖過幾回
加獨佔表級寫鎖:lock table 表名 write
1.lock table testmysam WRITE
在同一個session中
insert testmysam value(3);
delete from testmysam where id = 3
select * from testmysam
2.對不一樣的表操做(報錯)
select s.* from testmysam s
insert into testdemo value(2,'2','3');
3.在其餘session中 (等待)
select * from testmysam
Innodb行鎖
共享行鎖又稱讀鎖;當一個事務對某幾行上讀鎖時,容許其餘事務對這幾行讀操做,可是不予許其進行寫操做,也不予許其餘事務給這幾行上排它鎖,但容許上讀鎖。
排它鎖又稱寫鎖;當一個事務對某幾行上寫鎖時,容許其餘事務對這幾行讀操做,不予許其進行寫操做,更不予許其餘事務給這幾行上鎖,包括讀鎖。
注意:1.兩個事務不能鎖同一個索引。
2.insert,delete,update在事務中會默認加上排它鎖
3.行鎖必須有索引才能實現,不然會自動寫全表,那麼就不是行鎖了
1.
BEGIN
select * from testdemo where id =1 for update
在另一個session中
update testdemo set c1 = '1' where id = 2 成功
update testdemo set c1 = '1' where id = 1 等待
2.BEGIN
update testdemo set c1 = '1' where id = 1
在另一個session中
update testdemo set c1 = '1' where id = 1 等待
3.
BEGIN
update testdemo set c1 = '1' where c1 = '1'
在另一個session中
update testdemo set c1 = '2' where c1 = '2' 等待
如今的不少軟件都是多用戶,多程序,多線程的,對同一個表可能同時有不少人在用,爲保持數據的一致性,因此提出了事務的概念。
事務應該具備4個屬性:原子性、一致性、隔離性、持久性。這四個屬性一般稱爲ACID特性。
原子性(atomicity)。一個事務是一個不可分割的工做單位,事務中包括的諸操做要麼都作,要麼都不作。
一致性(consistency)。事務必須是使數據庫從一個一致性狀態變到另外一個一致性狀態。一致性與原子性是密切相關的。
隔離性(isolation)。一個事務的執行不能被其餘事務干擾。即一個事務內部的操做及使用的數據對併發的其餘事務是隔離的,併發執行的各個事務之間不能互相干擾。
持久性(durability)。持久性也稱永久性(permanence),指一個事務一旦提交,它對數據庫中數據的改變就應該是永久性的。接下來的其餘操做或故障不該該對其有任何影響。
mysql默認的事務隔離級別爲repeatable-read
show variables like '%tx_isolation%';
set SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
測試:
啓動兩個session
一個session中
start TRANSACTION
update account set balance = balance -50 where id = 1
另一個session中查詢
select * from account
回到第一個session中 回滾事務
ROLLBACK
在第二個session種
update account set balance = balance -50 where id = 1
查詢結果仍是 400
第二個session覺得結果是350,但前面的400數據爲髒讀數據,致使最後的結果和意料中的結果並不一致。
測試
show variables like '%tx_isolation%';
set SESSION TRANSACTION ISOLATION LEVEL read committed;
一個session中
start TRANSACTION
update account set balance = balance -50 where id = 1
另一個session中查詢 (數據並沒改變)
select * from account
回到第一個session中 回滾事務
commit
在第二個session種
select * from account (數據已經改變)
測試
show variables like '%tx_isolation%';
set SESSION TRANSACTION ISOLATION LEVEL repeatable read;
一個session中
start TRANSACTION
update account set balance = balance -50 where id = 1
另一個session中查詢 (數據並沒改變)
select * from account
回到第一個session中 回滾事務
commit
在第二個session種
select * from account (數據並未改變)
測試
show variables like '%tx_isolation%';
set SESSION TRANSACTION ISOLATION LEVEL repeatable read;
account 表有3條記錄,業務規定,最多容許4條記錄。
開啓一個事務
begin
select * from account 發現3條記錄
開啓另一個事務
begin
select * from account 發現3條記錄 也是3條記錄
insert into account VALUES(4,'deer',500)
查詢 4條記錄
select * from account
回到第一個session
insert into account VALUES(5,'james',500)
select * from account 4條記錄
session1 與 session2 都提交事務
set SESSION TRANSACTION ISOLATION LEVEL serializable; 從新上面的測試發現插入報錯
事務隔離級別爲可重複讀時,若是有索引(包括主鍵索引)的時候,以索引列爲條件更新數據,會存在間隙鎖間、行鎖、頁鎖的問題,從而鎖住一些行;若是沒有索引,更新數據時會鎖住整張表
事務隔離級別爲串行化時,讀寫數據都會鎖住整張表
隔離級別越高,越能保證數據的完整性和一致性,可是對併發性能的影響也越大,對於多數應用程序,能夠優先考慮把數據庫系統的隔離級別設爲Read Committed,它可以避免髒讀取,並且具備較好的併發性能。
MySQL官方對索引的定義爲:索引(Index)是幫助MySQL高效獲取數據的數據結構。
能夠獲得索引的本質:索引是數據結構。
平時咱們到圖書館,首先看到的都是目錄,經過目錄去查詢想要的書籍會很是的迅速。
咱們要去圖書館找一本書,這圖書館的書確定不是線性存放的,它對不一樣的書籍內容進行了分類存放,整索引因爲一個個節點組成,根節點有中間節點,中間節點下面又由子節點,最後一層是葉子節點,
可見,整個索引結構是一棵倒掛着的樹,其實它就是一種數據結構,這種數據結構比前面講到的線性目錄更好的增長了查詢的速度。
MySql中的索引其實也是這麼一回事,咱們能夠在數據庫中創建一系列的索引,好比建立主鍵的時候默認會建立主鍵索引,上圖是一種BTREE的索引。每個節點都是主鍵的Id
當咱們經過ID來查詢內容的時候,首先去查索引庫,在到索引庫後能快速的定位索引的具體位置。
索引得分類
普通索引:即一個索引只包含單個列,一個表能夠有多個單列索引
惟一索引:索引列的值必須惟一,但容許有空值
複合索引:即一個索引包含多個列
聚簇索引(彙集索引):並非一種單獨的索引類型,而是一種數據存儲方式(索引與數據放在同一個文件裏)。具體細節取決於不一樣的實現,InnoDB的聚簇索引其實就是在同一個結構中保存了B-Tree索引(技術上來講是B+Tree)和數據行。
非聚簇索引:不是聚簇索引,就是非聚簇索引
查看索引
SHOW INDEX FROM table_name\G
建立索引
CREATE [UNIQUE ] INDEX indexName ON mytable(columnname(length));
ALTER TABLE 表名 ADD [UNIQUE ] INDEX [indexName] ON (columnname(length))
刪除索引
DROP INDEX [indexName] ON mytable;
什麼是慢查詢
慢查詢日誌,顧名思義,就是查詢慢的日誌,是指mysql記錄全部執行超過long_query_time參數設定的時間閾值的SQL語句的日誌。該日誌能爲SQL語句的優化帶來很好的幫助。默認狀況下,慢查詢日誌是關閉的,要使用慢查詢日誌功能,首先要開啓慢查詢日誌功能。
slow_query_log 啓動中止技術慢查詢日誌
slow_query_log_file 指定慢查詢日誌得存儲路徑及文件(默認和數據文件放一塊兒)
long_query_time 指定記錄慢查詢日誌SQL執行時間得伐值(單位:秒,默認10秒)
log_queries_not_using_indexes 是否記錄未使用索引的SQL
log_output 日誌存放的地方【TABLE】【FILE】【FILE,TABLE】
配置了慢查詢後,它會記錄符合條件的SQL
包括:
查詢語句
數據修改語句
已經回滾得SQL
實操:
經過下面命令查看下上面的配置:
show VARIABLES like '%slow_query_log%'
show VARIABLES like '%slow_query_log_file%'
show VARIABLES like '%long_query_time%'
show VARIABLES like '%log_queries_not_using_indexes%'
show VARIABLES like 'log_output'
set global long_query_time=0; ---默認10秒,這裏爲了演示方便設置爲0
set GLOBAL slow_query_log = 1; --開啓慢查詢日誌
set global log_output='FILE,TABLE' --項目開發中日誌只能記錄在日誌文件中,不能記表中
設置完成後,查詢一些列表能夠發現慢查詢的日誌文件裏面有數據了。
從慢查詢日誌裏面摘選一條慢查詢日誌,數據組成以下
第一行:用戶名 、用戶的IP信息、線程ID號
第二行:執行花費的時間【單位:毫秒】
第三行:執行得到鎖的時間
第四行:得到的結果行數
第五行:掃描的數據行數
第六行:這SQL執行的具體時間
第七行:具體的SQL語句
使用EXPLAIN關鍵字能夠模擬優化器執行SQL查詢語句,從而知道MySQL是如何處理你的SQL語句的。分析你的查詢語句或是表結構的性能瓶頸。
表的讀取順序
數據讀取操做的操做類型
哪些索引可使用
哪些索引被實際使用
表之間的引用
每張表有多少行被優化器查詢
執行計劃的語法其實很是簡單: 在SQL查詢的前面加上EXPLAIN關鍵字就行。
好比:EXPLAIN select * from table1
重點的就是EXPLAIN後面你要分析的SQL語句
ID列:描述select查詢的序列號,包含一組數字,表示查詢中執行select子句或操做表的順序
根據ID的數值結果能夠分紅一下三種狀況
id相同:執行順序由上至下
id不一樣:若是是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
id相同不一樣:同時存在
分別舉例來看
如上圖所示,ID列的值全爲1,表明執行的容許從t1開始加載,依次爲t3與t2
EXPLAIN
select t2.* from t1,t2,t3 where t1.id = t2.id and t1.id = t3.id
and t1.other_column = '';
Id不一樣
若是是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
EXPLAIN
select t2.* from t2 where id = (
select id from t1 where id = (select t3.id from t3 where t3.other_column='')
);
Id相同又不一樣
id若是相同,能夠認爲是一組,從上往下順序執行;
在全部組中,id值越大,優先級越高,越先執行
EXPLAIN
select t2.* from (
select t3.id
from t3 where t3.other_column = ''
) s1 ,t2 where s1.id = t2.id
Select_type:查詢的類型,
要是用於區別:普通查詢、聯合查詢、子查詢等的複雜查詢
類型以下
SIMPLE
EXPLAIN select * from t1
簡單的 select 查詢,查詢中不包含子查詢或者UNION
PRIMARY與SUBQUERY
PRIMARY:查詢中若包含任何複雜的子部分,最外層查詢則被標記爲
SUBQUERY:在SELECT或WHERE列表中包含了子查詢
EXPLAIN
select t1.*,(select t2.id from t2 where t2.id = 1 ) from t1
DERIVED
在FROM列表中包含的子查詢被標記爲DERIVED(衍生)
MySQL會遞歸執行這些子查詢, 把結果放在臨時表裏。
.UNION RESULT 與UNION
UNION:若第二個SELECT出如今UNION以後,則被標記爲UNION;
UNION RESULT:從UNION表獲取結果的SELECT
#UNION RESULT ,UNION
EXPLAIN
select * from t1
UNION
select * from t2
顯示這一行的數據是關於哪張表的
type顯示的是訪問類型,是較爲重要的一個指標,結果值從最好到最壞依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
須要記憶的
system>const>eq_ref>ref>range>index>ALL
通常來講,得保證查詢至少達到range級別,最好能達到ref。
System與const
System:表只有一行記錄(等於系統表),這是const類型的特列,平時不會出現,這個也能夠忽略不計
Const:表示經過索引一次就找到了
const用於比較primary key或者unique索引。由於只匹配一行數據,因此很快
如將主鍵置於where列表中,MySQL就能將該查詢轉換爲一個常量
eq_ref
惟一性索引掃描,對於每一個索引鍵,表中只有一條記錄與之匹配。常見於主鍵或惟一索引掃描
Ref
非惟一性索引掃描,返回匹配某個單獨值的全部行.
本質上也是一種索引訪問,它返回全部匹配某個單獨值的行,然而,它可能會找到多個符合條件的行,因此他應該屬於查找和掃描的混合體
Range
只檢索給定範圍的行,使用一個索引來選擇行。key 列顯示使用了哪一個索引
通常就是在你的where語句中出現了between、<、>、in等的查詢
這種範圍掃描索引掃描比全表掃描要好,由於它只須要開始於索引的某一點,而結束語另外一點,不用掃描所有索引。
Index
當查詢的結果全爲索引列的時候,雖然也是所有掃描,可是隻查詢的索引庫,而沒有去查詢
數據。
All
Full Table Scan,將遍歷全表以找到匹配的行
possible_keys 與Key
possible_keys:可能使用的key
Key:實際使用的索引。若是爲NULL,則沒有使用索引
查詢中若使用了覆蓋索引,則該索引和查詢的select字段重疊
Key_len表示索引中使用的字節數,可經過該列計算查詢中使用的索引的長度。在不損失精確性的狀況下,長度越短越好
key_len顯示的值爲索引字段的最大可能長度,並不是實際使用長度,即key_len是根據表定義計算而得,不是經過表內檢索出的
key_len表示索引使用的字節數,
根據這個值,就能夠判斷索引使用狀況,特別是在組合索引的時候,判斷全部的索引字段是否都被查詢用到。
char和varchar跟字符編碼也有密切的聯繫,
latin1佔用1個字節,gbk佔用2個字節,utf8佔用3個字節。(不一樣字符編碼佔用的存儲空間不一樣)
字符類型
字符類型-索引字段爲char類型+不可爲Null時
name這一列爲char(10),字符集爲utf-8佔用3個字節Keylen=10*3
字符類型-索引字段爲char類型+容許爲Null時
name這一列爲char(10),字符集爲utf-8佔用3個字節,外加須要存入一個null值
Keylen=10*3+1(null) 結果爲31
索引字段爲varchar類型+不可爲Null時
Keylen=varchar(n)變長字段+不容許Null=n*(utf8=3,gbk=2,latin1=1)+2
索引字段爲varchar類型+容許爲Null時
Keylen=varchar(n)變長字段+容許Null=n*(utf8=3,gbk=2,latin1=1)+1(NULL)+2
字符類型
變長字段須要額外的2個字節(VARCHAR值保存時只保存須要的字符數,另加一個字節來記錄長度(若是列聲明的長度超過255,則使用兩個字節),因此VARCAHR索引長度計算時候要加2),固定長度字段不須要額外的字節。
而NULL都須要1個字節的額外空間,因此索引字段最好不要爲NULL,由於NULL讓統計更加複雜而且須要額外的存儲空間。
複合索引有最左前綴的特性,若是複合索引能所有使用上,則是複合索引字段的索引長度之和,這也能夠用來斷定複合索引是否部分使用,仍是所有使用。
整數/浮點數/時間類型的索引長度
NOT NULL=字段自己的字段長度
NULL=字段自己的字段長度+1(由於須要有是否爲空的標記,這個標記須要佔用1個字節)
datetime類型在5.6中字段長度是5個字節,datetime類型在5.5中字段長度是8個字節
顯示索引的哪一列被使用了,若是可能的話,是一個常數。哪些列或常量被用於查找索引列上的值
由key_len可知t1表的idx_col1_col2被充分使用,col1匹配t2表的col1,col2匹配了一個常量,即 'ac'
其中 【shared.t2.col1】 爲 【數據庫.表.列】
根據表統計信息及索引選用狀況,大體估算出找到所需的記錄所須要讀取的行數
包含不適合在其餘列中顯示但十分重要的額外信息。
Using filesort
說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。MySQL中沒法利用索引完成的排序操做稱爲「文件排序」
當發現有Using filesort 後,實際上就是發現了能夠優化的地方
上圖實際上是一種索引失效的狀況,後面會講,能夠看出查詢中用到了個聯合索引,索引分別爲col1,col2,col3
當我排序新增了個col2,發現using filesort 就沒有了。
Using temporary
使了用臨時表保存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序 order by 和分組查詢 group by。
尤爲發如今執行計劃裏面有using filesort並且還有Using temporary的時候,特別須要注意
Using index
表示相應的select操做中使用了覆蓋索引(Covering Index),避免訪問了表的數據行,效率不錯!
若是同時出現using where,代表索引被用來執行索引鍵值的查找;
若是沒有同時出現using where,代表索引用來讀取數據而非執行查找動做
覆蓋索引(Covering Index),一說爲索引覆蓋。
理解方式一:就是select的數據列只用從索引中就可以取得,沒必要讀取數據行,MySQL能夠利用索引返回select列表中的字段,而沒必要根據索引再次讀取數據文件,換句話說查詢列要被所建的索引覆蓋。
理解方式二:索引是高效找到行的一個方法,可是通常數據庫也能使用索引找到一個列的數據,所以它沒必要讀取整個行。畢竟索引葉子節點存儲了它們索引的數據;當能經過讀取索引就能夠獲得想要的數據,那就不須要讀取行了。一個索引包含了(或覆蓋了)知足查詢結果的數據就叫作覆蓋索引
注意:
若是要使用覆蓋索引,必定要注意select列表中只取出須要的列,不可select *,
由於若是將全部字段一塊兒作索引會致使索引文件過大,查詢性能降低。
因此,千萬不能爲了查詢而在全部列上都創建索引,會嚴重影響修改維護的性能。
Using where 與 using join buffer
Using where
代表使用了where過濾
using join buffer
使用了鏈接緩存:
impossible where
where子句的值老是false,不能用來獲取任何元組
全職匹配我最愛,最左前綴要遵照;
帶頭大哥不能死,中間兄弟不能斷;
索引列上少計算,範圍以後全失效;
LIKE百分寫最右,覆蓋索引不寫*;
全職匹配我最愛?
當創建了索引列後,能在where條件中使用索引的儘可能所用。
最左前綴要遵照,帶頭大哥不能死,中間兄弟不能斷?
若是索引了多列,要遵照最左前綴法則。指的是查詢從索引的最左前列開始而且不跳過索引中的列。
聯合索引index(name,age,pos),帶頭大哥name,少了索引直接失效,使用(name,pos)丟下中間兄弟age索引失效。
索引列上少計算?
不在索引列上作任何操做(計算、函數、(自動or手動)類型轉換),會致使索引失效而轉向全表掃描
範圍以後全失效?
中間有範圍查詢會致使後面的索引列所有失效
EXPLAIN SELECT * FROM staffs WHERE NAME = 'July' and age >22 and pos='manager'
LIKE百分寫最右?
like以通配符開頭('%abc...')mysql索引失效會變成全表掃描的操做
解決方式:覆蓋索引
EXPLAIN select name,age,pos from staffs where name like '%july%'
覆蓋索引不寫* ?
使用select * from 破壞了了覆蓋索引的使用條件。
補充兩個比較偏的
索引不可爲空
在字段爲not null的狀況下,使用is null 或 is not null 會致使索引失效
解決方式:覆蓋索引
EXPLAIN select name,age,pos from staffs where name is not null
索引可爲空:
Is not null 的狀況會致使索引失效