溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

常見的數(shù)據(jù)庫避坑指南,趕緊收藏起來

發(fā)布時間:2020-03-24 11:37:39 來源:億速云 閱讀:170 作者:小新 欄目:編程語言
常見的數(shù)據(jù)庫避坑指南有哪些?有什么技巧?大家跟著小編一起來看看吧!
前言

工作的這些年發(fā)現(xiàn)一個比較奇怪的現(xiàn)象就是身邊無論是工作十多年的老兵,還是初級剛?cè)胄械某绦騿T,在高談闊論技術(shù)和趨勢的時候都是人工智能,大數(shù)據(jù),區(qū)塊鏈,各種框架,語言,算法,AI,BI,CI,DI…… 等等,倒是發(fā)現(xiàn)很少有人關(guān)注數(shù)據(jù)庫,不知道是因為數(shù)據(jù)庫感覺太低端還是太低調(diào),總是不容易被人提起

技術(shù)就是這樣,不太關(guān)注的地方就不會重視,越是不被重視的地方,掉進坑里的概率就會越大,所以就在這里給大家簡單聊聊在使用數(shù)據(jù)庫過程中有哪些防掉坑指南,也可以對剛?cè)胄械男∨笥延幸粋€提醒的作用,萬丈高樓平地起,一定要先打好基礎(chǔ)再去考慮上層的建筑,不要舍本逐末

本章主要分以下四個小節(jié)(預(yù)計讀完 5 分鐘左右):

  1. 數(shù)據(jù)庫為什么重要
  2. 數(shù)據(jù)庫有哪些使用技巧
  3. 數(shù)據(jù)庫有哪些容易掉進去的坑?
  4. 深入學習數(shù)據(jù)庫的建議
數(shù)據(jù)庫為什么重要

很多人在開發(fā)過程中不太關(guān)注數(shù)據(jù)庫,對于表結(jié)構(gòu)的設(shè)計也沒什么講究大多屬于“能用就行”,但是根據(jù)作者將近十年的開發(fā)經(jīng)驗來看的話,只要你是從事 Web 相關(guān)領(lǐng)域開發(fā)你就無法避免不和數(shù)據(jù)庫打交道,在Web開發(fā)中大多功能操作本質(zhì)上都是對數(shù)據(jù)庫進行操作,不管你用是 Pythod,Java,Ruby 等語言進行 Web 開發(fā),你其實都是在面向數(shù)據(jù)庫進行編程,很多 Web 框架作者為了避免程序員接觸數(shù)據(jù)庫的相關(guān)知識甚至還封裝了一層 ORM (Object Relational Mapping 對象關(guān)系映射),把數(shù)據(jù)庫當做一個黑盒子,然后通過操作對象的形式來操作數(shù)據(jù)庫

常見的數(shù)據(jù)庫避坑指南,趕緊收藏起來

雖然某種意義上是簡化的開發(fā),對此我是持有保留意見的,因為對于程序員來說很有必要了解你的 SQL 語言在數(shù)據(jù)庫是怎么執(zhí)行的,你不僅需要使用 explain 執(zhí)行計劃來查看你的 SQL 是否高效(掃描行數(shù),命中索引,回表,排序等),對比不同 SQL 的寫法外,你還需要知道如何使用 show index 來查看你的索引是否高效(通過 Cardinality 由數(shù)據(jù)庫評估),這些技巧很大程度依賴你對 SQL 的了解,SQL 對于程序員來說也是一門非常重要的技能,沒錯 SQL 就是操作數(shù)據(jù)庫的語言,據(jù)我了解大多數(shù)的公司在面試的時候都會考察程序員的 SQL 功底,扎實的 SQL 功底不僅可以讓你寫出高性能的查詢語言外,對于數(shù)據(jù)分析,報表統(tǒng)計也是有非常大的幫助

大多數(shù)商業(yè)公司的核心資產(chǎn)其實就是數(shù)據(jù)庫里面的數(shù)據(jù),是非常寶貴的財富,程序和系統(tǒng)掛了,最多就是一段時間不可用,大多是情況重啟就可以恢復(fù),但是是數(shù)據(jù)庫不小心被誤刪了,如果是運維能力差的中小企業(yè)可能會面臨倒閉的地步,從商業(yè)角度上來說數(shù)據(jù)庫大多數(shù)軟件公司的核心

很多程序員從菜鳥成長到高手,接觸的項目從學校的"某某管理系統(tǒng)"到剛加入公司內(nèi)部系統(tǒng),然后再到大型分布式系統(tǒng),在大型系統(tǒng)中,大多數(shù)人程序員通常遇到的第一個問題通常不是線程不夠用,不是CPU負載過高,不是內(nèi)存不夠快,通常都是數(shù)據(jù)庫扛不住壓力了,為什么呢?數(shù)據(jù)庫本身就基于磁盤的文件系統(tǒng),每次讀取數(shù)據(jù)都是通過 I/O 去訪問磁盤,了解計算機原理的同學應(yīng)該都知道,在馮諾依曼計算機體系結(jié)構(gòu)里磁盤 I/O 號稱是最慢的 I/O (毫秒級),通常在你的系統(tǒng)只有幾千上萬的數(shù)據(jù)量時,全表掃描通常不會有很大的延遲感,但是當你的存量數(shù)據(jù)達到百萬千萬時,那么一次普通的查詢就會把你的數(shù)據(jù)庫服務(wù)器撐爆,做過應(yīng)用的人都知道,數(shù)據(jù)庫掛了,不管是什么分布式,微服務(wù)的牛逼架構(gòu)都基本沒啥用了,嘮嘮叨叨說到這里,相信大家應(yīng)該已經(jīng)知道數(shù)據(jù)庫的重要性的,后面我們再從數(shù)據(jù)庫設(shè)計的角度來看下問題

這里我們簡單做一個對比,良好的數(shù)據(jù)庫設(shè)計可以為你帶來什么 ?

  1. 減少數(shù)據(jù)冗余,避免數(shù)據(jù)維護異常
  2. 節(jié)省存儲空間,高效的訪問速度

糟糕的設(shè)計 ?

  1. 大量數(shù)據(jù)冗余插入,更新,刪除異常
  2. 浪費存儲空間,低效的訪問速度

常見的數(shù)據(jù)庫避坑指南,趕緊收藏起來

糟糕的設(shè)計(圖)

比如說對于一個簡單的年齡字段,嚴謹來說應(yīng)該使用 tinyint(1字節(jié))或者 smallint(2字節(jié)),但是你偏偏要用 int (4字節(jié)) 這就屬于糟糕的字段選擇,看到這里很多剛?cè)腴T的同學就可能就會反駁了,這么在意空間利用是不是有點矯枉過正?包括存儲已經(jīng)很便宜了,還這么斤斤計較般的選擇,反正最終實現(xiàn)的功能都是相同的,別人也看不出什么差別呀。對于這種觀點其實我想反駁一下,這是典型的新手思維,你只在看到在單個字段上的空間節(jié)省,但是沒有考慮過數(shù)據(jù)也是在持續(xù)增長,糟糕的設(shè)計越到后期增長成本會越高(這里就類似于 Java 的經(jīng)典面試題,集合類 ArrayList 和 LinkedList 在少量數(shù)據(jù)對比時看不出時間上的差距,但是隨著計算數(shù)據(jù)量的上升,消耗數(shù)據(jù)的差距也會越拉越大),等到了千萬級數(shù)據(jù)量的時候,可能你設(shè)計的表和別人設(shè)計的表是相同的內(nèi)容,但是你的表無端的多出幾百G的存儲空間,如果你的應(yīng)用還是多數(shù)據(jù)中心的話,那么這種無端的空間浪費還會被拷貝幾十倍到不同的數(shù)據(jù)中心,而且只要你的應(yīng)用還在線上運行,那么這種增長所帶來的成本還會持續(xù)上升,這里也僅僅只是說對空間的浪費,下面在分析表結(jié)構(gòu)存儲上,還會具體說一下糟糕的設(shè)計對于性能會有多大的影響,這對企業(yè)來說就是邊際成本的遞增,從技術(shù)和架構(gòu)上來說就會讓你的系統(tǒng)不具備可擴展性

數(shù)據(jù)庫的使用技巧

MySQL 的開放性架構(gòu)設(shè)計兼容了很多不種類的存儲引擎(要是你足夠厲害的話,也可以自己寫一套存儲引擎),存儲引擎的設(shè)計初衷就是應(yīng)對不同類型的數(shù)據(jù)倉庫,工作中有見過不管什么表都直接用 Innodb(MySQL 5.0 的默認存儲引擎,雖然大多數(shù)場景是不錯的選擇,但不是所有類型的表結(jié)構(gòu)都適用)也見過根本不知道什么是存儲引擎的同學,如果這些同學來設(shè)計數(shù)據(jù)庫的話,那么你的系統(tǒng)就很容易踩到坑,出現(xiàn)很多你自己的預(yù)料不到的問題,合理的存儲引擎的選擇是應(yīng)該結(jié)合實際業(yè)務(wù)場景,從目前最主流的 MySQL 來說,最常用的存儲引擎主要是 MyISAM, Innodb,當然還有很多其他的存儲引擎,例如 NDB(集群存儲引擎),Memory(基于內(nèi)存的存儲引擎),Archive(歸檔存儲引擎),因為這些平時使用不多,并不主流,工作中也很少用得到,意義不大,所以就不展開來講,這里主要簡單將下 MyISAM,Innodb 的區(qū)別,主要有以下特點:

MyISAM

  • 無事務(wù)機制,表級鎖,自帶計數(shù)功能(count 全表毫秒級響應(yīng))
  • 主要面向 OLAP 型應(yīng)用,適合存儲報表日志等類型數(shù)據(jù)

Innodb

  • 行級別,高并發(fā),支持事務(wù),四種事務(wù)隔離級別(MySQL 5.0+ 默認是讀已提交)
  • 主要面向 OLTP 型應(yīng)用,適合存儲小量的事務(wù)型數(shù)據(jù)

常見的數(shù)據(jù)庫避坑指南,趕緊收藏起來

因為不了解數(shù)據(jù)庫的基本原理,所以很多初級程序員在選擇數(shù)據(jù)庫字段類型的時候比較迷茫,主要還是沒有明確指導(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ù)庫原理規(guī)則去隨意選擇字段的行為也只會出現(xiàn)在你 LocalHost 里的一些小項目或者玩具,基本上不了什么大臺面

據(jù)我所知,主流的數(shù)據(jù)庫大多都提供非常豐富的字段類型給開發(fā)者使用,老司機都是基于業(yè)務(wù)類型的判斷從而選擇合適的字段類型,最終收獲的是性能(時間)和存儲(空間)都非常低的高性能數(shù)據(jù)庫,具體數(shù)據(jù)庫有哪些字段類型,文章里面就不多數(shù)了,這方面的資料簡直太多了,有興趣的小伙伴可以自己去搜索,例如這里 MySQL Data Types,那么對于新手而言如何選擇字段類型呢?

簡單的基本原則如下:(后面會具體將原因)

  1. 優(yōu)先數(shù)字型字段(比如盡量使用 int 作為數(shù)據(jù)庫主鍵 id 的類型而不是 varchar)
  2. 在滿足需求的前提下,字段類型盡量足夠的?。ɡ?age 字段應(yīng)該考慮使用 tinyint 而不是 int 或者 long 類型)
  3. 時間字段考慮 timestamp (4字節(jié),支持 UTC)而不是 datetime(8字節(jié),不支持 UTC)

遵循基本規(guī)范能帶來什么好處?

  1. 節(jié)省存儲的開銷,避免空間浪費(如果1條數(shù)據(jù)造成的空間開銷n,那么隨著數(shù)據(jù)增長,浪費空間的比例也就是 n * n)
  2. 最好的性能(用戶體驗,另一種角度的節(jié)省資源-算力)

為什么要把“選擇盡可能小的字段”作為基本原則?我們可以先看下 innodb 的邏輯存儲結(jié)構(gòu)

常見的數(shù)據(jù)庫避坑指南,趕緊收藏起來

innodb 邏輯存儲結(jié)構(gòu)(圖)

innodb 的存儲結(jié)構(gòu)如下:

  • 表空間(Tablespace)
  • 段(Segment):表空間由多個段組成
  • 區(qū)(Extent):單個區(qū)由 64 個連續(xù)頁(Page)組成
  • 頁(Page):磁盤的最小單位,默認大小 16 KB
  • 行(Row):每條記錄,也稱行數(shù)據(jù),數(shù)據(jù)存儲在頁中 Page

上圖可以看到讀取最小單元 Page,匹配的數(shù)據(jù)都是從 Page 里面取出,按照這個簡單的邏輯來說頁中存儲的行數(shù)據(jù)越多,數(shù)據(jù)庫的性能就越高,怎么算出來的呢?按最小類型 2B 來計算 Row,那么 Page 的默認大?。?6KB)是可以匹配到 7992 行記錄,相反,如果你的 Row 行數(shù)據(jù)過大,假如一行 32 KB,那么數(shù)據(jù)庫就需要 2 個連續(xù)的 Page 來保存你一行的數(shù)據(jù),那么性能可想而知會有多低,前后性能差距差不多 1.6 萬倍,這塊也不深入講了,有興趣的小伙伴推薦去閱讀經(jīng)典書籍,這里的內(nèi)容也只是書里的冰山一角

索引是一種用空間換時間的優(yōu)化手段,是數(shù)據(jù)庫最重要的優(yōu)化手段,也是最后的殺手锏,索引是否高效取決數(shù)據(jù)庫設(shè)計是否良好,字段類型選擇是否合理,索引是一把雙刃劍,在提升檢索速度的時候,也會減低插入,修改的性能(維護索引樹的開銷),在工作中這些年面試了不下幾百人發(fā)現(xiàn)能把數(shù)據(jù)庫索引原理講明白的候選人非常的少,大多數(shù)情況下我們說索引通常默認指的是 BTREE 索引,BTREE 結(jié)構(gòu)是特意為磁盤 I/O 這種緩慢的讀取存儲設(shè)計的數(shù)據(jù)結(jié)構(gòu),是一棵多路多叉樹,和二叉樹相反,每層的元素非常多,但是樹的高度很矮(通常不會超過三層),從而可以保證最多不超過三次磁盤 I/O 即可定位到匹配的元素,所以說 BTREE 是一種非常適合磁盤的數(shù)據(jù)結(jié)構(gòu),也是 MySQL 默認索引類型是 BREE 的原因,如果能把這塊吃透的話,那么去面試肯定是很大的加分項,索引在數(shù)據(jù)庫可以簡單參考下圖:

常見的數(shù)據(jù)庫避坑指南,趕緊收藏起來

簡單說了下索引的結(jié)構(gòu),那么新手程序員在使用數(shù)據(jù)庫所以的時候可以遵循以下原則:

  • 明白索引不是越多越好,過多的索引會降低讀/寫效率
  • 數(shù)據(jù)小和選擇性低的列沒有必要建索引(就像沒必要為只有幾頁的書建目錄)
  • 定期維護索引(移除不必要的索引,索引的最左匹配原則)
  • 謹慎使用全文索引,哈希索引,謹慎使用 FORCE INDEX 強制索引(強制會干擾優(yōu)化器對索引選擇的判斷)

索引這塊可以玩的還有很多,例如如何通過 SHOW INDEX 查看數(shù)據(jù)庫為索引做出的評級(通過 Cardinality 統(tǒng)計),通過 Explain 查看 SQL 是否命中索引,rows 列可以看到 SQL 掃描的數(shù)據(jù)行數(shù),Extra 列還可以查看索引匹配的類型,例如 Using index 代表完全匹配索引(無需回到 Primary Key 表查詢數(shù)據(jù),也稱回表,甚至直接使用索引的排序,無需排序)往往說明性能不錯,Using temporary 代表查詢有使用臨時表,一般出現(xiàn)于排序,多表 join 的情況,查詢效率不高,建議優(yōu)化

還有哪些要避開的坑?

常見的數(shù)據(jù)庫避坑指南,趕緊收藏起來

人生總會遇到很多坑,與其自己去踩坑不如去總結(jié)別人踩過的坑,自己少走一些彎路也許可以更快的成功,這里是最后一章,不想把文章拉的太長,所以我在這里就直接拋出結(jié)論,不會再說明原因,如果對數(shù)據(jù)庫有興趣推薦看到最后我推薦的書籍

避免使用觸發(fā)器/存儲過程

  • 用存儲過程寫邏輯會導(dǎo)致代碼非常的復(fù)雜難懂,并且難以定位問題
  • 降低數(shù)據(jù)庫的性能(數(shù)據(jù)庫不應(yīng)該執(zhí)行除 SQL 外的其他邏輯操作)

避免使用預(yù)留字段

  • 無法準確預(yù)測字段類型
  • 增加后期維護成本

反范式設(shè)計

  • 不必完全遵守古板的三大范式,對范式進行違反,用空間換時間
  • 對數(shù)據(jù)進行有計劃的冗余,可以達到減少關(guān)聯(lián),提高性能和效率

盡量避免使用 Null 字段

  • Null 值會導(dǎo)致索引失效,讓統(tǒng)計函數(shù)更加復(fù)雜,另外 Null 還會占用額外的空間(數(shù)據(jù)庫需要額外標記)
  • 對于 Null 值,數(shù)據(jù)庫程序通常都會進行額外的邏輯處理,獎勵數(shù)據(jù)庫性能
  • 從數(shù)據(jù)庫中取出 Null 值容易造成程序出錯,還會增加很多 if != null 的重復(fù)模板代碼

關(guān)于常見的數(shù)據(jù)庫避坑指南就分享到這里了,當然并不止以上和大家分析的辦法,不過小編可以保證其準確性是絕對沒問題的。希望以上內(nèi)容可以對大家有一定的參考價值,可以學以致用。如果喜歡本篇文章,不妨把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI