1. 程式人生 > >MySQL優化系列之資料庫schema設計優化

MySQL優化系列之資料庫schema設計優化

前言

MySQL優化有兩大層面,第一是資料庫層面,第二是硬體層面。資料庫層面可以細分為以下幾個方面:

  • 鎖策略優化
  • 儲存引擎優化
  • 伺服器配置優化
  • 主從,讀寫分離
  • 叢集,負載均衡

本文講解資料庫schema設計優化

高效的模型設計

適度冗餘(反正規化)

在很多人眼裡,資料庫schema滿足的正規化級別越高越好,目的是儘量減少資料的冗餘,保持資料一致。但是適當的冗餘能減少多表連線操作,這樣一來冗餘的欄位就需要手動維護(比如觸發器、訊息監聽欄位變更),以保持資料一致性。如果犧牲一點維護成本能換來更大的效能提升,那麼完全可以選擇冗餘

垂直拆分

將欄位從主表拆分出去放到另外的表中。適合垂直才拆分的欄位有:

1.內容很大,但訪問頻率低的欄位

存放內容較多,訪問頻率相對其他欄位少很多的欄位。由於內容較多,大部分情況佔整條記錄的80%以上,而資料庫中資料在資料檔案中的格式一般都是以一條一條記錄為單位來存放。也就是說,如果我們要查詢某些記錄的某幾個欄位,資料庫並不是只需要訪問我們需要查詢的哪幾個欄位,而是需要讀取其他所有欄位(可以在索引中完成整個查詢的情況除外),也無法做到只讀取我們需要的幾個欄位的資料。這樣,我們就不得不讀取包括大欄位在內的很多並不相干的資料。而由於大欄位所佔的空間比例非常大,自然所浪費的IO 資源也就非常之大了。拆分大欄位後需要join來查詢它,所以還需要滿足頻率低才行

2.頻繁更新,導致快取重新整理,但訪問頻率低的欄位

比如,你有一個叫“last_login”的欄位,它會在每次使用者登入時被更新。但是,每次更新時會導致該表的查詢快取被清空。所以,你可以把這個欄位放到另一個表中,這樣就不會影響你對使用者ID,使用者名稱,使用者角色的不停地讀取了,因為查詢快取會幫你增加很多效能。

水平拆分

當單表的資料量過大時,可以按照某種規則把資料劃分到不同的表或庫中,比如訂單表,可以按年份來劃分,不同年份的訂單資料可以存放到不同的地方;有比如使用者表可以按ID取模、按性別來劃分。

統計表準實時優化

對於更新是非常頻繁的,但並不要求實時準確的資料可能弄成準實時的,比如網站訪問量、使用者活躍數這類資訊,我們可以通過定時任務,每隔一段時間去統計一次。

選擇合適的資料型別

資料型別的選擇有下面幾個簡單原則:

1.更小的通常更好

一般情況下應該選擇正確儲存資料的最小資料型別,因為它暫用更少的磁碟、記憶體和CPU快取,並且處理的CPU週期更少

2.簡單就好

簡單資料型別的操作通常需要更少的CPU週期。例如,用整型代替字元型,因為字符集和校對規則(排序規則)使字元比較比整型更復雜;用內建型別而不是字串來儲存日期時間;整型儲存IP地址

3.儘量避免NULL

NULL使索引、索引統計和值的比較都更復雜

整數型別

可以使用的整數型別有:tinyint,smallint,mediumint,int,bigint。分別使用8,16,24,32,64位儲存空間。值範圍從-2^(N-1) 到 2^(N-1)-1,N為儲存空間位數。

整數型別可選unsigned屬性,表示不允許負值,正值範圍將提高一倍,但是儲存空間和效能和有符號是相同的。

另外,整數型別可以指定寬度,其實沒有多大意義,比如int(1)和int(20)範圍是相同的

實數型別

實數是帶小數部分的數字。然而,它們不只是為了儲存小數部分;也可以用decimal儲存比bigint還大的整數。

float和double型別支援使用標準的浮點運算進行近似計算,可能存在進度丟失

decimal用於儲存精確的小數,支援精確計算

浮點型別在儲存同樣範圍的值的時候,通常比decimal使用更少的空間,float4個,double8個位元組。因為需要額外的空間和計算開銷,所以應該儘量只在對小數進行精確計算的時候才使用decimal——比如財務資料,當然也可以將小數放大適當倍數轉為整數用bigint來儲存。

字串型別

1.char和varchar

varchar可變長度,需要1個或2個額外位元組記錄字串長度,小於等於225位元組是,使用1個位元組,否則2個位元組。比如varchar(10)需要11個位元組的儲存空間,varchar(1000)需要1002個。varchar節省了儲存空間,所以對效能也有幫助。

char固定長度,適合儲存很短的字串,或者所有值都接近同一個長度。例如,char非常適合儲存MD5值,因為它是一個定長的值。

2.blog和text

blog和text都是為儲存很大的 資料而設計的字串型別。blog採用二進位制儲存,沒有排序規則或字符集,text採用字元方式儲存,有排序規則和字符集

實際上,它們分別屬於兩組不同的資料型別家族:字元型別是tinytext,smalltext,text,mediumtext,longtext;對應的二進位制型別tinyblog,smallblog,blog,mediumblog,longblog。blog和smallblog是同義詞,text和smalltext是同義詞。

MySQL對blog和text列進行排序與其他型別不同:它只對最前max_sort_lenght位元組而不是整個字串做排序。

3.使用列舉enum代替字串型別(慎用)

有時候可以使用列舉型別代替常用的字串型別,比如性別、國家、民族等。MySQL儲存列舉是非常緊湊,會根據列值壓縮到一個或者兩個位元組中MySQL在內部會將每個值在列表中的位置保持為整數,並且在的.frm檔案中儲存“數字-字串”對映關係的“查詢表”。

列舉最不好的地方是字串列表是固定的,新增或刪除字串必須使用alter table,對於未來可能會改變的字串,使用列舉不是個好主意

日期和時間型別

1.datetime

能儲存大範圍的值,從1001到9999年,精度為秒,與時區無關,使用8位元組儲存空間

1.timestamp
儲存了從1970年1月1日午夜(格林尼治標準時間)以來的秒數,它和Unix時間戳相同。依賴時區,只使用4個位元組的儲存空間,因此範圍比datetime小的多:1970年到2038年。與其他資料型別不一樣,timestamp預設為not null

同時需要注意的是,由於在多個時區儲存或訪問資料造成時間不一致的問題。

關於alert table

alter table效能對於大表來說是個很大問題。MySQL執行大部分修改表結構的操作的方法是用新的結構建立一個空表,從舊錶中查出所有資料插入新表,然後刪除舊錶。如果記憶體不足而表有很大,而且還有很多索引,alert table可能花數個小時甚至數天才能完成。解決這個問題有兩個技巧:

1.先在一臺不提供服務的機器上執行alter table操作,然後和提供服務的主庫進行切換

2.“影子拷貝”,用要求的結構建立一張和原表無關聯的新表,然後通過重新命名和刪表操作交換兩張表。有很多工具可以幫我們完成這件事,不詳細介紹。

相關推薦

MySQL優化系列資料庫schema設計優化

前言 MySQL優化有兩大層面,第一是資料庫層面,第二是硬體層面。資料庫層面可以細分為以下幾個方面: 鎖策略優化 儲存引擎優化 伺服器配置優化 主從,讀寫分離 叢集,負載均衡 本文講解資料庫schema設計優化 高效的模型設計 適度冗餘(反

Mysql資料庫優化系列(五)------索引優化策略面試題

實驗: Type:range   此處使用上了範圍索引 Key_len:12/3=4列 使用到了索引c1,c2,c3,c4.解析:因為order by c3是有序的,所以c3,c4也用到了索引 上圖用到了c1,c2,c3,order by有序,可以利用索引。 上圖

Mysql優化系列數據類型優化

時間 條件參數 字符串存儲 更新 最小數 () col 其中 長度   本篇是優化系列的第一篇:數據類型   為了不產生贅述,盡量用簡潔的語言來描述。   在選擇數據類型之前,首先要知道幾個原則: 更小的通常更好   盡量使用可以正確存儲數據的最小數據類型。更小的數據類

Mysql SQL優化系列——執行計劃連線方式淺釋

關係庫SQL調優中,雖然思路都是一樣的,具體方法和步驟也是大同小異,但細節卻不容忽視,尤其是執行計劃的具體細節的解讀中,各關係庫確實有區別,特別是mysql資料庫,與其他關係庫的差別更大些,下面,我們僅就SQL執行計劃中最常見的連線方式,做以下簡要介紹和說明。 system : a syst

Mysql優化系列——優化器對子查詢的處理

根據子查詢的型別和位置不同,mysql優化器會對查詢語句中的子查詢採取不同的處理策略,其中包括改寫為連線(join),改寫為半連線(semi-join)及進行物化處理等。 標量子查詢(Scalar Subquery):查詢語句中的標量子查詢每次只返回一行資料,執行期間優化器能將其優化掉並對其進行

提交訂單效能優化系列002-引入自己編寫的資料庫連線池

資料庫連線池對效能的影響 總是在各種地方看到類似的說明:“資料庫連線池是非常昂貴的資源。” 那麼請問“非常昂貴”到底是有多昂貴呢? 在我的機器上的測試結果是:從資料庫獲取一個連線的平均耗時大

mysql 優化系列欄位型別選取

mysql  優化是一個很有意思的話題,可以從很多方面來說,大到伺服器叢集,應用體系架構等,小到欄位型別選擇,儲存引擎的選擇等,隨著mysql的發展,到目前(最新版本是8.0,筆者5.7)Innodb 已是預設的儲存引擎(mysql 5.5 已將InnoDB作為預設儲存引擎)

提交訂單效能優化系列011-放棄java同步,引入資料庫修改行數來驗證庫存

概括總結 既然Java同步之後,效能這麼差,那麼有沒有辦法可以不使用Java同步呢?有的,那就是利用資料庫修改的行數來驗證庫存。另外,假設現在庫存是10,需要減少1,推薦的做法是update Goods set stock=stock-1,而不是update

提交訂單效能優化系列017-資料庫ID為int(10)型別與long(20)型別的對比

概括總結 int(10)型別的效能比long(20)型別的效能好4.01%(差別不明顯)。 017版本更新說明 這一版本有兩個SQL檔案: 另外一個比較重要的改動是,之前的版本是測試10次,然後

MySQL優化系列(一)--查詢優化(1)(非索引設計

一、明確搜尋優化的整體思路以及查詢優化的因素: (1)搜尋優化的整體思路: 索引優化,查詢優化,查詢快取,伺服器設定優化,作業系統和硬體優化,應用層面優化(web伺服器,快取)等等。對於一個整體專案而言只有這些齊頭並進,才能實現mysql高效能。 (2)查詢優化的因素思路:

MySQL資料庫系列資料庫設計原則

MySQL中資料庫設計原則: 1.一般情況下,應該儘量使用可以正確儲存資料的最小資料型別。資料型別不一樣,儲存的執行效率也不一樣。最好使用適度的整型資料型別,例如int之類的資料,這樣在做查詢或者欄位

MySQL優化系列(二)--查詢優化(1)(非索引設計

接下來這篇是查詢優化,使用者80%的操作基本都在查詢,我們有什麼理由不去優化他呢??所以這篇部落格將會講解大量的查詢優化(索引以及庫表結構優化等高階用法後面文章再講),先講單表查優化,再講多表查優化。

MySQL效能優化資料庫結構優化

1.選擇合適資料型別 1.1.使用可以儲存你資料型別的最小資料型別。 1.2.使用簡單的資料型別。 1.3.儘量使用NOT NULL定義欄位。 1.4.儘量少用大的型別(text),非用不可使用從表拆分出來。 1.5.例子: 1.5.1.利用Int型別儲存日期型別:利用F

.net core實踐系列簡訊服務-架構優化

前言 通過前面的幾篇文章,講解了一個簡訊服務的架構設計與實現。然而初始方案並非100%完美的,我們仍可以對該架構做一些優化與調整。 同時我也希望通過這篇文章與大家分享一下,我的架構設計理念。 原始碼地址:https://github.com/SkyChenSky/Sikiro.SMS/tree/opti

圖解算法系列插入排序(優化版)

(1)演算法描述 對於給定的一個線性空間,遍歷考察每一個元素,將當前元素拷貝一份,並將前一個元素拷貝到當前元素的原位置。拷貝出來的元素與前一個元素進行比較,如果滿足前一個元素大於或小於當前元素就將當前拷貝出來的元素放到當前位置,否則繼續向前比較。 (2)圖解演算法 (3)C/C++程式碼實現

提交訂單效能優化系列003-測試阿里巴巴的druid資料來源

概括總結 使用druid資料來源之後,相對於第002版自己隨手寫的資料庫,效能反而下降了8.49%。原因在於,002版是“隨手”寫的,因此功能非常簡陋,要什麼沒什麼,只能從記憶體中獲取連線,因此很快。

提交訂單效能優化系列004-測試hikari資料來源

概括總結 使用hikari資料來源之後,相對於第003版的druid資料來源,從提交訂單這個複雜的操作上來說,效能提升了17.79%。而從獲取資料庫連線這一簡單的操作上來說,hikari比druid優秀幾百倍。 004版本更新說明 pom.xml檔案中

提交訂單效能優化系列006-普通的Thread多執行緒改為Java8的parallelStream併發流

概括總結 Java8的parallelStream併發流能達到跟多執行緒類似的效果,但它也不是什麼善茬,為了得到跟上一版本的多執行緒類似的效果,一改再改,雖然最後改出來了,但是還是存在理解不了的地方。

圖解算法系列氣泡排序(優化版)

演算法描述 在第一層迴圈中設定一個變數,只要該序列區域性有序就不需要進行排序了,提前終止迴圈。 圖解演算法 略. C/C++程式碼實現 Custom.h void BubbleSortAdvanced(int arr[], int number); Custom.cpp v

圖解算法系列冒泡排序(優化版)

bool 算法系列 num block 代碼 als lean 設置 復雜 算法描述 在第一層循環中設置一個變量,只要該序列局部有序就不需要進行排序了,提前終止循環。 圖解算法 略. C/C++代碼實現 Custom.h void BubbleSortAdvanced(