Mysql设计层优化整理总结
設計層優化主要包括:索引的使用、分表分區等。
目錄
一、索引
索引的基本概念:
B-tree索引:
hash索引:
使用索引好處:
索引速度快的原因:
索引類型:
索引的數據結構:
Myisam索引數據結構:
Myisam主鍵索引數據結構原理:
Myisam非主鍵索引數據結構原理:
Innodb索引數據結構:
Innodb主鍵索引數據結構原理:
Innodb非主鍵索引數據結構原理:
聚簇索引的優劣:
索引的業務設計依據:
創建索引:
1.創建表的同時創建索引:
2.給已經創建過了的表增加索引:
索引簡介:
前綴索引簡介:
前綴索引制作:
全文索引:
舉例使用fulltext全文索引:
復合索引:
刪除索引:
1.刪除非主鍵索引(唯一、普通、全文、復合索引)
2.刪除主鍵索引
主鍵和auto_increment屬性的設置順序:
索引覆蓋:
索引使用原則:
2.1左原則:
2.2對于左前綴不易區分的列,建立索引的技巧:
3.復合索引(2個字段)
4.or原則
btree索引的常見誤區:
1.在where條件用的列上都加上索引:
2.在多列上建立索引后,查詢哪個列,索引都將發揮作用:
索引與排序:
重復索引與冗余索引:
重復索引:
冗余索引:
索引碎片與維護:
二、分表設計
分表設計的兩種方式:
1.邏輯分表(分區):
分區常用的規則:
key分表:
hash分表:
range分表:
list分表:
2.分表管理(增加、減少):
刪除分表:
增加分表:
2.物理分表:
3.垂直分表:
垂直分表地制作:
一、索引
索引的基本概念:
索引是數據結構+算法,是對數據表中一列或多列(字段)的值進行排序的一種結構,結構支撐一定的算法,可以保證數據被快速檢索。
數據結構:數據以一種規律的、規則的方式組織在一個格式里邊。
Mysql的索引數據結構都是B+tree(balance平衡查找樹)結構,(可以了解相關的數據結構例如B-tree、二叉樹、Binary-tree等)。
B-tree索引:
抽象來看,B-tree結構,可理解為”排好序的快速查找結構”。名叫btree索引,用的也是平衡樹,但具體的實現上, 各引擎稍有不同,比如,嚴格來講:NDB引擎,使用的是T-tree,Myisam、innodb中默認用B-tree索引。
hash索引:
在memory表里,默認是hash索引,hash的理論查詢時間復雜度為O(1),查找非常高效,但是也不是都用hash索引,原因主要有:
① hash函數計算后的結果,是隨機的,如果是在磁盤上放置數據的話,比如主鍵為id為例,那么隨著id的增長,id對應的行會在磁盤上隨機放置,越來越不好。
② 無法對范圍查詢進行優化。
③ 無法利用前綴索引。比如在btree中,Col1列的值“helloworld”,并加上索引,查詢xx=helloword,自然可以利用索引,xx=hello,也可以利用索引. (左前綴索引),但是hash索引不行,因為hash(‘helloword’)和hash(‘hello’)兩者的關系仍為隨機。
④ 無法對排序進行優化。
⑤ 必須回行,也就是說通過索引拿到數據位置,必須回到表中取數據。
使用索引好處:
可以非常快速定位我們需要找到的信息。
在現實生活中有許多地方使用到索引,例如:公交車站牌、書的目錄、辦公樓指示牌、查詢漢字所在頁碼等。
索引速度快的原因:
數據表全部“字段”都可以做索引。
在沒有索引的時候,sql語句查詢會遍歷全部的記錄信息,找到與條件相符合的。
在有索引的時候是精準定位指定的記錄信息,sql語句做數據查詢的時候,要通過索引做條件,在索引里邊可以通過算法快速、準確地獲得記錄索引字段及字段對應的物理地址,再通過物理地址去數據表中獲得記錄的詳細信息。
索引類型:
① 主鍵索引(值不重復,auto_increment自增特性)
② 唯一索引(字段內容不能重復)
③ 普通索引
④ 全文索引(適合給文章字段設置)
⑤ 復合索引
索引的數據結構:
Myisam索引數據結構:
Myisam的數據和索引是分離的,數據結構為“非聚集型”,如下圖:
myisam中,主索引和次索引,都指向物理行(磁盤位置)。
Myisam主鍵索引數據結構原理:
數據表有3個字段:Col1、Col2、Col3,其中Col1是主鍵:
節點:根節點、分支節點、葉子節點,索引字段內容根據算法存儲在各個節點中。
葉子節點:字段內容+記錄物理地址,物理地址與數據記錄的物理地址一一對應。
空白指針:記錄著下個節點的位置,通過算法尋找、指引到下個節點。
高度:索引結構從上到下的層數,高度不要過高或過低,最好趨向“正三角形”,有利于數據快速查找。
寬度:每層索引從左到右節點的數量。
Myisam(主鍵)索引:
索引字段內容 --------> 記錄物理地址--------> 具體記錄信息
Myisam非主鍵索引數據結構原理:
非主鍵索引的原理與主鍵索引基本一致:
索引和數據部分都是分離的,它們通過“物理地址”進行聯系。
Innodb索引數據結構:
Innodb索引結構稱為“聚合型”,“索引”和”數據”是合并在一個文件里邊的。
innodb的主索引文件上直接存放該行數據,稱為聚簇索引,次索引指向對主鍵的引用。
Innodb主鍵索引數據結構原理:
主鍵索引既存儲索引值,又在葉子中存儲行的數據。像innodb中,主鍵的索引結構中,既存儲了主鍵值,又存儲了行數據,這種結構稱為“聚簇索引”。
Innodb(主鍵)索引:
索引字段內容 --------> 直接對應記錄信息
這個表如果沒有主鍵,則會unique key做主鍵 ,如果又沒有unique key,則系統生成一個內部的rowid做主鍵。
Innodb非主鍵索引數據結構原理:
Innodb(非主鍵)索引:
索引字段內容 ---> 記錄主鍵id值 --->(主鍵索引)---> 記錄信息
innodb索引里邊沒有物理地址,非主鍵索引需要借助主鍵索引找到數據記錄,所以:
非主鍵索引-->主鍵索引-->數據記錄
聚簇索引的優劣:
優勢:根據主鍵查詢條目比較少時,不用回行(數據就在主鍵節點下)。
劣勢:如果碰到不規則數據插入時,造成頻繁的頁分裂。
因此聚簇索引應注意的點:
聚簇索引的主鍵值,應盡量是連續增長的值,而不是要是隨機值 (不要用隨機字符串或UUID) ,否則會造成大量的頁分裂與頁移動。
索引的業務設計依據:
1.頻繁使用的字段設置索引:
sql語句中,被頻繁用在where和order等條件里的字段適合用來創建索引。數據表創建完畢,預估哪些字段會被經常使用,可以給其創建索引。
2.執行時間長的sql語句考慮設計索引:
可以利用“慢查詢日志”收集這樣的sql語句并優化設計索引。
3.字段內容足夠花樣化,可以考慮設計索引:
例如類似性別字段不適合做索引,因為它的內容取值太少。
4.查詢出來的記錄條數比較少的時候可以使用索引:
例如,數據表總共有100萬的記錄信息
select * from 表名?where id > 5;? //不會使用索引,記錄范圍大
select * from 表名?where?id < 5;?? //會使用索引
5.sql語句里邊有in條件,有時候可以給in條件的字段設計索引:
where?id in (13,33,39)
6.兩個表通過“外鍵”進行連接,該外鍵可以為之創建索引:
創建索引:
1.創建表的同時創建索引:
create table 表名(
...
???????? primary key (字段),
???????? unique key? [索引名稱]? (字段),
???????? key?[索引名稱]? (字段),
???????? fulltext key?? [索引名稱]? (字段)
)
除了主鍵索引,其他索引設置的同時可以給其起一個“索引名稱”,名稱不設置的話會與該索引字段名稱一致,如果索引名稱疊加(重復)則會自動額外設置序號。
索引創建完畢后查看創建表的SQL語句為:
2.給已經創建過了的表增加索引:
alter table 表名 add primary key (字段);
alter table 表名 add unique key ?[索引名稱]? (字段);
alter table 表名 add key? [索引名稱]? (字段);
alter table 表名 add fulltext key? [索引名稱]? (字段);
測試:
首先創建一個沒有任何索引的數據表,也不要給id設置auto_increment屬性:
然后給它設置索引:
查看索引設置的效果:
索引簡介:
前綴索引簡介:
索引長度直接影響索引文件的大小,影響增刪改的速度,并間接影響查詢速度(占用內存多)。前綴索引是通過字段前N位創建的索引。
如果一個字段內容的前邊的n位信息已經足夠標識當前的字段內容,就可以把字段的前N位獲得出來并創建索引,該索引占據更空間更小、運行速度更快。
前綴索引制作:
制作前綴索引語法:
alter table? 表名? add?key? (字段(前n位位數)) ?;
獲取制作前綴索引的N的信息:
針對列中的值,從左往右截取部分,來建索引:
① 截的越短, 重復度越高,區分度越小, 索引效果越不好
② 截的越長, 重復度越低,區分度越高, 索引效果越好,但帶來的影響也越大--增刪改變慢,并間影響查詢速度.
③ 去除字段重復內容并計算總數目。
④ 取字段的前(n)1、2、3.....位不重復的信息并計算總數目,n從1開始不斷累加,直到總數目 與 ①計算的總數目相等,此時N就是我們設計前綴索引的數字N信息。
所以, 我們要在區分度 + 長度?兩者上取得一個平衡:
慣用手法是截取不同長度并測試其區分度:
mysql> select count(distinct left(word,6))/count(*) from dict;
+---------------------------------------+
| count(distinct left(word,6))/count(*) |
+---------------------------------------+
|???????????????????? ???????????0.9992 |
+---------------------------------------+1 row in set (0.30 sec)
對于一般的系統應用來說,區別度能達到0.1,索引的性能就可以接受。
全文索引:
其他索引是把字段的內容作為一個整體進行索引設計,而全文索引會把文章的各個關鍵單詞獲得出來,制作為索引內容。Mysql5.6.4之前只有Myisam支持全文索引,之后 Myisam和Innodb都支持,類似我們有一篇作文,把作文中的一些關鍵字給獲取出來當成是索引內容。
目前Mysql中只有英文支持全文索引,要使用支持中文的全文索引一般都是借助第三方軟件sphinx,一般使用全文索引也不使用Mysql本身的。
注意:
索引字段類型必須為varchar或char或text類型。
舉例使用fulltext全文索引:
創建表并插入測試語句:
CREATE TABLE articles (
?????? id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
?????? title VARCHAR(200),
?????? body TEXT
)engine=myisam charset utf8;
INSERT INTO articles (title,body) VALUES
???? ('MySQL Tutorial','DBMS stands for DataBase ...'),
???? ('How To Use MySQL Well','After you went through a ...'),
???? ('Optimizing MySQL','In this tutorial we will show ...'),
???? ('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'),
???? ('MySQL vs. YourSQL','In the following database comparison ...'),
???? ('MySQL Security','When configured properly, MySQL ...');
給title字段創建全文索引:
alter table articles add fulltext key (title);
查看創建好的全文索引:
全文索引使用語法規則:
正確:
select * from articles where? match(字段)? against(模糊內容);? 不正確:
select * from articles where 字段? like ‘%模糊內容%’;
mysql本身的全文索引在做模糊查詢的時候會有“自身的考慮”,把一些不常見的特殊內容給設計為索引內容,一些生活等常見用語(what where? how等等)就不會設計為索引內容。
因此,例如下邊的4次查詢,只有一次是成功的:
復合索引:
多列索引的考慮因素一般是列的查詢頻率以及列的區分度:
以ecshop商城為例,goods表中的cat_id,brand_id做多列索引,從區分度看,brand_id區分度更高:
mysql>select count(distinct cat_id) / count(*) from ?goods;
+-----------------------------------+
| count(distinct cat_id) / count(*) |
+-----------------------------------+
|??????????????????????????? 0.2903 |
+-----------------------------------+
1 row in set (0.00 sec)
mysql>select count(distinct brand_id) / count(*) from ?goods;
+-------------------------------------+
| count(distinct brand_id) / count(*) |
+-------------------------------------+
|????????????????????????????? 0.3871 |
+-------------------------------------+
1 row in set (0.00 sec)
但從實際業務業務看,客戶一般先選大分類再選小分類最后是品牌。最終選擇index(cat_id,brand_id)來建立索引。
設置復合索引:
[primary/unique] key? [索引名稱]? (字段1,字段2,字段3...)
多個字段組合設置索引,主鍵、唯一、普通索引的都可以設置為復合索引,如果不指明索引名稱,就把索引的第一個字段獲得出來當做索引名稱使用。
給數據表的name和age字段設置為“復合索引”:
查看創建索引的結果:
測試:
現在再給name做一個唯一索引,為了讓復合索引的name名稱與普通索引的name名稱起沖突,我們不設置索引名稱。
結果沒有沖突,系統把第二個name設置了一個“_2”的序號。
刪除索引:
1.刪除非主鍵索引(唯一、普通、全文、復合索引)
alter? table? 表名 drop? key? 索引名稱;
2.刪除主鍵索引
alter table? 表名 drop primary key;
注:如果有“auto_increment”屬性,要先除去“auto_increment”屬性。
語句如下:
給id字段添加auto_increment屬性:
alter table student4 modify id int unsigned not null auto_increment comment '主鍵id';
給id字段去除auto_increment屬性:
alter table student4 modify id int unsigned not null comment '主鍵id';
刪除主鍵:
主鍵和auto_increment屬性的設置順序:
①設置:先主鍵、再auto_increment。
②刪除:先auto_increment、再主鍵。
在auto_increment存在的情形下刪除主鍵,系統會報錯:
索引覆蓋:
索引覆蓋是指如果查詢的列恰好是索引的一部分,那么查詢只需要在索引文件上進行,不需要回行到磁盤再找數據。這種查詢速度就非常快,稱為”索引覆蓋”。
例如:
1.推斷出是innodb引擎,物理行在葉子上,如果是mysam的話,物理行在磁盤上,查找不會這么慢,那應該不會出現這個問題。
2.有比較長的字段列,塊比較多,id主鍵是聚簇索引,導致沿id查找時要跨許多小塊。
3.id與ver是聯合索引,且發生了索引覆蓋。
看上面的sql語句,沒有使用where、也沒有使用order,只有ename的復合索引可用,并且查詢的字段(ename,deptno)與ename復合索引字段(ename,deptno)完全一致,此時就把當前使用索引的情形稱為是“索引覆蓋”,也可以稱為“黃金索引”,在索引里邊就已經可以獲得需要的信息(不需要去數據表里邊做二次記錄查詢了)。
索引使用原則:
1.字段獨立原則:
2.1左原則:
例如“like”模糊查詢,左邊內容固定,右邊匹配模糊內容的模式就是——左原則。
模糊查詢:like
%:匹配多個模糊內容。
_:匹配一個模糊內容。
例如符合“左原則”情況:
like? '北京%'?? //“北京”內容右邊出現多個模糊內容
like? '北京_'?? //“北京”內容右邊只出現一個模糊內容
例如不符合左原則情況:
like? '%北京%'
like? '_北京_'
like? '%北京'
2.2對于左前綴不易區分的列,建立索引的技巧:
例如url列:
http://www.baidu.com
http://www.zixue.it
列的前11個字符都是一樣的,不易區分,此時可以用以下兩個辦法來解決:
①把列內容倒過來存儲,并建立索引:
Moc.udiab.www//:ptth
Ti.euxiz.www//://ptth
這樣左前綴區分度大。
②偽hash索引效果:
同時存 url_hash列
3.復合索引(2個字段)
①第一個字段作為條件 ,有索引。
②全部字段都作為條件,不管前后順序,有索引。
③單獨使用其他字段(復合索引的非第一個字段)作為條件,沒有索引。
上圖,deptno本身是一個普通的索引,但是當前情況也沒有用到該索引為什么呢?
因為是deptno>200的條件獲得數據記錄太多了,不會用到索引要想用到deptno的普通索引,可以把條件設置獲取的記錄的少一些(例如deptno>20000)。
4.or原則
①or左右條件字段都有索引,則都可以使用。
②or的左右只體現一個索引字段,則整體都沒有使用。
btree索引的常見誤區:
1.在where條件用的列上都加上索引:
例:
where cat_id=3 and price>100
誤:cat_id和price上都加上索引。
因為只能用上cat_id或price索引其中一個索引,因為是獨立的索引,同時只能用上1個。
2.在多列上建立索引后,查詢哪個列,索引都將發揮作用:
誤:多列索引上,索引發揮作用的話需要滿足左前綴要求。
以 index(a,b,c)為例:
| SQL語句 | 索引是否發揮作用 |
| where a=3 | 是,只使用了a列 |
| where a=3 and b=5 | 是,使用了a,b列 |
| where a=3 and b=5 and c=4 | 是,使用了a,b,c |
| where b=3? 或 where c=4 | 否 |
| where a=3 and c=4 | a列能發揮索引,c不能 |
| where a=3 and b>10 and c=7 | a能利用,b能利用,c不能利用 |
| where a=3 and b like ‘xxxx%’ and c=7 | a能利用,b能利用,c不能利用 |
測試:
假設某一個表有一個聯合索引(c1,c2,c3,c4),以下只能使用該聯合索引的c1,c2,c3部分的語句為哪個?
A. where c1=x and c2=x and c4>x and c3=x
B. where c1=x and c2=x and c4=x order by c3
C. where c1=x and c4=x group by c3,c2
D. where c1=x and c5=x order by c2,c3
E. where c1=x and c2=x and c5=? order by c2,c3
創建表并插入數據:
create table t4 (
??? c1 tinyint(1) not null default 0,
??? c2 tinyint(1) not null default 0,
??? c3 tinyint(1) not null default 0,
??? c4 tinyint(1) not null default 0,
??? c5 tinyint(1) not null default 0,
??? index c1234(c1,c2,c3,c4)
);
insert into t4 values (1,3,5,6,7),(2,3,9,8,3),(4,3,2,7,5);
對于A:
c1=x and c2=x and c4>x and c3=x? 等價于 c1=x and c2=x and c3=x and c4>x
因此 c1,c2,c3,c4都能用上。如下:
mysql>explain select * from t4 where c1=1 and c2=2 and c4>3 and c3=3 \G
***************************1. row ***************************
?????? ????id: 1
? select_type: SIMPLE
??????? table: t4
???????? type: range
possible_keys: c1234
????????? key: c1234
????? key_len: 4 #可以看出c1,c2,c3,c4索引都用上
????????? ref: NULL
???????? rows: 1
??????? Extra: Using where
對于B:
select * from t4 where c1=1 and c2=2 and c4=3 order by c3
c1 ,c2索引用上了,在c2用到索引的基礎上,c3是排好序的,因此不用額外排序,而c4沒發揮作用。
mysql>explain select * from t4 where c1=1 and c2=2 and c4=3 order by c3 \G
***************************1. row ***************************
?????????? id: 1
? select_type: SIMPLE
???????table: t4
???????type: ref
possible_keys: c1234
????????? key: c1234
????? key_len: 2
????????? ref: const,const
???????? rows: 1
??????? Extra: Using where
1 row in set (0.00 sec)
mysql>explain select * from t4 where c1=1 and c2=2 and c4=3 order by c5 \G
***************************1. row ***************************
?????????? id: 1
? select_type: SIMPLE
??????? table: t4
???????? type: ref
possible_keys: c1234
????????? key: c1234
????? key_len: 2
????????? ref: const,const
???????? rows: 1
?? ?????Extra: Using where; Using filesort
1 row in set (0.00 sec)
對于 C:
只用到c1索引,因為group by c3,c2的順序無法利用c2,c3索引
mysql>explain select * from t4 where c1=1 and c4=2 group by c3,c2 \G
***************************1. row ***************************
?????????? id: 1
? select_type: SIMPLE
??????? table: t4
???????? type: ref
possible_keys: c1234
????????? key: c1234
????? key_len: 1 #只用到c1,因為先用c3后用c2分組,導致c2,c3索引沒發揮作用
????????? ref: const
???????? rows: 1
??????? Extra: Using where; Using temporary; Using filesort
1 row in set (0.00 sec)
這時候如果把group by的兩個字段順序換下,則不同:
mysql>explain select * from t4 where c1=1 and c4=2 group by c2,c3 \G
***************************1. row ***************************
?????????? id: 1
? select_type: SIMPLE
??????? table: t4
???????? type: ref
possible_keys: c1234
? ????????key: c1234
????? key_len: 1
????????? ref: const
???????? rows: 1
??????? Extra: Using where
1 row in set (0.00 sec)
對于D:
c1確定的基礎上,c2是有序的,c2之下c3是有序的,因此c2,c3發揮的排序的作用,不會用到filesort。
mysql>explain select * from t4 where c1=1 and c5=2 order by c2,c3 \G?
***************************1. row ***************************
?????????? id: 1
? select_type: SIMPLE
??????? table: t4
???????? type: ref
possible_keys: c1234
????????? key: c1234
????? key_len: 1
????????? ref: const
???????? rows: 1
??????? Extra: Using where
1 row in set (0.00 sec)
對于E:
它等價與select * from t4 where c1=1 and c2=3 and c5=2 order by c3; 因為c2的值既是固定的,所以參與排序時并不考慮。
mysql>explain select * from t4 where c1=1 and c2=3 and c5=2 order by c2,c3 \G
***************************1. row ***************************
?????????? id: 1
? select_type: SIMPLE
??????? table: t4
???????? type: ref
possible_keys: c1234
????????? key: c1234
????? key_len: 2
????????? ref: const,const
???????? rows: 1
??????? Extra: Using where
1 row in set (0.00 sec)
一道題:
有商品表,有主鍵goods_id,欄目列cat_id,價格列price,在價格列上已經加了索引,但按價格查詢還是很慢,問可能是什么原因,怎么解決?
原因:
在實際場景中,一個電商網站的商品分類很多,直接在所有商品中,按價格查商品,是極少的,一般客戶都來到分類下,然后再查價格。
解決:
去掉單獨的price列的索引,加 (cat_id,price)復合索引再使用。?
索引與排序:
排序可能發生2種情況:
1.對于覆蓋索引,直接在索引上查詢時,就是有順序的:using index。
2.先取出數據,形成臨時表做filesort(文件排序,但文件可能在磁盤上,也可能在內存中)。
在實際項目中,目標就是取出來的數據本身就是有序的!利用索引來排序。
例如:
goods商品表,(cat_id,shop_price)組成聯合索引,where cat_id=N order by shop_price,可以利用索引來排序。
select goods_id,cat_id,shop_price from goods order by shop_price;(// using where),按照shop_price索引取出的結果,本身就是有序的。
select goods_id,cat_id,shop_price from goods order by click_count;(// using filesort)用到了文件排序,即取出的結果需要再次排序。
重復索引與冗余索引:
重復索引:
是指在同1個列(如age),或者順序相同的幾個列(age,school),建立了多個索引,這種就是稱之為重復索引,重復索引沒有任何幫助,只會增大索引文件,拖慢更新(增刪改)速度。
冗余索引:
冗余索引是指2個索引所覆蓋的列有重疊,稱為冗余索引。
比如 x,m,列,加索引index x(x),index xm(x,m)兩索引,兩者的x列重疊了,這種情況稱為冗余索引。甚至可以把 index mx(m,x) 索引也建立,mx與xm也不是重復的,列的順序不一樣。
索引碎片與維護:
在長期的數據更改過程中,索引文件和數據文件,都將產生空洞,形成碎片。我們可以通過一個nop操作(不產生對數據實質影響的操作),來修改表。
比如:
表的引擎本來就為innodb ,可以再alter table xxx engine innodb,此時不會更改數據,但是會整理數據。
修復的專用命令:
optimize table 表名 ,也可以修復。
注意:
修復表的數據及索引碎片,就會把所有的數據文件重新整理一遍,使之對齊。這個過程如果表的行數比較大,也是非常耗費資源的操作。所以,不能頻繁的修復。
如果表的Update操作很頻率,可以按周/月來修復,如果不頻繁可以更長的周期來做修復。
二、分表設計
一個表里存儲太多的記錄的話會導致該表的活性大大降低,表的運行速度就會比較慢、效率也比較低,進而影響到Mysql數據庫的整體性能。這時候可以采取分表設計,把記錄信息平均分攤給各個子表來解決上面的問題。
分表設計的兩種方式:
①邏輯分表:
邏輯分表是Mysql本身就支持的技術,使用者不需要考慮記錄在哪個數據表存儲。
②物理分表:
需要程序考慮并記錄在哪個分表存儲數據。
1.邏輯分表(分區):
通過mysql自帶的的分區功能,mysql將會根據指定的規則,把數據放在不同的表文件上,相當于在文件上被拆成了小塊,但是給使用者的界面還是1張表。
分區常用的規則:
求余方式的兩種(業務聯系不緊密 ):key和hash
范圍方式的兩種(業務聯系緊密):range和list
key分表:
分表設計好后,可以簡單(非嚴格)理解為通過“求余”算法把記錄寫到各個分表中。例如下圖分表字段id對分表數量5,進行求余然后填充數據記錄信息到對應分區。
create? table 表名(? .....
)engine=Myisam charset=utf8
partition by key(分表字段) partitions 分表數量;
分表文件在硬盤中存儲的效果:
向分表中寫入數據:
磁盤文件體現如下:
hash分表:
根據表達式或字段的方式進行分表設計。
create? table 表名(? .....
)engine=Myisam charset=utf8
partition by hash(表達式/字段) partitions 數量;
創建分表:
分表文件效果如下:
向分表中insert入數據:
存儲效果:
range分表:
該分表與業務聯系非常緊密,數據可以根據分表算法嚴格填充到分表中。分表字段可以是表達式也可以是獨立字段。
create? table 表名(? .....
)engine=Myisam charset=utf8
partition by range(表達式/字段)(
partition 名稱? values?less than (常量),
partition 名稱? values?less than (常量),
?? ...
)
又例如:
按range分區
?create table goods (
?id ?int,
?uname char(10)
?)engine myisam
?partition by range(id) (
?partition p1 values less than (10),
?partition p2 values less than (20),
?partition p3 values less than MAXVALUE
?);
(分表為innodb存儲引擎)需要注意的是,每個innodb數據表有獨立的數據文件,如下圖:
(set global innodb_file_per_table=1;? //設置innodb獨立數據文件,但是不建議使用)
創建分表的效果:
insert入數據:
存儲效果:
如果想要插入的數據超過了分表的范圍,則報錯禁止寫入:
list分表:
該分表與業務聯系非常緊密,數據可以根據分表算法嚴格填充到分表中,創建分表的內容可以是表達式也可以是獨立字段。
create? table 表名(? ?.....
)engine=Myisam charset=utf8
partition by list(表達式/字段)(
partition 名稱? values?in (列表范圍),
partition 名稱? values?in (列表范圍),
?? ...
)
根據月份創建季節分表:
分表效果:
insert入數據:
存儲效果:
2.分表管理(增加、減少):
刪除分表:
①在key/hash領域不會造成數據丟失(刪除分表后數據會重新整合到剩余的分表去)。
②在range/list領域會造成數據丟失。
求余方式(key/hash):
alter table 表名 coalesce partition 數量;
范圍方式(range/list):
alter table 表名 drop partition 分表名稱;
①刪除hash類型分表:
剩余一個分表的時候的存儲效果:
數據不會變化:
當試圖刪除最后一個分表的時候:
報錯,禁止刪除!
②刪除list類型分表:
刪除對應名稱的分表之后,該分表的數據也被刪除了。
增加分表:
求余方式(key/hash):
alter table 表名? add? partition partitions? 數量;
范圍方式(range/list):
alter table 表名 add partition(
?????????? partition 名稱 values less than (常量)
?????????? 或
?????????? partition 名稱 in (n,n,n)
);
①增加hash分表:
增加后一共有6個分表體現:
如上圖,分表增加好后,又把數據平均地分配給各個分表存儲了。
①增加range分表:
效果:
?
2.物理分表:
物理方式分表設計是自己手動創建多個數據表出來,然后例如PHP等程序需要考慮分表算法:數據往哪個表寫,從哪個表讀等。
例如下PHP程序實現在哪個分表對數據的讀取、修改、刪除:
PHP程序對某個分表實現數據添加:
3.垂直分表:
水平分表:
是把一個表的全部記錄信息分別存儲到不同的分表之中。
垂直分表:
是把一個表的全部字段分別存儲到不同的表里邊。
實際項目中,一個數據表設計好了,里邊有許多字段,但是這些字段有的是經常使用的,有的是不常用的。在進行正常數據表操作的時候,不常用的字段也會占據一定的資源,對整體操作的性能造成一定的干擾、影響。為了減少資源的開銷、提升運行效率,就可以把不常用的字段給創建到一個專門的輔表中去。而這種同一個業務表的不同字段分別存儲到不同數據表的過程就是“垂直分表”。
垂直分表地制作:
下面把會員表根據字段的常用程度而分為兩個表的過程就是垂直分表:
例如會員數據表有如下字段:
user_id? 登錄名? 密碼? 郵箱? 手機號碼? 身高? 體重? 性別? 家庭地址? 身份證號碼
以上表,紅色是常用的,藍色的是不常用的
為了使得常用字段運行速度更快、效率更高,把常用字段給調出來,因此數據表做以下垂直分表設計:
會員表(主)user字段:user_id? 登錄名? 密碼? 郵箱? 手機號碼
會員表(輔)user_fu字段:user_id? 身高? 體重? 性別? 家庭地址? 身份證號碼
總結
以上是生活随笔為你收集整理的Mysql设计层优化整理总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python24小时12小时转换_pyt
- 下一篇: SQL2000恢复单MDF数据库过程