面試不再尬聊的Mysql數據庫優化方案

點贊多大膽,就有多大產!有支持纔有動力!將技術分享給每一個技術使用者和愛好者!

乾貨滿滿,擺好姿勢,點贊發車!

 前言

數據庫優化是一個老生常談的問題,剛入門的小白或者工作N年的光頭對這個問題應該都不陌生,你要面試一箇中高級工程師那麼他就想"哥倆好"一樣那麼粘,面試官肯定會問這個問題,這篇文章我們就和它哥倆好!而且這個問題就是一個送分題,數據庫的優化方案基本就是那些,答案也都是固定的,大家只要好好準備這個問題就不會住你,可以在面試中安排面試官,不然就被面試官安排!話不多說下邊就針對數據庫優化展開講!

相關文章

《MySQL索引從零上手使用》

《MySQL索引數據結構,看看什麼是B+樹吧》

《基於MyCat實現MySQL讀寫分離》

《基於MyCat實現MySQL數據拆分》

面試開始

小夥子看你簡歷上寫了Mysql,數據庫優化了解嗎?

摸摸頭之後笑着說數據庫優化不是很瞭解嘿嘿~~~,這時和藹的面試官頭上出現了一抹紅!

如果這時你正好想到了我這篇文章,那麼你就會說數據庫優化方面我還是很有研究的,請您聽我慢慢道來......

首先

面試官我想解釋一下爲什麼做數據庫優化(這個你心裏知道就好了,面試的時候就不要說了)

  • 系統的數據都從數據庫上來,數據庫的吞吐量和速度一定程度決定系統的併發和響應速度
  • 系統運行與數據量成正比,數據讀處理尤其是查詢自然就慢
  • Mysql數據庫的數據最終在磁盤上持久化存儲,讀寫不如Redis等這些內存數據庫

其次

面試官大人我想說一下數據庫優化一般從以下幾個方面來:

  • 數據庫設計:數據表設計遵循三範式,使用合適的數據類型,使用合適的存儲引擎
  • 適當創建索引
  • 數據庫擴展:數據庫的分表分庫,讀寫分離等
  • SQL語句優化等

接下來我們一一說明解釋

數據庫設計

數據庫設計3範式

數據庫設計範式如果要滿足N範式必須要先滿足N-1範式

第一範式1NF:字段原子性

第一範式簡單的說就是表中的字段是最小不可再分的,我們下邊舉個例子,我們看到以下一張用戶表。裏邊的字段是不可再分的,這樣就符合第一範式的原子性,可能有些朋友會疑問,這個地址還可以分成省份、城市、區/縣三個字段,是的!如果是一個電商項目它需要再分,那麼就不符合第一範式,所以具體還是看項目的需求,沒有固定標準,在項目需求中它的設計已不可再分那麼就符合第一範式!

第二範式2NF: 消除對主鍵的部分依賴

2NF的使用是需要滿足1NF爲前提,在表中添加一個業務字段,而主鍵不用來做業務處理,比如我們的商品表有商品id,商品id爲商品的主鍵,但是需要創建一個商品編號列來專門處理業務,因爲id太敏感,我們處理業務都是用商品編號來處理,比如展示商品時展示編號等等!

第三範式3NF:在2NF的基礎上添加外鍵

3NF的使用必須滿足2NF,要求表中的每一列只與主鍵直接相關而不是間接相關,(表中的每一列只能依賴於主鍵),比如下面的例子,訂單表中有客戶相關信息,在分離出客戶表之後,訂單表中只需要有一個用戶id即可(外鍵),而不能有其他的客戶信息。因爲其他的客戶信息直接關聯於用戶id,而不是直接與訂單id直接相關。如下圖所示:

分離之後:

三大範式只是一般設計數據庫的基本理念,可以建立冗餘較小、結構合理的數據庫。如果有特殊情況,當然要特殊對待,數據庫設計最重要的是看需求跟性能,需求>性能>表結構。所以不能一味的去追求範式建立數據庫!需求才是粑粑

數據類型

儘量使用可以正確存儲數據的最小數據類型

更小的數據類型意味着更快,佔用更少的磁盤,內存、緩存和處理時間

儘量使用整型表示字符串

因爲字符集和校對規則,使處理字符比整型更復雜,比如:我們使用數據庫內置的datetime類型存儲時間而不是字符類型,我們使用整型存儲ip而不是直接將ip字符串存到數據庫中

儘可能使用not null

這個值是很煩人的,建字段時請儘量指定是否非空,NULL使得索引,統計,比較都變得更復雜,而且索引儘量不要創建到可以爲null的字段上

字符串類型

VARCHAR是可變長字符串

比定長字符串(CHAR)更節省空間,僅使用必要的空間另外VARCHAR需要額外字節記錄字符串長度(不同情況需要字節數不同)

CHAR類型是定長字符串

開發中基本很少用(一些公司甚至基本上不考慮這種類型了),注意:字符串長度定義不是字節數,是字符數

日期和時間類型

datetime

使用8字節存儲空間,保存從1001年到9999年的秒數。與時區無關,默認情況下,Mysql以一種可排序的格式顯示它的值,例如:"2018-10-14 22:30:08"

timestamp

只使用4字節存儲,保存1970年1月1日午夜以來的秒數,依賴於系統時區,和UNIX時間戳相同,轉換函數分別爲FROM_UNIXTIME()和UNIX_TIMESTAMP(),可以設置根據當前時間戳更新,比如我們熟悉的update_time字段

整數類型

UNSIGNED

屬性表示不允許負值,可以使得正數的上限提高一倍,比如tinyint+unsigned可以使原本的-128~127的範圍變爲0~255

tinyint

我們一般用它存儲狀態值而不要用int,如果是Boolean類型,那麼tinyint(1)當值爲1和0時,查詢結果自動轉爲true和false,條件參數相應的也可以直接傳入true和false即可

INT(11)

不會限制值的範圍,只是規定了一些客戶端工具用來顯示的字符的個數,所以對於存儲和計算來說INT(11)和INT(1)相同

IP地址

實際上是32位無符號整數,用INT存儲,Mysql提供轉換函數爲INET_ATON()和INET_NTOA()

小數

decimal不會損失精度,存儲空間會隨數據的增大而增大。double佔用固定空間,較大數的存儲會損失精度,通常存金額用decimal(11,2),這表示整數部分和小數部分分別爲9位和2位注意!,當然可以根據具體的金額大小選擇長度,注意這時候對應的java中用BigDecimal類來處理運算時要仔細,因爲加減法和比較跟平常不一樣

存儲引擎

介紹

數據庫存儲引擎是數據庫底層組件,數據庫管理系統使用數據引擎進行創建、查詢、更新和刪除數據操作。不同的存儲引擎提供不同的存儲機制、索引技巧、鎖定水平等功能,使用不同的存儲引擎還可以獲得特定的功能。我們可以通過SHOW ENGINES;

InnoDB存儲引擎

InnoDB越做越好從MySQL5.5版本之後,MySQL的默認內置存儲引擎已經是InnoDB,主要特點有

  1. 容災恢復性比較好
  2. 支持事務,默認事務隔離界別爲可重複讀
  3. 使用的鎖粒度爲行鎖,可以支持更高的併發
  4. 支持外鍵
  5. 配合一些熱備工具可以支持在線熱備份
  6. 在InnoDB中存在着緩衝管理,通過緩衝池,將索引和數據全部緩存起來,加快查詢的速度
  7. 對於InnoDB類型的表,其數據的物理組織形式是聚簇表。所有的數據按照主鍵來組織。根據主鍵進行排序,數據和索引放在一塊,都位於B+數的葉子節點上

MyISAM存儲引擎

在5.5版本之前,MyISAM是MySQL的默認存儲引擎,該存儲引擎併發性差,不支持事務,所以使用場景比較少,主要特點有

  1. 不支持事務
  2. 不支持外鍵,如果強行增加外鍵,不會提示錯誤,只是外鍵不其作用
  3. 對數據的查詢緩存只會緩存索引,不會像InnoDB一樣緩存數據,而且是利用操作系統本身的緩存
  4. 默認的鎖粒度爲表級鎖,所以併發度很差,加鎖快,鎖衝突較少,所以不太容易發生死鎖
  5. 支持全文索引(MySQL5.6之後,InnoDB存儲引擎也對全文索引做了支持),但是MySQL的全文索引基本不會使用,對於全文索引,現在有其他成熟的解決方案,比如:ElasticSearch,Solr,Sphinx等
  6. 數據庫所在主機如果宕機,MyISAM的數據文件容易損壞,而且難恢復

MEMORY存儲引擎

將數據存在內存中,和市場上的Redis,memcached等思想類似,爲了提高數據的訪問速度,主要特點有

  1. 支持的數據類型有限制,不支持TEXT和BLOB類型,對於字符串類型的數據,只支持固定長度的行,VARCHAR會被自動存儲爲CHAR類型
  2. 支持的鎖粒度爲表級鎖。所以,在訪問量比較大時,表級鎖會成爲MEMORY存儲引擎的瓶頸
  3. 由於數據是存放在內存中,所以在服務器重啓之後,所有數據都會丟失
  4. 查詢的時候,如果有用到臨時表,而且臨時表中有BLOB,TEXT類型的字段,那麼這個臨時表就會轉化爲MyISAM類型的表,性能會急劇降低

ARCHIVE存儲引擎

ARCHIVE存儲引擎適合的場景有限,由於其支持壓縮,故主要是用來做日誌,流水等數據的歸檔,主要特點有

  1. 支持Zlib壓縮,數據在插入表之前,會先被壓縮
  2. 僅支持SELECT和INSERT操作,存入的數據就只能查詢,不能做修改和刪除;
  3. 只支持自增鍵上的索引,不支持其他索引

CSV存儲引擎

數據中轉試用,主要特點有

  1. 其數據格式爲.csv格式的文本,可以直接編輯保存
  2. 導入導出比較方便,可以將某個表中的數據直接導出爲csv,試用Excel辦公軟件打開

選擇依據

如果沒有特殊需求默認使用InnoDB引擎即可

MyISAM:以讀寫插入爲主的應用程序,比如博客系統、新聞門戶網站。

Innodb:更新(刪除)操作頻率也高,或者要保證數據的完整性;併發量高,支持事務和外鍵保證數據完整性。比如OA自動化辦公系統

索引

已爲客官備好,輕點哦《這小夥子把MySQL索引使用講的真明白,真好,快來戳他》

索引數據結構在這在這《搞懂MySQL數據庫索引數據結構這一篇足夠從此不再萌萌噠》

MySQL讀寫分離

點一下就會《看了這篇文章覺得MySQL讀寫分離這麼簡單》

MySQL分表分庫

一樣點一下就成《手把手基於Mycat實現MySQL數據拆分》

SQL優化

這裏列舉出來一些用過的,看到的歡迎大家評論區補充討論

1、查詢儘量避免全表掃描,首先考慮在where、order by字段上添加索引

2、避免在where字段上使用NULL值,所以在設計表時儘量使用NOT NULL約束,有些數據會默認爲NULL,可以設置默認值爲0或者-1

3、避免在where子句中使用!=或<>操作符,Mysql只對<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE使用索引

4、避免在where中使用OR來連接條件,否則可能導致引擎放棄索引來執行全表掃描,可以使用UNION進行合併查詢

      select id from t where num = 30 union select id from t where num = 40;

5、儘量避免在where子句中進行函數或者表達式操作

6、最好不要使用select * from t,用具體的字段列表代替"*",不要返回用不到的任何字段

7、in 和 not in 也要慎用,否則會導致全表掃描,如

select id from t where num IN(1,2,3)如果是連續的值建議使用between and,select id from t where between 1 and 3;

8、select id from t where col like %a%;模糊查詢左側有%會導致全表檢索,如果需要全文檢索可以使用全文搜索引擎比如es,slor

9、limit offset rows關於分頁查詢,儘量保證不要出現大的offset,比如limit 10000,10相當於對已查詢出來的行數棄掉前10000行後再取10行,完全可以加一些條件過濾一下(完成篩選),而不應該使用limit跳過已查詢到的數據。這是一個==offset做無用功==的問題。對應實際工程中,要避免出現大頁碼的情況,儘量引導用戶做條件過濾

關注本系列文章的朋友應該發現,這裏的未完待續已經消失,我們的MySQL優化就告一段落,主要從數據庫設計、索引、數據庫拆分和SQL語句上進行優化,更多優化方案希望大家通過評論區讓曉添和讀者朋友們都學習到,謝謝閱讀,點贊收藏和關注!


 路漫漫其修遠兮,吾將上下而求索

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章