Mysql數(shù)據(jù)庫優(yōu)化總結(jié)

1.存儲(chǔ)引擎的選擇(MyISAM和Innodb)

存儲(chǔ)引擎:MySQL中的數(shù)據(jù)泳姐、索引以及其他對象是如何存儲(chǔ)的效拭,是一套文件系統(tǒng)的實(shí)現(xiàn)。

5.1之前默認(rèn)存儲(chǔ)引擎是MyISAM,5.1之后默認(rèn)存儲(chǔ)引擎是Innodb胖秒。

功能差異

image

選擇依據(jù)

MyISAM引擎設(shè)計(jì)簡單缎患,數(shù)據(jù)以緊密格式存儲(chǔ),所以某些讀取場景下性能很好阎肝。

如果沒有特別的需求挤渔,使用默認(rèn)的Innodb即可。

MyISAM:以讀寫插入為主的應(yīng)用程序风题,比如博客系統(tǒng)蚂蕴、新聞門戶網(wǎng)站。

Innodb:更新(刪除)操作頻率也高俯邓,或者要保證數(shù)據(jù)的完整性;并發(fā)量高熔号,支持事務(wù)和外鍵保證數(shù)據(jù)完整性稽鞭。比如OA自動(dòng)化辦公系統(tǒng)。

官網(wǎng)建議

官方建議使用Innodb,上面只是告訴大家,數(shù)據(jù)引擎是可以選擇,不過大多數(shù)情況還是不要選為妙

2.字段設(shè)計(jì)

數(shù)據(jù)庫設(shè)計(jì)3大范式

  • 第一范式(確保每列保持原子性)
  • 第二范式(確保表中的每列都和主鍵相關(guān))
  • 第三范式(確保每列都和主鍵列直接相關(guān)引镊,而不是間接相關(guān))

通常建議使用范式化設(shè)計(jì),因?yàn)榉妒交ǔ?huì)使得執(zhí)行操作更快朦蕴。但這并不是絕對的,范式化也是有缺點(diǎn)的,通常需要關(guān)聯(lián)查詢,不僅代價(jià)昂貴,也可能使一些索引策略無效弟头。

所以,我們有時(shí)需要混同范式化和反范式化,比如一個(gè)更新頻率低的字段可以冗余在表中,避免關(guān)聯(lián)查詢

單表字段不宜過多

建議最多30個(gè)以內(nèi)

字段越多,會(huì)導(dǎo)致性能下降,并且增加開發(fā)難度(一眼望不盡的字段,我們這些開發(fā)仔會(huì)頓時(shí)傻掉的)

使用小而簡單的合適數(shù)據(jù)類型

a.字符串類型

固定長度使用char,非定長使用varchar,并分配合適且足夠的空間

char在查詢時(shí),會(huì)把末尾的空格去掉;

b.小數(shù)類型

一般情況可以使用float或double,占用空間小,但存儲(chǔ)可能會(huì)損失精度

decimal可存儲(chǔ)精確小數(shù),存儲(chǔ)財(cái)務(wù)數(shù)據(jù)或經(jīng)度要求高時(shí)使用decimal

c.時(shí)間日期

datetime:

  • 范圍:1001年~9999年
  • 存儲(chǔ):8個(gè)字節(jié)存儲(chǔ),以YYYYMMDDHHMMSS的格式存儲(chǔ)
  • 時(shí)區(qū):與時(shí)區(qū)無關(guān)

timestamp:

  • 范圍:1970年~2038年
  • 存儲(chǔ):4個(gè)字節(jié)存儲(chǔ),存儲(chǔ)以UTC格式保存,與UNIX時(shí)間戳相同
  • 時(shí)區(qū):存儲(chǔ)時(shí)對當(dāng)前的時(shí)區(qū)進(jìn)行轉(zhuǎn)換,檢索時(shí)再轉(zhuǎn)換回當(dāng)前的時(shí)區(qū)

1.通常盡量使用timestamp,因?yàn)樗加每臻g小,并且會(huì)自動(dòng)進(jìn)行時(shí)區(qū)轉(zhuǎn)換,無需關(guān)心地區(qū)時(shí)差

2.datetime和timestamp只能存儲(chǔ)最小顆粒度是秒,可以使用BIGINT類型存儲(chǔ)微秒級別的時(shí)間戳

d.大數(shù)據(jù) blob和text

blob和text是為存儲(chǔ)很大的數(shù)據(jù)的而設(shè)計(jì)的字符串?dāng)?shù)據(jù)類型,但通常建議避免使用

MySQL會(huì)把每個(gè)blob和text當(dāng)做獨(dú)立的對象處理,存儲(chǔ)引擎存儲(chǔ)時(shí)會(huì)做特殊處理,當(dāng)值太大,innoDB使用專門的外部存儲(chǔ)區(qū)域進(jìn)行存儲(chǔ),行內(nèi)存儲(chǔ)指針,然后在外部存儲(chǔ)實(shí)際的值吩抓。這些都會(huì)導(dǎo)致嚴(yán)重的性能開銷

盡量將列設(shè)置為NOT NULL

a.可為NULL的列占用更多的存儲(chǔ)空間

b.可為NULL的列,在使用索引和值比較時(shí),mySQL需要做特殊的處理,損耗一定的性能

建議:通常最好指定列為NOT NULL,除非真的需要存儲(chǔ)NULL值

盡量使用整型做主鍵

a.整數(shù)類型通常是標(biāo)識(shí)列最好的選擇,因?yàn)樗鼈兒芸觳⑶铱梢允褂肁UTO_INCREMENT

b.應(yīng)該避免使用字符串類型作為標(biāo)識(shí)列,因?yàn)樗鼈兒芟目臻g,并且通常比數(shù)字類型慢

c.對于完全"隨機(jī)"的字符串也需要多加注意。例如:MD5(),SHAI()或者UUID()產(chǎn)生的字符串赴恨。這些函數(shù)生成的新值也任意分布在很大空間內(nèi)疹娶,這會(huì)導(dǎo)致INSERT和一些SELECT語句很緩慢

索引

使用索引為什么快

  • 索引相對于數(shù)據(jù)本身,數(shù)據(jù)量小
  • 索引是有序的,可以快速確定數(shù)據(jù)位置
  • InnoDB的表示索引組織表,表數(shù)據(jù)的分布按照主鍵排序

就好比書的目錄,想要找到某一個(gè)內(nèi)容,直接看目錄便可找到對應(yīng)的頁

索引的存儲(chǔ)結(jié)構(gòu)

a.B+樹(具體的結(jié)構(gòu)就不說了,自己去了解)

b.哈希(鍵值對的結(jié)構(gòu))

MySQL中的主鍵索引用的是B+樹結(jié)構(gòu),非主鍵索引可以選擇B+樹或者哈希

通常建議使用B+樹索引

因?yàn)楣K饕秉c(diǎn)比較多:

1.無法用于排序

2.無法用于范圍查詢

3.數(shù)據(jù)量大時(shí),可能會(huì)出現(xiàn)大量哈希碰撞,導(dǎo)致效率低下

索引的類型

按作用分類:

1.主鍵索引:不解釋,都知道

2.普通索引:沒有特殊限制,允許重復(fù)的值

3.唯一索引:不允許有重復(fù)的值,速度比普通索引略快

4.全文索引:用作全文搜索匹配,但基本用不上,只能索引英文單詞,而且操作代價(jià)很大

按數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)分類:

1.聚簇索引

定義:數(shù)據(jù)行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同伦连,一個(gè)表中只能擁有一個(gè)聚集索引雨饺。

主鍵索引是聚簇索引,數(shù)據(jù)的存儲(chǔ)順序是和主鍵的順序相同的

2.非聚簇索引

定義:該索引中索引的邏輯順序與磁盤上行的物理存儲(chǔ)順序不同钳垮,一個(gè)表中可以擁有多個(gè)非聚集索引。

聚簇索引以外的索引都是非聚集索引,細(xì)分為普通索引额港、唯一索引饺窿、全文索引,它們也被稱為二級索引。

如下圖<高性能MySQL> Innodb存儲(chǔ)數(shù)據(jù)和索引的關(guān)系

image

主鍵索引的葉子節(jié)點(diǎn)存儲(chǔ)的是"行指針",直接指向物理文件的數(shù)據(jù)行移斩。

二級索引的葉子結(jié)點(diǎn)存儲(chǔ)的是主鍵值

覆蓋索引:可直接從非主鍵索引直接獲取數(shù)據(jù)無需回表的索引

比如:

假設(shè)t表有一個(gè)(clo1,clo2)的多列索引

select clo1,clo2 from t where clo = 1

那么,使用這條sql查詢,可直接從(clo1,clo2)索引樹中獲取數(shù)據(jù),無需回表查詢

因此我們需要盡可能的在select后只寫必要的查詢字段肚医,以增加索引覆蓋的幾率。

多列索引:使用多個(gè)列作為索引,比如(clo1,clo2)

使用場景:當(dāng)查詢中經(jīng)常使用clo1和clo2作為查詢條件時(shí),可以使用組合索引,這種索引會(huì)比單列索引更快

需要注意的是,多列索引的使用遵循最左索引原則

假設(shè)創(chuàng)建了多列索引index(A,B,C)向瓷,那么其實(shí)相當(dāng)于創(chuàng)建了如下三個(gè)組合索引:

1.index(A,B,C)

2.index(A,B)

3.index(A)

這就是最左索引原則肠套,就是從最左側(cè)開始組合。

索引優(yōu)化

1.索引不是越多越好,索引是需要維護(hù)成本的

2.在連接字段上應(yīng)該建立索引

3.盡量選擇區(qū)分度高的列作為索引,區(qū)分度count(distinct col)/count(*)表示字段不重復(fù)的比例,比例越大掃描的記錄數(shù)越少风罩,狀態(tài)值糠排、性別字段等區(qū)分度低的字段不適合建索引

4.幾個(gè)字段經(jīng)常同時(shí)以AND方式出現(xiàn)在Where子句中,可以建立復(fù)合索引,否則考慮單字段索引

5.把計(jì)算放到業(yè)務(wù)層而不是數(shù)據(jù)庫層

6.如果有 order by、group by 的場景超升,請注意利用索引的有序性入宦。

  • order by 最后的字段是組合索引的一部分,并且放在索引組合順序的最后室琢,避免出現(xiàn) file_sort 的情況乾闰,影響查詢性能。

例如對于語句 where a=? and b=? order by c盈滴,可以建立聯(lián)合索引(a,b,c)涯肩。

order by 最后的字段是組合索引的一部分,并且放在索引組合順序的最后巢钓,避免出現(xiàn) file_sort(外部排序) 的情況病苗,影響查詢性能。

  • 例如對于語句 where a=? and b=? order by c症汹,可以建立聯(lián)合索引(a,b,c)硫朦。
  • 如果索引中有范圍查找,那么索引有序性無法利用背镇,如 WHERE a>10 ORDER BY b;索引(a,b)無法排序咬展。

可能導(dǎo)致無法使用索引的情況

1.is null 和 is not null

2.!= 和 <> (可用in代替)

3."非獨(dú)立列":索引列為表達(dá)式的一部分或是函數(shù)的參數(shù)

例如:

表達(dá)式的一部分:select id from t where id +1 = 5

函數(shù)參數(shù):select id from t where to_days(date_clo) >= 10

4.like查詢以%開頭

5.or (or兩邊的列都建立了索引則可以使用索引)

6.類型不一致

如果列是字符串類型,傳入條件是必須用引號(hào)引起來瞒斩,不然無法使用索引

select * from tb1 where email = 999;

3.Sql優(yōu)化建議

1.首先了解一下sql的執(zhí)行順序,使我們更好的優(yōu)化

(1)FROM:數(shù)據(jù)從硬盤加載到數(shù)據(jù)緩沖區(qū)破婆,方便對接下來的數(shù)據(jù)進(jìn)行操作

(2)ON:join on實(shí)現(xiàn)多表連接查詢,先篩選on的條件,再連接表

(3)JOIN:將join兩邊的表根據(jù)on的條件連接

(4)WHERE:從基表或視圖中選擇滿足條件的元組

(5)GROUP BY:分組,一般和聚合函數(shù)一起使用

(6)HAVING:在元組的基礎(chǔ)上進(jìn)行篩選胸囱,選出符合條件的元組(必須與GROUP BY連用)

(7)SELECT:查詢到得所有元組需要羅列的哪些列

(8)DISTINCT:去重

(9)UNION:將多個(gè)查詢結(jié)果合并

(10)ORDER BY:進(jìn)行相應(yīng)的排序

(11)LIMIT:顯示輸出一條數(shù)據(jù)記錄

  • join on實(shí)現(xiàn)多表連接查詢祷舀,推薦該種方式進(jìn)行多表查詢,不使用子查詢(子查詢會(huì)創(chuàng)建臨時(shí)表,損耗性能)。
  • 避免使用HAVING篩選數(shù)據(jù),而是使用where
  • ORDER BY后面的字段建立索引,利用索引的有序性排序,避免外部排序
  • 如果明確知道只有一條結(jié)果返回蔑鹦,limit 1 能夠提高效率

2.超過三個(gè)表最好不要 join

3.避免 SELECT *夺克,從數(shù)據(jù)庫里讀出越多的數(shù)據(jù),那么查詢就會(huì)變得越慢

4.盡可能的使用 NOT NULL列,可為NULL的列占用額外的空間,且在值比較和使用索引時(shí)需要特殊處理,影響性能

5.用exists嚎朽、not exists和in铺纽、not in相互替代

原則是哪個(gè)的子查詢產(chǎn)生的結(jié)果集小,就選哪個(gè)

select * from t1 where x in (select y from t2)
select * from t1 where exists (select null from t2 where y =x)

IN適合于外表大而內(nèi)表小的情況哟忍;exists適合于外表小而內(nèi)表大的情況

6狡门、使用exists替代distinct

當(dāng)提交一個(gè)包含一對多表信息(比如部門表和雇員表)的查詢時(shí),避免在select子句中使用distinct锅很,一般可以考慮使用exists代替其馏,exists使查詢更為迅速,因?yàn)樽硬樵兊臈l件一旦滿足爆安,立馬返回結(jié)果叛复。

低效寫法:

select distinct dept_no,dept_name from dept d,emp e where d.dept_no=e.dept_no

高效寫法:

select dept_no,dept_name from dept d where exists (select 'x' from emp e where e.dept_no=d.dept_no)

備注:其中x的意思是:因?yàn)閑xists只是看子查詢是否有結(jié)果返回,而不關(guān)心返回的什么內(nèi)容扔仓,因此建議寫一個(gè)常量褐奥,性能較高!

用exists的確可以替代distinct翘簇,不過以上方案僅適用dept_no為唯一主鍵的情況撬码,如果要去掉重復(fù)記錄,需要參照以下寫法:

select * from emp where dept_no exists (select Max(dept_no)) from dept d, emp e where e.dept_no=d.dept_no group by d.dept_no)

7版保、避免隱式數(shù)據(jù)類型轉(zhuǎn)換

隱式數(shù)據(jù)類型轉(zhuǎn)換不能適用索引呜笑,導(dǎo)致全表掃描!t_tablename表的phonenumber字段為varchar類型

以下代碼不符合規(guī)范:

select column1 into i_l_variable1 from t_tablename where phonenumber=18519722169;

應(yīng)編寫如下:

select column1 into i_lvariable1 from t_tablename where phonenumber='18519722169';

8.分段查詢

在一些查詢頁面中彻犁,當(dāng)用戶選擇的時(shí)間范圍過大叫胁,造成查詢緩慢。主要的原因是掃描行數(shù)過多汞幢。這個(gè)時(shí)候可以通過程序曹抬,分段進(jìn)行查詢,循環(huán)遍歷急鳄,將結(jié)果合并處理進(jìn)行展示。

4.Expalin 分析執(zhí)行計(jì)劃

explain顯示了mysql如何使用索引來處理select語句以及連接表堰酿〖埠辏可以幫助選擇更好的索引和寫出更優(yōu)化的查詢語句。

例:

explain SELECT user_name from sys_user where user_id <10

image

該語句連接類型為range,使用主鍵索引進(jìn)行了范圍查詢,估計(jì)掃描了100行數(shù)據(jù)

更多含義詳看下面表格從上可看出

image
image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末触创,一起剝皮案震驚了整個(gè)濱河市坎藐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖岩馍,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碉咆,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛀恩,警方通過查閱死者的電腦和手機(jī)疫铜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來双谆,“玉大人壳咕,你說我怎么就攤上這事⊥绮觯” “怎么了谓厘?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長寸谜。 經(jīng)常有香客問我竟稳,道長,這世上最難降的妖魔是什么熊痴? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任他爸,我火速辦了婚禮,結(jié)果婚禮上愁拭,老公的妹妹穿的比我還像新娘讲逛。我一直安慰自己,他們只是感情好岭埠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布盏混。 她就那樣靜靜地躺著,像睡著了一般惜论。 火紅的嫁衣襯著肌膚如雪许赃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天馆类,我揣著相機(jī)與錄音混聊,去河邊找鬼。 笑死乾巧,一個(gè)胖子當(dāng)著我的面吹牛句喜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沟于,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼咳胃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了旷太?” 一聲冷哼從身側(cè)響起展懈,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤销睁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后存崖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冻记,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年来惧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冗栗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,981評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡违寞,死狀恐怖贞瞒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情趁曼,我是刑警寧澤军浆,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站挡闰,受9級特大地震影響乒融,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜摄悯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一赞季、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奢驯,春花似錦申钩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至管跺,卻和暖如春义黎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背豁跑。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工廉涕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艇拍。 一個(gè)月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓狐蜕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親卸夕。 傳聞我的和親對象是個(gè)殘疾皇子层释,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 數(shù)據(jù)庫的基本是概念名詞解釋: 數(shù)據(jù)庫名詞解釋 元組:可以理解為表的每一行就是一個(gè)元組 候選碼:若關(guān)系中的某一屬性組...
    杰倫哎呦哎呦閱讀 1,111評論 0 6
  • 面試時(shí)遇到的問題:千萬級的mysql數(shù)據(jù)庫如何優(yōu)化?作為一個(gè)剛?cè)腴T的phper,遇到這個(gè)問題時(shí),我還是壓力山大的....
    linfree閱讀 686評論 0 7
  • 數(shù)據(jù)庫開發(fā)規(guī)范1. 數(shù)據(jù)庫命名規(guī)范前綴對象前綴命名: 前綴命名一般用小寫表的前綴: 業(yè)務(wù)模塊組名前綴存儲(chǔ)過程前綴:...
    PowerYangSoft閱讀 2,457評論 0 8
  • 聲明:本文為學(xué)習(xí)總結(jié)篇娇哆,來自一篇比較老的文章,文中的數(shù)據(jù)結(jié)構(gòu)、算法原理講解的通俗易懂碍讨,透徹治力,值得反復(fù)閱讀。原文出處...
    Vechace閱讀 1,969評論 1 33
  • 回顧 字段類型(列類型):數(shù)值型勃黍,時(shí)間日期型和字符串類型 數(shù)值型:整型和小數(shù)型(浮點(diǎn)型和定點(diǎn)型) 時(shí)間日期型:da...
    翊溪閱讀 947評論 0 0