日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Mysql设计层优化整理总结

發(fā)布時(shí)間:2023/12/20 数据库 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mysql设计层优化整理总结 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

設(shè)計(jì)層優(yōu)化主要包括:索引的使用、分表分區(qū)等。

目錄

一、索引

索引的基本概念:

B-tree索引:

hash索引:

使用索引好處:

索引速度快的原因:

索引類型:

索引的數(shù)據(jù)結(jié)構(gòu):

Myisam索引數(shù)據(jù)結(jié)構(gòu):

Myisam主鍵索引數(shù)據(jù)結(jié)構(gòu)原理:

Myisam非主鍵索引數(shù)據(jù)結(jié)構(gòu)原理:

Innodb索引數(shù)據(jù)結(jié)構(gòu):

Innodb主鍵索引數(shù)據(jù)結(jié)構(gòu)原理:

Innodb非主鍵索引數(shù)據(jù)結(jié)構(gòu)原理:

聚簇索引的優(yōu)劣:

索引的業(yè)務(wù)設(shè)計(jì)依據(jù):

創(chuàng)建索引:

1.創(chuàng)建表的同時(shí)創(chuàng)建索引:

2.給已經(jīng)創(chuàng)建過了的表增加索引:

索引簡介:

前綴索引簡介:

前綴索引制作:

全文索引:

舉例使用fulltext全文索引:

復(fù)合索引:

刪除索引:

1.刪除非主鍵索引(唯一、普通、全文、復(fù)合索引)

2.刪除主鍵索引

主鍵和auto_increment屬性的設(shè)置順序:

索引覆蓋:

索引使用原則:

2.1左原則:

2.2對于左前綴不易區(qū)分的列,建立索引的技巧:

3.復(fù)合索引(2個(gè)字段)

4.or原則

btree索引的常見誤區(qū):

1.在where條件用的列上都加上索引:

2.在多列上建立索引后,查詢哪個(gè)列,索引都將發(fā)揮作用:

索引與排序:

重復(fù)索引與冗余索引:

重復(fù)索引:

冗余索引:

索引碎片與維護(hù):

二、分表設(shè)計(jì)

分表設(shè)計(jì)的兩種方式:

1.邏輯分表(分區(qū)):

分區(qū)常用的規(guī)則:

key分表:

hash分表:

range分表:

list分表:

2.分表管理(增加、減少):

刪除分表:

增加分表:

2.物理分表:

3.垂直分表:

垂直分表地制作:


一、索引

索引的基本概念:

索引是數(shù)據(jù)結(jié)構(gòu)+算法,是對數(shù)據(jù)表中一列或多列(字段)的值進(jìn)行排序的一種結(jié)構(gòu),結(jié)構(gòu)支撐一定的算法,可以保證數(shù)據(jù)被快速檢索。

數(shù)據(jù)結(jié)構(gòu):數(shù)據(jù)以一種規(guī)律的、規(guī)則的方式組織在一個(gè)格式里邊。

Mysql的索引數(shù)據(jù)結(jié)構(gòu)都是B+tree(balance平衡查找樹)結(jié)構(gòu),(可以了解相關(guān)的數(shù)據(jù)結(jié)構(gòu)例如B-tree、二叉樹、Binary-tree等)。

B-tree索引:

抽象來看,B-tree結(jié)構(gòu),可理解為”排好序的快速查找結(jié)構(gòu)”。名叫btree索引,用的也是平衡樹,但具體的實(shí)現(xiàn)上, 各引擎稍有不同,比如,嚴(yán)格來講:NDB引擎,使用的是T-tree,Myisam、innodb中默認(rèn)用B-tree索引。

hash索引:

在memory表里,默認(rèn)是hash索引,hash的理論查詢時(shí)間復(fù)雜度為O(1),查找非常高效,但是也不是都用hash索引,原因主要有:

① hash函數(shù)計(jì)算后的結(jié)果,是隨機(jī)的,如果是在磁盤上放置數(shù)據(jù)的話,比如主鍵為id為例,那么隨著id的增長,id對應(yīng)的行會(huì)在磁盤上隨機(jī)放置,越來越不好。

② 無法對范圍查詢進(jìn)行優(yōu)化。

③ 無法利用前綴索引。比如在btree中,Col1列的值“helloworld”,并加上索引,查詢xx=helloword,自然可以利用索引,xx=hello,也可以利用索引. (左前綴索引),但是hash索引不行,因?yàn)閔ash(‘helloword’)和hash(‘hello’)兩者的關(guān)系仍為隨機(jī)。

④ 無法對排序進(jìn)行優(yōu)化。

⑤ 必須回行,也就是說通過索引拿到數(shù)據(jù)位置,必須回到表中取數(shù)據(jù)。

使用索引好處:

可以非常快速定位我們需要找到的信息。

在現(xiàn)實(shí)生活中有許多地方使用到索引,例如:公交車站牌、書的目錄、辦公樓指示牌、查詢漢字所在頁碼等。

索引速度快的原因:

數(shù)據(jù)表全部“字段”都可以做索引。

在沒有索引的時(shí)候,sql語句查詢會(huì)遍歷全部的記錄信息,找到與條件相符合的。

在有索引的時(shí)候是精準(zhǔn)定位指定的記錄信息,sql語句做數(shù)據(jù)查詢的時(shí)候,要通過索引做條件,在索引里邊可以通過算法快速、準(zhǔn)確地獲得記錄索引字段及字段對應(yīng)的物理地址,再通過物理地址去數(shù)據(jù)表中獲得記錄的詳細(xì)信息。

索引類型:

① 主鍵索引(值不重復(fù),auto_increment自增特性)

② 唯一索引(字段內(nèi)容不能重復(fù))

③ 普通索引

④ 全文索引(適合給文章字段設(shè)置)

⑤ 復(fù)合索引

索引的數(shù)據(jù)結(jié)構(gòu):

Myisam索引數(shù)據(jù)結(jié)構(gòu):

Myisam的數(shù)據(jù)和索引是分離的,數(shù)據(jù)結(jié)構(gòu)為“非聚集型”,如下圖:

myisam中,主索引和次索引,都指向物理行(磁盤位置)。

Myisam主鍵索引數(shù)據(jù)結(jié)構(gòu)原理:

數(shù)據(jù)表有3個(gè)字段:Col1、Col2、Col3,其中Col1是主鍵:

節(jié)點(diǎn):根節(jié)點(diǎn)、分支節(jié)點(diǎn)、葉子節(jié)點(diǎn),索引字段內(nèi)容根據(jù)算法存儲(chǔ)在各個(gè)節(jié)點(diǎn)中。

葉子節(jié)點(diǎn):字段內(nèi)容+記錄物理地址,物理地址與數(shù)據(jù)記錄的物理地址一一對應(yīng)。

空白指針:記錄著下個(gè)節(jié)點(diǎn)的位置,通過算法尋找、指引到下個(gè)節(jié)點(diǎn)。

高度:索引結(jié)構(gòu)從上到下的層數(shù),高度不要過高或過低,最好趨向“正三角形”,有利于數(shù)據(jù)快速查找。

寬度:每層索引從左到右節(jié)點(diǎn)的數(shù)量。

Myisam(主鍵)索引:

索引字段內(nèi)容 --------> 記錄物理地址--------> 具體記錄信息

Myisam非主鍵索引數(shù)據(jù)結(jié)構(gòu)原理:

非主鍵索引的原理與主鍵索引基本一致:

索引和數(shù)據(jù)部分都是分離的,它們通過“物理地址”進(jìn)行聯(lián)系。

Innodb索引數(shù)據(jù)結(jié)構(gòu):

Innodb索引結(jié)構(gòu)稱為“聚合型”,“索引”和”數(shù)據(jù)”是合并在一個(gè)文件里邊的。

innodb的主索引文件上直接存放該行數(shù)據(jù),稱為聚簇索引,次索引指向?qū)χ麈I的引用。

Innodb主鍵索引數(shù)據(jù)結(jié)構(gòu)原理:

主鍵索引既存儲(chǔ)索引值,又在葉子中存儲(chǔ)行的數(shù)據(jù)。像innodb中,主鍵的索引結(jié)構(gòu)中,既存儲(chǔ)了主鍵值,又存儲(chǔ)了行數(shù)據(jù),這種結(jié)構(gòu)稱為“聚簇索引”。

Innodb(主鍵)索引:

索引字段內(nèi)容 --------> 直接對應(yīng)記錄信息

這個(gè)表如果沒有主鍵,則會(huì)unique key做主鍵 ,如果又沒有unique key,則系統(tǒng)生成一個(gè)內(nèi)部的rowid做主鍵。

Innodb非主鍵索引數(shù)據(jù)結(jié)構(gòu)原理:

Innodb(非主鍵)索引:

索引字段內(nèi)容 ---> 記錄主鍵id值 --->(主鍵索引)---> 記錄信息

innodb索引里邊沒有物理地址,非主鍵索引需要借助主鍵索引找到數(shù)據(jù)記錄,所以:

非主鍵索引-->主鍵索引-->數(shù)據(jù)記錄

聚簇索引的優(yōu)劣:

優(yōu)勢:根據(jù)主鍵查詢條目比較少時(shí),不用回行(數(shù)據(jù)就在主鍵節(jié)點(diǎn)下)。

劣勢:如果碰到不規(guī)則數(shù)據(jù)插入時(shí),造成頻繁的頁分裂。

因此聚簇索引應(yīng)注意的點(diǎn):

聚簇索引的主鍵值,應(yīng)盡量是連續(xù)增長的值,而不是要是隨機(jī)值 (不要用隨機(jī)字符串或UUID) ,否則會(huì)造成大量的頁分裂與頁移動(dòng)。

索引的業(yè)務(wù)設(shè)計(jì)依據(jù):

1.頻繁使用的字段設(shè)置索引:

sql語句中,被頻繁用在where和order等條件里的字段適合用來創(chuàng)建索引。數(shù)據(jù)表創(chuàng)建完畢,預(yù)估哪些字段會(huì)被經(jīng)常使用,可以給其創(chuàng)建索引。

2.執(zhí)行時(shí)間長的sql語句考慮設(shè)計(jì)索引:

可以利用“慢查詢?nèi)罩尽笔占@樣的sql語句并優(yōu)化設(shè)計(jì)索引。

3.字段內(nèi)容足夠花樣化,可以考慮設(shè)計(jì)索引:

例如類似性別字段不適合做索引,因?yàn)樗膬?nèi)容取值太少。

4.查詢出來的記錄條數(shù)比較少的時(shí)候可以使用索引:

例如,數(shù)據(jù)表總共有100萬的記錄信息

select * from 表名?where id > 5;? //不會(huì)使用索引,記錄范圍大

select * from 表名?where?id < 5;?? //會(huì)使用索引

5.sql語句里邊有in條件,有時(shí)候可以給in條件的字段設(shè)計(jì)索引:

where?id in (13,33,39)

6.兩個(gè)表通過“外鍵”進(jìn)行連接,該外鍵可以為之創(chuàng)建索引:

創(chuàng)建索引:

1.創(chuàng)建表的同時(shí)創(chuàng)建索引:

create table 表名(

...

???????? primary key (字段),

???????? unique key? [索引名稱]? (字段),

???????? key?[索引名稱]? (字段),

???????? fulltext key?? [索引名稱]? (字段)

)

除了主鍵索引,其他索引設(shè)置的同時(shí)可以給其起一個(gè)“索引名稱”,名稱不設(shè)置的話會(huì)與該索引字段名稱一致,如果索引名稱疊加(重復(fù))則會(huì)自動(dòng)額外設(shè)置序號。

索引創(chuàng)建完畢后查看創(chuàng)建表的SQL語句為:

2.給已經(jīng)創(chuàng)建過了的表增加索引:

alter table 表名 add primary key (字段);

alter table 表名 add unique key ?[索引名稱]? (字段);

alter table 表名 add key? [索引名稱]? (字段);

alter table 表名 add fulltext key? [索引名稱]? (字段);

測試:

首先創(chuàng)建一個(gè)沒有任何索引的數(shù)據(jù)表,也不要給id設(shè)置auto_increment屬性:

然后給它設(shè)置索引:

查看索引設(shè)置的效果:

索引簡介:

前綴索引簡介:

索引長度直接影響索引文件的大小,影響增刪改的速度,并間接影響查詢速度(占用內(nèi)存多)。前綴索引是通過字段前N位創(chuàng)建的索引。

如果一個(gè)字段內(nèi)容的前邊的n位信息已經(jīng)足夠標(biāo)識當(dāng)前的字段內(nèi)容,就可以把字段的前N位獲得出來并創(chuàng)建索引,該索引占據(jù)更空間更小、運(yùn)行速度更快。

前綴索引制作:

制作前綴索引語法:

alter table? 表名? add?key? (字段(前n位位數(shù))) ?;

獲取制作前綴索引的N的信息:

針對列中的值,從左往右截取部分,來建索引:

① 截的越短, 重復(fù)度越高,區(qū)分度越小, 索引效果越不好

② 截的越長, 重復(fù)度越低,區(qū)分度越高, 索引效果越好,但帶來的影響也越大--增刪改變慢,并間影響查詢速度.

③ 去除字段重復(fù)內(nèi)容并計(jì)算總數(shù)目。

④ 取字段的前(n)1、2、3.....位不重復(fù)的信息并計(jì)算總數(shù)目,n從1開始不斷累加,直到總數(shù)目 與 ①計(jì)算的總數(shù)目相等,此時(shí)N就是我們設(shè)計(jì)前綴索引的數(shù)字N信息。

所以, 我們要在區(qū)分度 + 長度?兩者上取得一個(gè)平衡:

慣用手法是截取不同長度并測試其區(qū)分度:

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)

對于一般的系統(tǒng)應(yīng)用來說,區(qū)別度能達(dá)到0.1,索引的性能就可以接受。

全文索引:

其他索引是把字段的內(nèi)容作為一個(gè)整體進(jìn)行索引設(shè)計(jì),而全文索引會(huì)把文章的各個(gè)關(guān)鍵單詞獲得出來,制作為索引內(nèi)容。Mysql5.6.4之前只有Myisam支持全文索引,之后 Myisam和Innodb都支持,類似我們有一篇作文,把作文中的一些關(guān)鍵字給獲取出來當(dāng)成是索引內(nèi)容。

目前Mysql中只有英文支持全文索引,要使用支持中文的全文索引一般都是借助第三方軟件sphinx,一般使用全文索引也不使用Mysql本身的。

注意:

索引字段類型必須為varchar或char或text類型。

舉例使用fulltext全文索引:

創(chuàng)建表并插入測試語句:

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字段創(chuàng)建全文索引:

alter table articles add fulltext key (title);

查看創(chuàng)建好的全文索引:

全文索引使用語法規(guī)則:

正確:

select * from articles where? match(字段)? against(模糊內(nèi)容);? 不正確:

select * from articles where 字段? like ‘%模糊內(nèi)容%’;

mysql本身的全文索引在做模糊查詢的時(shí)候會(huì)有“自身的考慮”,把一些不常見的特殊內(nèi)容給設(shè)計(jì)為索引內(nèi)容,一些生活等常見用語(what where? how等等)就不會(huì)設(shè)計(jì)為索引內(nèi)容。

因此,例如下邊的4次查詢,只有一次是成功的:

復(fù)合索引:

多列索引的考慮因素一般是列的查詢頻率以及列的區(qū)分度:

以ecshop商城為例,goods表中的cat_id,brand_id做多列索引,從區(qū)分度看,brand_id區(qū)分度更高:

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)

但從實(shí)際業(yè)務(wù)業(yè)務(wù)看,客戶一般先選大分類再選小分類最后是品牌。最終選擇index(cat_id,brand_id)來建立索引。

設(shè)置復(fù)合索引:

[primary/unique] key? [索引名稱]? (字段1,字段2,字段3...)

多個(gè)字段組合設(shè)置索引,主鍵、唯一、普通索引的都可以設(shè)置為復(fù)合索引,如果不指明索引名稱,就把索引的第一個(gè)字段獲得出來當(dāng)做索引名稱使用。

給數(shù)據(jù)表的name和age字段設(shè)置為“復(fù)合索引”:

查看創(chuàng)建索引的結(jié)果:

測試:

現(xiàn)在再給name做一個(gè)唯一索引,為了讓復(fù)合索引的name名稱與普通索引的name名稱起沖突,我們不設(shè)置索引名稱。

結(jié)果沒有沖突,系統(tǒng)把第二個(gè)name設(shè)置了一個(gè)“_2”的序號。

刪除索引:

1.刪除非主鍵索引(唯一、普通、全文、復(fù)合索引)

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屬性的設(shè)置順序:

①設(shè)置:先主鍵、再auto_increment。

②刪除:先auto_increment、再主鍵。

在auto_increment存在的情形下刪除主鍵,系統(tǒng)會(huì)報(bào)錯(cuò):

索引覆蓋:

索引覆蓋是指如果查詢的列恰好是索引的一部分,那么查詢只需要在索引文件上進(jìn)行,不需要回行到磁盤再找數(shù)據(jù)。這種查詢速度就非常快,稱為”索引覆蓋”。

例如:

1.推斷出是innodb引擎,物理行在葉子上,如果是mysam的話,物理行在磁盤上,查找不會(huì)這么慢,那應(yīng)該不會(huì)出現(xiàn)這個(gè)問題。

2.有比較長的字段列,塊比較多,id主鍵是聚簇索引,導(dǎo)致沿id查找時(shí)要跨許多小塊。

3.id與ver是聯(lián)合索引,且發(fā)生了索引覆蓋。

看上面的sql語句,沒有使用where、也沒有使用order,只有ename的復(fù)合索引可用,并且查詢的字段(ename,deptno)與ename復(fù)合索引字段(ename,deptno)完全一致,此時(shí)就把當(dāng)前使用索引的情形稱為是“索引覆蓋”,也可以稱為“黃金索引”,在索引里邊就已經(jīng)可以獲得需要的信息(不需要去數(shù)據(jù)表里邊做二次記錄查詢了)。

索引使用原則:

1.字段獨(dú)立原則:

2.1左原則:

例如“l(fā)ike”模糊查詢,左邊內(nèi)容固定,右邊匹配模糊內(nèi)容的模式就是——左原則。

模糊查詢:like

%:匹配多個(gè)模糊內(nèi)容。

_:匹配一個(gè)模糊內(nèi)容。

例如符合“左原則”情況:

like? '北京%'?? //“北京”內(nèi)容右邊出現(xiàn)多個(gè)模糊內(nèi)容

like? '北京_'?? //“北京”內(nèi)容右邊只出現(xiàn)一個(gè)模糊內(nèi)容

例如不符合左原則情況:

like? '%北京%'

like? '_北京_'

like? '%北京'

2.2對于左前綴不易區(qū)分的列,建立索引的技巧:

例如url列:

http://www.baidu.com

http://www.zixue.it

列的前11個(gè)字符都是一樣的,不易區(qū)分,此時(shí)可以用以下兩個(gè)辦法來解決:

①把列內(nèi)容倒過來存儲(chǔ),并建立索引:

Moc.udiab.www//:ptth

Ti.euxiz.www//://ptth

這樣左前綴區(qū)分度大。

②偽hash索引效果:

同時(shí)存 url_hash列

3.復(fù)合索引(2個(gè)字段)

①第一個(gè)字段作為條件 ,有索引。

②全部字段都作為條件,不管前后順序,有索引。

③單獨(dú)使用其他字段(復(fù)合索引的非第一個(gè)字段)作為條件,沒有索引。

上圖,deptno本身是一個(gè)普通的索引,但是當(dāng)前情況也沒有用到該索引為什么呢?

因?yàn)槭莇eptno>200的條件獲得數(shù)據(jù)記錄太多了,不會(huì)用到索引要想用到deptno的普通索引,可以把條件設(shè)置獲取的記錄的少一些(例如deptno>20000)。

4.or原則

①or左右條件字段都有索引,則都可以使用。

②or的左右只體現(xiàn)一個(gè)索引字段,則整體都沒有使用。

btree索引的常見誤區(qū):

1.在where條件用的列上都加上索引:

例:

where cat_id=3 and price>100

誤:cat_id和price上都加上索引。

因?yàn)橹荒苡蒙蟘at_id或price索引其中一個(gè)索引,因?yàn)槭仟?dú)立的索引,同時(shí)只能用上1個(gè)。

2.在多列上建立索引后,查詢哪個(gè)列,索引都將發(fā)揮作用:

誤:多列索引上,索引發(fā)揮作用的話需要滿足左前綴要求。

以 index(a,b,c)為例:

SQL語句

索引是否發(fā)揮作用

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列能發(fā)揮索引,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不能利用

測試:

假設(shè)某一個(gè)表有一個(gè)聯(lián)合索引(c1,c2,c3,c4),以下只能使用該聯(lián)合索引的c1,c2,c3部分的語句為哪個(gè)?

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

創(chuàng)建表并插入數(shù)據(jù):

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? 等價(jià)于 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用到索引的基礎(chǔ)上,c3是排好序的,因此不用額外排序,而c4沒發(fā)揮作用。

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索引,因?yàn)間roup 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,因?yàn)橄扔胏3后用c2分組,導(dǎo)致c2,c3索引沒發(fā)揮作用

????????? ref: const

???????? rows: 1

??????? Extra: Using where; Using temporary; Using filesort

1 row in set (0.00 sec)

這時(shí)候如果把group by的兩個(gè)字段順序換下,則不同:

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確定的基礎(chǔ)上,c2是有序的,c2之下c3是有序的,因此c2,c3發(fā)揮的排序的作用,不會(huì)用到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:

它等價(jià)與select * from t4 where c1=1 and c2=3 and c5=2 order by c3; 因?yàn)閏2的值既是固定的,所以參與排序時(shí)并不考慮。

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,價(jià)格列price,在價(jià)格列上已經(jīng)加了索引,但按價(jià)格查詢還是很慢,問可能是什么原因,怎么解決?

原因:

在實(shí)際場景中,一個(gè)電商網(wǎng)站的商品分類很多,直接在所有商品中,按價(jià)格查商品,是極少的,一般客戶都來到分類下,然后再查價(jià)格。

解決:

去掉單獨(dú)的price列的索引,加 (cat_id,price)復(fù)合索引再使用。?

索引與排序:

排序可能發(fā)生2種情況:

1.對于覆蓋索引,直接在索引上查詢時(shí),就是有順序的:using index。

2.先取出數(shù)據(jù),形成臨時(shí)表做filesort(文件排序,但文件可能在磁盤上,也可能在內(nèi)存中)。

在實(shí)際項(xiàng)目中,目標(biāo)就是取出來的數(shù)據(jù)本身就是有序的!利用索引來排序。

例如:

goods商品表,(cat_id,shop_price)組成聯(lián)合索引,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索引取出的結(jié)果,本身就是有序的。

select goods_id,cat_id,shop_price from goods order by click_count;(// using filesort)用到了文件排序,即取出的結(jié)果需要再次排序。

重復(fù)索引與冗余索引:

重復(fù)索引:

是指在同1個(gè)列(如age),或者順序相同的幾個(gè)列(age,school),建立了多個(gè)索引,這種就是稱之為重復(fù)索引,重復(fù)索引沒有任何幫助,只會(huì)增大索引文件,拖慢更新(增刪改)速度。

冗余索引:

冗余索引是指2個(gè)索引所覆蓋的列有重疊,稱為冗余索引。

比如 x,m,列,加索引index x(x),index xm(x,m)兩索引,兩者的x列重疊了,這種情況稱為冗余索引。甚至可以把 index mx(m,x) 索引也建立,mx與xm也不是重復(fù)的,列的順序不一樣。

索引碎片與維護(hù):

在長期的數(shù)據(jù)更改過程中,索引文件和數(shù)據(jù)文件,都將產(chǎn)生空洞,形成碎片。我們可以通過一個(gè)nop操作(不產(chǎn)生對數(shù)據(jù)實(shí)質(zhì)影響的操作),來修改表。

比如:

表的引擎本來就為innodb ,可以再alter table xxx engine innodb,此時(shí)不會(huì)更改數(shù)據(jù),但是會(huì)整理數(shù)據(jù)。

修復(fù)的專用命令:

optimize table 表名 ,也可以修復(fù)。

注意:

修復(fù)表的數(shù)據(jù)及索引碎片,就會(huì)把所有的數(shù)據(jù)文件重新整理一遍,使之對齊。這個(gè)過程如果表的行數(shù)比較大,也是非常耗費(fèi)資源的操作。所以,不能頻繁的修復(fù)。

如果表的Update操作很頻率,可以按周/月來修復(fù),如果不頻繁可以更長的周期來做修復(fù)。

二、分表設(shè)計(jì)

一個(gè)表里存儲(chǔ)太多的記錄的話會(huì)導(dǎo)致該表的活性大大降低,表的運(yùn)行速度就會(huì)比較慢、效率也比較低,進(jìn)而影響到Mysql數(shù)據(jù)庫的整體性能。這時(shí)候可以采取分表設(shè)計(jì),把記錄信息平均分?jǐn)偨o各個(gè)子表來解決上面的問題。

分表設(shè)計(jì)的兩種方式:

①邏輯分表:

邏輯分表是Mysql本身就支持的技術(shù),使用者不需要考慮記錄在哪個(gè)數(shù)據(jù)表存儲(chǔ)。

②物理分表:

需要程序考慮并記錄在哪個(gè)分表存儲(chǔ)數(shù)據(jù)。

1.邏輯分表(分區(qū)):

通過mysql自帶的的分區(qū)功能,mysql將會(huì)根據(jù)指定的規(guī)則,把數(shù)據(jù)放在不同的表文件上,相當(dāng)于在文件上被拆成了小塊,但是給使用者的界面還是1張表。

分區(qū)常用的規(guī)則:

求余方式的兩種(業(yè)務(wù)聯(lián)系不緊密 ):key和hash

范圍方式的兩種(業(yè)務(wù)聯(lián)系緊密):range和list

key分表:

分表設(shè)計(jì)好后,可以簡單(非嚴(yán)格)理解為通過“求余”算法把記錄寫到各個(gè)分表中。例如下圖分表字段id對分表數(shù)量5,進(jìn)行求余然后填充數(shù)據(jù)記錄信息到對應(yīng)分區(qū)。

create? table 表名(? .....

)engine=Myisam charset=utf8

partition by key(分表字段) partitions 分表數(shù)量;

分表文件在硬盤中存儲(chǔ)的效果:

向分表中寫入數(shù)據(jù):

磁盤文件體現(xiàn)如下:

hash分表:

根據(jù)表達(dá)式或字段的方式進(jìn)行分表設(shè)計(jì)。

create? table 表名(? .....

)engine=Myisam charset=utf8

partition by hash(表達(dá)式/字段) partitions 數(shù)量;

創(chuàng)建分表:

分表文件效果如下:

向分表中insert入數(shù)據(jù):

存儲(chǔ)效果:

range分表:

該分表與業(yè)務(wù)聯(lián)系非常緊密,數(shù)據(jù)可以根據(jù)分表算法嚴(yán)格填充到分表中。分表字段可以是表達(dá)式也可以是獨(dú)立字段。

create? table 表名(? .....

)engine=Myisam charset=utf8

partition by range(表達(dá)式/字段)(

partition 名稱? values?less than (常量),

partition 名稱? values?less than (常量),

?? ...

)

又例如:

按range分區(qū)

?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存儲(chǔ)引擎)需要注意的是,每個(gè)innodb數(shù)據(jù)表有獨(dú)立的數(shù)據(jù)文件,如下圖:

(set global innodb_file_per_table=1;? //設(shè)置innodb獨(dú)立數(shù)據(jù)文件,但是不建議使用)

創(chuàng)建分表的效果:

insert入數(shù)據(jù):

存儲(chǔ)效果:

如果想要插入的數(shù)據(jù)超過了分表的范圍,則報(bào)錯(cuò)禁止寫入:

list分表:

該分表與業(yè)務(wù)聯(lián)系非常緊密,數(shù)據(jù)可以根據(jù)分表算法嚴(yán)格填充到分表中,創(chuàng)建分表的內(nèi)容可以是表達(dá)式也可以是獨(dú)立字段。

create? table 表名(? ?.....

)engine=Myisam charset=utf8

partition by list(表達(dá)式/字段)(

partition 名稱? values?in (列表范圍),

partition 名稱? values?in (列表范圍),

?? ...

)

根據(jù)月份創(chuàng)建季節(jié)分表:

分表效果:

insert入數(shù)據(jù):

存儲(chǔ)效果:

2.分表管理(增加、減少):

刪除分表:

①在key/hash領(lǐng)域不會(huì)造成數(shù)據(jù)丟失(刪除分表后數(shù)據(jù)會(huì)重新整合到剩余的分表去)。

②在range/list領(lǐng)域會(huì)造成數(shù)據(jù)丟失。

求余方式(key/hash):

alter table 表名 coalesce partition 數(shù)量;

范圍方式(range/list):

alter table 表名 drop partition 分表名稱;

①刪除hash類型分表:

剩余一個(gè)分表的時(shí)候的存儲(chǔ)效果:

數(shù)據(jù)不會(huì)變化:

當(dāng)試圖刪除最后一個(gè)分表的時(shí)候:

報(bào)錯(cuò),禁止刪除!

②刪除list類型分表:

刪除對應(yīng)名稱的分表之后,該分表的數(shù)據(jù)也被刪除了。

增加分表:

求余方式(key/hash):

alter table 表名? add? partition partitions? 數(shù)量;

范圍方式(range/list):

alter table 表名 add partition(

?????????? partition 名稱 values less than (常量)

?????????? 或

?????????? partition 名稱 in (n,n,n)

);

①增加hash分表:

增加后一共有6個(gè)分表體現(xiàn):

如上圖,分表增加好后,又把數(shù)據(jù)平均地分配給各個(gè)分表存儲(chǔ)了。

①增加range分表:

效果:

?

2.物理分表:

物理方式分表設(shè)計(jì)是自己手動(dòng)創(chuàng)建多個(gè)數(shù)據(jù)表出來,然后例如PHP等程序需要考慮分表算法:數(shù)據(jù)往哪個(gè)表寫,從哪個(gè)表讀等。

例如下PHP程序?qū)崿F(xiàn)在哪個(gè)分表對數(shù)據(jù)的讀取、修改、刪除:

PHP程序?qū)δ硞€(gè)分表實(shí)現(xiàn)數(shù)據(jù)添加:

3.垂直分表:

水平分表:

是把一個(gè)表的全部記錄信息分別存儲(chǔ)到不同的分表之中。

垂直分表:

是把一個(gè)表的全部字段分別存儲(chǔ)到不同的表里邊。

實(shí)際項(xiàng)目中,一個(gè)數(shù)據(jù)表設(shè)計(jì)好了,里邊有許多字段,但是這些字段有的是經(jīng)常使用的,有的是不常用的。在進(jìn)行正常數(shù)據(jù)表操作的時(shí)候,不常用的字段也會(huì)占據(jù)一定的資源,對整體操作的性能造成一定的干擾、影響。為了減少資源的開銷、提升運(yùn)行效率,就可以把不常用的字段給創(chuàng)建到一個(gè)專門的輔表中去。而這種同一個(gè)業(yè)務(wù)表的不同字段分別存儲(chǔ)到不同數(shù)據(jù)表的過程就是“垂直分表”。

垂直分表地制作:

面把會(huì)員表根據(jù)字段的常用程度而分為兩個(gè)表的過程就是垂直分表:

例如會(huì)員數(shù)據(jù)表有如下字段:

user_id? 登錄名? 密碼? 郵箱? 手機(jī)號碼? 身高? 體重? 性別? 家庭地址? 身份證號碼

以上表,紅色是常用的,藍(lán)色的是不常用的

為了使得常用字段運(yùn)行速度更快、效率更高,把常用字段給調(diào)出來,因此數(shù)據(jù)表做以下垂直分表設(shè)計(jì):

會(huì)員表()user字段:user_id? 登錄名? 密碼? 郵箱? 手機(jī)號碼

會(huì)員表(輔)user_fu字段:user_id? 身高? 體重? 性別? 家庭地址? 身份證號碼

總結(jié)

以上是生活随笔為你收集整理的Mysql设计层优化整理总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。