mysql sql優化 & 事務處理特徵 & 約束新增、刪除
阿新 • • 發佈:2021-06-30
索引樹高度
-
表的資料量
-
資料量越大,樹的高度就會變高,理論上三層索引樹的高度最為理想,可以支援百萬級別的資料量
-
解決:可以使用分表(橫切,豎切),分庫,增加快取,解決資料量大,查詢慢
-
-
索引鍵值過長
- 該索引欄位儲存資料太大,滅個葉子節點最大儲存16k,超過這個範圍會新增加葉子節點和分頁節點
- 解決:字首索引(擷取前5個長度)
-
資料型別
- char(定長) varchar(變長) 從開闢空間的速度來看,char快;從資料結構上看,varchar更為合理
- (1) 避免使用select ,不確定表大小的時候,使用count()查一下資料
- (2) 儘量使用資料型別較小的欄位做索引
- (3) 重複值少的,區分度高的欄位做索引,性別這樣的欄位不要做索引
- (4) 在奪標查詢時 使用join,儘量少的使用子查詢
- char(定長) varchar(變長) 從開闢空間的速度來看,char快;從資料結構上看,varchar更為合理
執行計劃
-
desc/explain
-
執行計劃:在一條sql執行之前,指定執行的方案
desc select * from s1; mysql> desc select * from ceshi_table; +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+ | 1 | SIMPLE | ceshi_table | NULL | ALL | NULL | NULL | NULL | NULL | 6 | 100.00 | NULL | +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec) mysql> explain select * from ceshi_table; +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+ | 1 | SIMPLE | ceshi_table | NULL | ALL | NULL | NULL | NULL | NULL | 6 | 100.00 | NULL | +----+-------------+-------------+------------+------+---------------+------+---------+------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec)
-
select_type
- simple 代表的是簡單查詢(單邊查詢,不包括子查詢,union)
- primary sql巢狀中的主查詢(最外層)
- subquery sql巢狀中的子查詢(最裡面)
- derived 衍生查詢(把子查詢結果作為一張臨時表)
-
table
- 在多表或者子查詢時候,通過table分析出問題的表是誰
-
type
-
顯示執行計劃的型別,優先順序從低到高如下,優化時至少達到range或者ref級別
all < index < range < ref < eq_ref < const < system
-
all 全表掃描(不走索引)
- 在大範圍內查詢 > < >= <= != between and in like ..
- where條件中有計算,有函式
- 資料型別不匹配
- 拼接條件使用or
-
index 全索引掃描
-
掃描整個索引樹,才能獲取到所有資料,這樣的索引失去意義
desc select count(*) from s1;
-
-
range 索引範圍掃描(注意點:範圍太大,不能命中索引),慢查詢
desc select * from s1 where id < 10; #type=range desc select * from s1 where id < 1000000; #type=all desc select * from s1 where id between 1 and 10;#type=range desc select * from s1 where id between 1 and 100000; #type=all desc select * from s1 where email like "%w%"; #type=all desc select * from s1 where email like "w%"; #type=range '''如果範圍過大,不能命中索引,如果範圍適當,可以命中索引''' desc select * from s1 where id in (1,2,3) #對in或者or這樣的語句進行優化 '''優化:union all比union速度快,union在合併資料之後,多一步去重操作''' desc select * from s1 where id=1 union all select * from s1 where id = 1; desc select * from s1 where id=1 union select * from s1 where id = 1; #優化or條件 desc select * from s1 where id = 10 or name ='aaaa'; desc select * from s1 where id = 10 union all select * from s1 where name = 'aaaa';
-
ref 普通索引查詢(非唯一)
desc select * from s1 where email = 'xboyww10@oldboy'; desc select * from s1 where id = 10;
-
eq_ref 唯一性索引(聯表)
alter table s1 drop index index_id; alter table s1 add primary key(id); desc select * from s1 where id = 10;
create database db0624; use db0624; #建立一張表 create table class1(id int,classname varchar(255)); create table student1( id int primary key auto_increment, name varchar(255) not null, age int not null, class_id int ); #插入資料 insert into student1 values(null,;"wangbaoqiang",82,2); insert into student1 values(null,;"wanglihong",7,1); insert into student1 values(null,;"wangwen",7,2); insert into class1 values(1,"python30"); insert into class1 values(2,"python31");
'''要求:應用在多聯表中,被關聯的欄位需要主鍵或者唯一,表之間的關係為一對一併且資料條數相同''' desc select student1.age from student1,class1 where student1.class_id = class1.id;#ALL alter table class1 add primary key(id); desc select student1.age from student1,class1 where student1.class_id = class1.id;#INDEX delete from student1 where id = 3; desc select student1.age from student1,class1 where student1.class_id = class1.id;#EQ_REF
-
const:主鍵或者唯一索引(單表)
'''針對於primary key 和unique索引等值查詢''' desc select * from class1 where id=1; #const desc select * from class1 where id>1; #range
-
system(瞭解)
- 只有一條資料的系統表
-
-
possible_keys:執行sql時,可能用到的索引是誰
-
key:執行sql時,實際用到的索引是誰
show index from s1;展現表s1所有的索引
-
key_len :判斷聯合索引覆蓋的長度(通過位元組數可以判定出到底觸發了那些)
#在沒有not null約束的時候,預設預留一個位元組,標記是空或者非空 #utf8 通常情況下,中文1個字元佔用3個位元組,字母佔用1個位元組,極個別的生僻字佔4個位元組 #varchar每次儲存資料的時候,系統底層預設會額外預留2個位元組 有not null(不為空) 沒有not null(可為空) tinyint 1 1+1 int 4 4+1 char(5) 5*3 5*3+1 varchar(5) 5*3 + 2 5*3+2+1
create table t100( n1 int, n2 int not null, n3 char(5), n4 char(5) not null, n5 varchar(5), n6 varchar(5) not null, index index_n1(n1,n2,n3), index index_n4(n4,n5,n6) ); insert into t100 values(1,2,"a","b","aa","bb"); insert into t100 values(1,2,"a","b","aa","bb"); insert into t100 values(1,2,"a","b","aa","bb"); insert into t100 values(1,2,"a","b","cc","dd"); #把資料表中的資料匯入 mysql> desc t100; +-------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------------+------+-----+---------+-------+ | n1 | int(11) | YES | MUL | NULL | | | n2 | int(11) | NO | | NULL | | | n3 | char(5) | YES | | NULL | | | n4 | char(5) | NO | MUL | NULL | | | n5 | varchar(5) | YES | | NULL | | | n6 | varchar(5) | NO | | NULL | | +-------+------------+------+-----+---------+-------+ 6 rows in set (0.00 sec) mysql> select * from t100; +------+----+------+----+------+----+ | n1 | n2 | n3 | n4 | n5 | n6 | +------+----+------+----+------+----+ | 1 | 2 | a | b | aa | bb | | 1 | 2 | a | b | aa | bb | | 1 | 2 | a | b | aa | bb | | 1 | 2 | a | b | cc | dd | +------+----+------+----+------+----+ 4 rows in set (0.00 sec) n1->5B n2->4B n3->16B 5+4+16=25 desc select * from t100 where n1 = 2 and n2 = 2 and n3 ="a";#命中n1 n2 n3 desc select * from t100 where n1 = 1 and n2 = 2 and n3 ="a";#如果有重複資料,不會觸發聯合索引 desc select * from t100 where n1 = 1 and n2 = 2;#如果有重複資料,不會觸發聯合索引 desc select * from t100 where n1 = 2 and n2 = 2;# n1 -> 5B n2->4B 命中n1,n2 desc select * from t100 where n1 = 2;#n1->5B 命中n1 desc select * from t100 where n1 = 2 and n3 = "a"; #n1-5B 命中n1,沒有命中n3 #index(a,b,c)-> a,ab,abc 建立了三組索引,符合最字首原則,第一個欄位必須存在才能觸發
-
事務處理的四項特徵 ACID
-
A:原子性
- 同一個事務中執行多條sql語句,要麼全部成功,要麼直接回滾,作為一個完整的整體,不能再繼續分隔的最小個體
-
C:一致性
- a,i,d 都是為了保證資料的一致性才提出來的,比如約束,鍵在插入資料時,必須按照要求插入,保證規則上的一致性;
- 上升到事務中,如果出現意外導致資料不一致,例如髒讀,幻讀,不可重讀,最終要保證資料是一致的
- 上升到主從資料庫,主資料庫增刪改,從資料也要進行同步改變,保證資料的一致性
-
I:隔離性
- lock + isolation鎖,來處理事務的隔離級別
- 一個事務和另外一個事務工作過程中彼此獨立隔離
-
D:永續性
- 把資料寫到磁碟上,保證資料持久化儲存不丟失
-
隔離性:隔離級別
+ 髒讀:沒提交的資料被讀出來了 + 不可重讀:前後多次讀書,結果資料內容不一樣(同一個會話裡,在不修改的情況下,永遠只看到同樣的一份資料) + 幻讀:前後多次讀取,結果資料的總量不一樣
- RU(READ-UNCOMMITTED):讀未提交:髒讀,不可重讀,幻讀
- RC (READ-COMMITTED):讀已提交:防止髒讀,會出現不可重讀和幻讀
- RR(REPEATABLE-READ):可重複讀:防止髒讀,不可重讀,可能會出現幻讀
- SR (SERIALIZABLE):可序列化:防止一切(但是會把非同步併發的程式變成同步程式,不能併發,效能差)
- 查詢當前mysql的隔離級別(預設是RR)
select @@ tx_isolation;
-
查詢當前是否自動提交資料
select @@ autocommit;
-
修改mysql配置檔案
D:\MYSQL5.7\mysql-5.7.25-winx64\my.ini #系統預設的隔離級別(REPEATABLE-READ) transaction_isolation = READ-UNCOMMITTED #防止系統自動提交資料 autocommit = 0 #重啟mysql net stop mysql net start mysql
-
髒讀
- READ-UNCOMMITTED
- 先去調整設定,重啟mysql;嘗試在一個窗口裡通過事務,更改一條資料,開啟另外一條視窗嘗試讀取,會出現問題
-
不可重複讀
#視窗1 begin; update t1 set k1='abc' where id=1 select * from t1; commit; #視窗2 select * from t1;資料也跟著改了是不可重讀
-
幻讀
#視窗1 begin; insert into t1 values(4,'c',50); select * from t1; commit; #視窗2 select * from t1;數量也跟著增加是幻讀
-
通過二次提交commit,可以讓多使用者同步資料;
-
事務應用的技術(瞭解)
- RR級別下,解決不可重讀,使用mvcc技術,生成最新的mysql的系統備份(快照),然後讀取快照
- RR級別下,解決幻讀,gap 間隙鎖 next-lock 下一鍵鎖
-
關於約束的新增和刪除
-
新增、刪除 約束 not null
#alter table 表名 modify 欄位名 型別 alter table t1 modify id int not null alter table t1 nodify id int
-
新增、刪除 unique唯一索引
#alter table 表名 add unique(id) alter table t1 add unique(id) alter table t1 drop index id
-
新增、刪除 primary key
#alter table 表名 add primary key(id) alter table t1 add primary key(id) alter table t1 drop primary key
-
新增、刪除 foreign key 外來鍵(先通過desc表 找到外來鍵的名字,然後再刪)
alter table student1 drop foreign key student1_ibkf_1#刪除 alter table student1 add foreign key(classid) references class(id)#新增