工作的這些年發(fā)現(xiàn)一個(gè)比較奇怪的現(xiàn)象就是身邊無論是工作十多年的老兵,還是初級(jí)剛?cè)胄械某绦騿T,在高談闊論技術(shù)和趨勢(shì)的時(shí)候都是人工智能,大數(shù)據(jù),區(qū)塊鏈,各種框架,語(yǔ)言,算法,AI,BI,CI,DI…… 等等,倒是發(fā)現(xiàn)很少有人關(guān)注數(shù)據(jù)庫(kù),不知道是因?yàn)閿?shù)據(jù)庫(kù)感覺太低端還是太低調(diào),總是不容易被人提起
成都創(chuàng)新互聯(lián)公司專注于企業(yè)營(yíng)銷型網(wǎng)站建設(shè)、網(wǎng)站重做改版、青山網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、HTML5、商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為青山等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
技術(shù)就是這樣,不太關(guān)注的地方就不會(huì)重視,越是不被重視的地方,掉進(jìn)坑里的概率就會(huì)越大,所以就在這里給大家簡(jiǎn)單聊聊在使用數(shù)據(jù)庫(kù)過程中有哪些防掉坑指南,也可以對(duì)剛?cè)胄械男∨笥延幸粋€(gè)提醒的作用,萬(wàn)丈高樓平地起,一定要先打好基礎(chǔ)再去考慮上層的建筑,不要舍本逐末
本章主要分以下四個(gè)小節(jié)(預(yù)計(jì)讀完 5 分鐘左右):
很多人在開發(fā)過程中不太關(guān)注數(shù)據(jù)庫(kù),對(duì)于表結(jié)構(gòu)的設(shè)計(jì)也沒什么講究大多屬于“能用就行”,但是根據(jù)作者將近十年的開發(fā)經(jīng)驗(yàn)來看的話,只要你是從事 Web 相關(guān)領(lǐng)域開發(fā)你就無法避免不和數(shù)據(jù)庫(kù)打交道,在Web開發(fā)中大多功能操作本質(zhì)上都是對(duì)數(shù)據(jù)庫(kù)進(jìn)行操作,不管你用是 Pythod,Java,Ruby 等語(yǔ)言進(jìn)行 Web 開發(fā),你其實(shí)都是在面向數(shù)據(jù)庫(kù)進(jìn)行編程,很多 Web 框架作者為了避免程序員接觸數(shù)據(jù)庫(kù)的相關(guān)知識(shí)甚至還封裝了一層 ORM (Object Relational Mapping 對(duì)象關(guān)系映射),把數(shù)據(jù)庫(kù)當(dāng)做一個(gè)黑盒子,然后通過操作對(duì)象的形式來操作數(shù)據(jù)庫(kù)
雖然某種意義上是簡(jiǎn)化的開發(fā),對(duì)此我是持有保留意見的,因?yàn)閷?duì)于程序員來說很有必要了解你的 SQL 語(yǔ)言在數(shù)據(jù)庫(kù)是怎么執(zhí)行的,你不僅需要使用 explain 執(zhí)行計(jì)劃來查看你的 SQL 是否高效(掃描行數(shù),命中索引,回表,排序等),對(duì)比不同 SQL 的寫法外,你還需要知道如何使用 show index 來查看你的索引是否高效(通過 Cardinality 由數(shù)據(jù)庫(kù)評(píng)估),這些技巧很大程度依賴你對(duì) SQL 的了解,SQL 對(duì)于程序員來說也是一門非常重要的技能,沒錯(cuò) SQL 就是操作數(shù)據(jù)庫(kù)的語(yǔ)言,據(jù)我了解大多數(shù)的公司在面試的時(shí)候都會(huì)考察程序員的 SQL 功底,扎實(shí)的 SQL 功底不僅可以讓你寫出高性能的查詢語(yǔ)言外,對(duì)于數(shù)據(jù)分析,報(bào)表統(tǒng)計(jì)也是有非常大的幫助
大多數(shù)商業(yè)公司的核心資產(chǎn)其實(shí)就是數(shù)據(jù)庫(kù)里面的數(shù)據(jù),是非常寶貴的財(cái)富,程序和系統(tǒng)掛了,最多就是一段時(shí)間不可用,大多是情況重啟就可以恢復(fù),但是是數(shù)據(jù)庫(kù)不小心被誤刪了,如果是運(yùn)維能力差的中小企業(yè)可能會(huì)面臨倒閉的地步,從商業(yè)角度上來說數(shù)據(jù)庫(kù)大多數(shù)軟件公司的核心
很多程序員從菜鳥成長(zhǎng)到高手,接觸的項(xiàng)目從學(xué)校的"某某管理系統(tǒng)"到剛加入公司內(nèi)部系統(tǒng),然后再到大型分布式系統(tǒng),在大型系統(tǒng)中,大多數(shù)人程序員通常遇到的第一個(gè)問題通常不是線程不夠用,不是CPU負(fù)載過高,不是內(nèi)存不夠快,通常都是數(shù)據(jù)庫(kù)扛不住壓力了,為什么呢?數(shù)據(jù)庫(kù)本身就基于磁盤的文件系統(tǒng),每次讀取數(shù)據(jù)都是通過 I/O 去訪問磁盤,了解計(jì)算機(jī)原理的同學(xué)應(yīng)該都知道,在馮諾依曼計(jì)算機(jī)體系結(jié)構(gòu)里磁盤 I/O 號(hào)稱是最慢的 I/O (毫秒級(jí)),通常在你的系統(tǒng)只有幾千上萬(wàn)的數(shù)據(jù)量時(shí),全表掃描通常不會(huì)有很大的延遲感,但是當(dāng)你的存量數(shù)據(jù)達(dá)到百萬(wàn)千萬(wàn)時(shí),那么一次普通的查詢就會(huì)把你的數(shù)據(jù)庫(kù)服務(wù)器撐爆,做過應(yīng)用的人都知道,數(shù)據(jù)庫(kù)掛了,不管是什么分布式,微服務(wù)的牛逼架構(gòu)都基本沒啥用了,嘮嘮叨叨說到這里,相信大家應(yīng)該已經(jīng)知道數(shù)據(jù)庫(kù)的重要性的,后面我們?cè)購(gòu)臄?shù)據(jù)庫(kù)設(shè)計(jì)的角度來看下問題
這里我們簡(jiǎn)單做一個(gè)對(duì)比,良好的數(shù)據(jù)庫(kù)設(shè)計(jì)可以為你帶來什么 ?
糟糕的設(shè)計(jì) ?
糟糕的設(shè)計(jì)(圖)
比如說對(duì)于一個(gè)簡(jiǎn)單的年齡字段,嚴(yán)謹(jǐn)來說應(yīng)該使用 tinyint(1字節(jié))或者 smallint(2字節(jié)),但是你偏偏要用 int (4字節(jié)) 這就屬于糟糕的字段選擇,看到這里很多剛?cè)腴T的同學(xué)就可能就會(huì)反駁了,這么在意空間利用是不是有點(diǎn)矯枉過正?包括存儲(chǔ)已經(jīng)很便宜了,還這么斤斤計(jì)較般的選擇,反正最終實(shí)現(xiàn)的功能都是相同的,別人也看不出什么差別呀。對(duì)于這種觀點(diǎn)其實(shí)我想反駁一下,這是典型的新手思維,你只在看到在單個(gè)字段上的空間節(jié)省,但是沒有考慮過數(shù)據(jù)也是在持續(xù)增長(zhǎng),糟糕的設(shè)計(jì)越到后期增長(zhǎng)成本會(huì)越高(這里就類似于 Java 的經(jīng)典面試題,集合類 ArrayList 和 LinkedList 在少量數(shù)據(jù)對(duì)比時(shí)看不出時(shí)間上的差距,但是隨著計(jì)算數(shù)據(jù)量的上升,消耗數(shù)據(jù)的差距也會(huì)越拉越大),等到了千萬(wàn)級(jí)數(shù)據(jù)量的時(shí)候,可能你設(shè)計(jì)的表和別人設(shè)計(jì)的表是相同的內(nèi)容,但是你的表無端的多出幾百G的存儲(chǔ)空間,如果你的應(yīng)用還是多數(shù)據(jù)中心的話,那么這種無端的空間浪費(fèi)還會(huì)被拷貝幾十倍到不同的數(shù)據(jù)中心,而且只要你的應(yīng)用還在線上運(yùn)行,那么這種增長(zhǎng)所帶來的成本還會(huì)持續(xù)上升,這里也僅僅只是說對(duì)空間的浪費(fèi),下面在分析表結(jié)構(gòu)存儲(chǔ)上,還會(huì)具體說一下糟糕的設(shè)計(jì)對(duì)于性能會(huì)有多大的影響,這對(duì)企業(yè)來說就是邊際成本的遞增,從技術(shù)和架構(gòu)上來說就會(huì)讓你的系統(tǒng)不具備可擴(kuò)展性
MySQL 的開放性架構(gòu)設(shè)計(jì)兼容了很多不種類的存儲(chǔ)引擎(要是你足夠厲害的話,也可以自己寫一套存儲(chǔ)引擎),存儲(chǔ)引擎的設(shè)計(jì)初衷就是應(yīng)對(duì)不同類型的數(shù)據(jù)倉(cāng)庫(kù),工作中有見過不管什么表都直接用 Innodb(MySQL 5.0 的默認(rèn)存儲(chǔ)引擎,雖然大多數(shù)場(chǎng)景是不錯(cuò)的選擇,但不是所有類型的表結(jié)構(gòu)都適用)也見過根本不知道什么是存儲(chǔ)引擎的同學(xué),如果這些同學(xué)來設(shè)計(jì)數(shù)據(jù)庫(kù)的話,那么你的系統(tǒng)就很容易踩到坑,出現(xiàn)很多你自己的預(yù)料不到的問題,合理的存儲(chǔ)引擎的選擇是應(yīng)該結(jié)合實(shí)際業(yè)務(wù)場(chǎng)景,從目前最主流的 MySQL 來說,最常用的存儲(chǔ)引擎主要是 MyISAM, Innodb,當(dāng)然還有很多其他的存儲(chǔ)引擎,例如 NDB(集群存儲(chǔ)引擎),Memory(基于內(nèi)存的存儲(chǔ)引擎),Archive(歸檔存儲(chǔ)引擎),因?yàn)檫@些平時(shí)使用不多,并不主流,工作中也很少用得到,意義不大,所以就不展開來講,這里主要簡(jiǎn)單將下 MyISAM,Innodb 的區(qū)別,主要有以下特點(diǎn):
MyISAM
Innodb
因?yàn)椴涣私鈹?shù)據(jù)庫(kù)的基本原理,所以很多初級(jí)程序員在選擇數(shù)據(jù)庫(kù)字段類型的時(shí)候比較迷茫,主要還是沒有明確指導(dǎo)原則,工作中我見過在只有十幾條數(shù)據(jù)的基礎(chǔ)信息表中使用 long(8字節(jié))作為 id 主鍵類型,還有就像上面說的狀態(tài)類型字段只有 0,1 值的字段使用 int (4字節(jié)),還見過字符類型字段統(tǒng)一使用 varchar(255),數(shù)值類型字段統(tǒng)一使用 int,這種不基于數(shù)據(jù)庫(kù)原理規(guī)則去隨意選擇字段的行為也只會(huì)出現(xiàn)在你 LocalHost 里的一些小項(xiàng)目或者玩具,基本上不了什么大臺(tái)面
據(jù)我所知,主流的數(shù)據(jù)庫(kù)大多都提供非常豐富的字段類型給開發(fā)者使用,老司機(jī)都是基于業(yè)務(wù)類型的判斷從而選擇合適的字段類型,最終收獲的是性能(時(shí)間)和存儲(chǔ)(空間)都非常低的高性能數(shù)據(jù)庫(kù),具體數(shù)據(jù)庫(kù)有哪些字段類型,文章里面就不多數(shù)了,這方面的資料簡(jiǎn)直太多了,有興趣的小伙伴可以自己去搜索,例如這里 MySQL Data Types,那么對(duì)于新手而言如何選擇字段類型呢?
簡(jiǎn)單的基本原則如下:(后面會(huì)具體將原因)
遵循基本規(guī)范能帶來什么好處?
為什么要把“選擇盡可能小的字段”作為基本原則?我們可以先看下 innodb 的邏輯存儲(chǔ)結(jié)構(gòu)
innodb 邏輯存儲(chǔ)結(jié)構(gòu)(圖)
innodb 的存儲(chǔ)結(jié)構(gòu)如下:
上圖可以看到讀取最小單元 Page,匹配的數(shù)據(jù)都是從 Page 里面取出,按照這個(gè)簡(jiǎn)單的邏輯來說頁(yè)中存儲(chǔ)的行數(shù)據(jù)越多,數(shù)據(jù)庫(kù)的性能就越高,怎么算出來的呢?按最小類型 2B 來計(jì)算 Row,那么 Page 的默認(rèn)大?。?6KB)是可以匹配到 7992 行記錄,相反,如果你的 Row 行數(shù)據(jù)過大,假如一行 32 KB,那么數(shù)據(jù)庫(kù)就需要 2 個(gè)連續(xù)的 Page 來保存你一行的數(shù)據(jù),那么性能可想而知會(huì)有多低,前后性能差距差不多 1.6 萬(wàn)倍,這塊也不深入講了,有興趣的小伙伴推薦去閱讀經(jīng)典書籍,這里的內(nèi)容也只是書里的冰山一角
索引是一種用空間換時(shí)間的優(yōu)化手段,是數(shù)據(jù)庫(kù)最重要的優(yōu)化手段,也是最后的殺手锏,索引是否高效取決數(shù)據(jù)庫(kù)設(shè)計(jì)是否良好,字段類型選擇是否合理,索引是一把雙刃劍,在提升檢索速度的時(shí)候,也會(huì)減低插入,修改的性能(維護(hù)索引樹的開銷),在工作中這些年面試了不下幾百人發(fā)現(xiàn)能把數(shù)據(jù)庫(kù)索引原理講明白的候選人非常的少,大多數(shù)情況下我們說索引通常默認(rèn)指的是 BTREE 索引,BTREE 結(jié)構(gòu)是特意為磁盤 I/O 這種緩慢的讀取存儲(chǔ)設(shè)計(jì)的數(shù)據(jù)結(jié)構(gòu),是一棵多路多叉樹,和二叉樹相反,每層的元素非常多,但是樹的高度很矮(通常不會(huì)超過三層),從而可以保證最多不超過三次磁盤 I/O 即可定位到匹配的元素,所以說 BTREE 是一種非常適合磁盤的數(shù)據(jù)結(jié)構(gòu),也是 MySQL 默認(rèn)索引類型是 BREE 的原因,如果能把這塊吃透的話,那么去面試肯定是很大的加分項(xiàng),索引在數(shù)據(jù)庫(kù)可以簡(jiǎn)單參考下圖:
簡(jiǎn)單說了下索引的結(jié)構(gòu),那么新手程序員在使用數(shù)據(jù)庫(kù)所以的時(shí)候可以遵循以下原則:
索引這塊可以玩的還有很多,例如如何通過 SHOW INDEX 查看數(shù)據(jù)庫(kù)為索引做出的評(píng)級(jí)(通過 Cardinality 統(tǒng)計(jì)),通過 Explain 查看 SQL 是否命中索引,rows 列可以看到 SQL 掃描的數(shù)據(jù)行數(shù),Extra 列還可以查看索引匹配的類型,例如 Using index 代表完全匹配索引(無需回到 Primary Key 表查詢數(shù)據(jù),也稱回表,甚至直接使用索引的排序,無需排序)往往說明性能不錯(cuò),Using temporary 代表查詢有使用臨時(shí)表,一般出現(xiàn)于排序,多表 join 的情況,查詢效率不高,建議優(yōu)化
人生總會(huì)遇到很多坑,與其自己去踩坑不如去總結(jié)別人踩過的坑,自己少走一些彎路也許可以更快的成功,這里是最后一章,不想把文章拉的太長(zhǎng),所以我在這里就直接拋出結(jié)論,不會(huì)再說明原因,如果對(duì)數(shù)據(jù)庫(kù)有興趣推薦看到最后我推薦的書籍
避免使用觸發(fā)器/存儲(chǔ)過程
避免使用預(yù)留字段
反范式設(shè)計(jì)
盡量避免使用 Null 字段
關(guān)于常見的數(shù)據(jù)庫(kù)避坑指南就分享到這里了,當(dāng)然并不止以上和大家分析的辦法,不過小編可以保證其準(zhǔn)確性是絕對(duì)沒問題的。希望以上內(nèi)容可以對(duì)大家有一定的參考價(jià)值,可以學(xué)以致用。如果喜歡本篇文章,不妨把它分享出去讓更多的人看到。