【mysql-innodb優化】-schema優化

首先是優化的幾大原則。
1、更小的通常更好,使用更小的數據類型進行存儲通常可以更快,因爲使用更少的cpu,IO,內存。但是要確定好你要存儲的值的範圍是數據類型能夠的存儲的範圍。
2、簡單就好,例如整型的數據比字符操作往往代價會更低。比如使用mysql的內建類型存儲日期,date,datetime等,不使用varchar。比如用整型存儲IP地址而不是使用varchar之類的。
3、儘量避免使用NULL,NULL對mysql來說很難優化,除非你真的需要存儲null,否則儘量避免使用null。尤其是在你準備建立索引的列上。



下面來看看怎麼爲一個列選擇一個數據類型:
1、第一步需要確定需要存儲的數據的大類型: 數字,字符串,時間等。這通常很簡單。
2、第二部是選擇具體的類型,很多mysql的數據類型都可以存儲相同的數據。只是遁出的長度和方位不一樣,允許的精度不同,或者需要的磁盤和內存空間不同。相同大類型的不同子類型數據有時也有一些特殊的行爲和屬性。

下面我們來具體看看數據類型的選擇:
1、整數類型, tinyint(1字節), smallint(2字節), mediuint(3字節),int(4字節),bigint(8字節)。整數類型可選的選項有UNSIGNED,表示不允許負值。
對於存儲計算來說int(1)和int(11)是沒有區別的,佔用的磁盤空間是一樣的,只是mysql用來展示的時候的區別而已。
2、實數類型,實數類型是指帶有小數部分的數字。個人建議還是存儲整數吧,瞭解計算機存儲小數的原理的童鞋應該清楚,小數在計算機中的存儲是會丟失精度的。實數類型的存儲有double,float,decimal, 你可以使用整數類型存儲,展示給前端的時候做一個除法即可。比如價格爲11.29元,數據存儲中可以使用1129,單位是分。
3、字符串類型。varchar和char類型。是字符串存儲的主要存儲方式。
     varchar類型,varchar類型是變長的類型,字符串需要多少存儲空間,實際就佔用多少磁盤空間,但是在磁盤中需要存儲額外的長度。varchar類型節省了存儲空間對性能也會有幫助,但是如果是一個經常需要update的列,update的字符串長度比之前的字符串長度更長,就會導致一些問題了, 仔細想想其實不難發現,更長的字符串的原本的磁盤上是無法存儲的,沒有足夠的空間。因此可能會造成頁的分裂等等複雜的操作。而如果update的字符串長度比之前的長度更短了,那麼就會浪費掉一部分存儲空間,個人感覺問題不大。在innodb中,過長的varchar會被存儲爲blob。
     char類型,char類型是變長的類型。在磁盤中,如果存儲的字符串長度不夠則會在末尾補充空格。,char類型適合存儲比較段的字符串或者所有的值都接近一個長度,比較短的字符串不會造成過多的磁盤空間浪費,長度接近的字符串也不會造成磁盤空間的浪費。比如char類型適合存儲身份證號碼,手機號碼,md5格式化的密碼等,char類型也不容易產生磁盤碎片,對於經常變更的列,而長度又比較短或者長度接近,使用char作爲存儲類型比使用varchar要更叫高效。比如,存儲Y和N兩種字符,使用char只需要一個字節,而使用varchar需要兩個字節,因爲還需要一個額外的字節存儲長度。
     還有一些不常用的二進制字符串存儲,比如binary,varbinary,不作討論.
     blob,text類型,存儲較大的字符串使用。text使用的字符類型存儲數據,分別有tinytext,smalltext,mediutext,text,bigtext;對應的二進制存儲爲tinyblob,smallblob,mediublob,blob,bigblob。當字符串的值太大時,此時一個值在一條記錄的磁盤存儲內需要1-4個字節存儲一個文件指針,指向一個外部區域,而這個外部區域就是存儲真正的數據的地方。blob和text之間僅有的不同是,blob是存儲的二進制數據,而text存儲的是字符數據,所以也就是說blob沒有字符集的區分。
4、枚舉類型     enum
     有時候可以使用枚舉類型來優化字符串的存儲,因爲mysql並不會在行記錄磁盤中真正的存儲字符串的內容,而是會存儲一個映射的值,這就類似於壓縮。 比如enum('aaa', 'bbb','ccc'),那麼真正存儲的可能是1,2,3. 然後做一個映射
     [
          1     =>     'aaa',
          2     =>     'bbb',
          3     =>     'ccc'
     ]
這個值是存儲在表結構定義文件中的,就是.frm結尾的文件。

5、日期和時間類型的選擇
datetime,保存大範圍的值,從1001年-9999年,精度爲秒。它把日期和時間封裝到格式爲YYYYMMDDHHMMSS的整數中,與時區無關。使用8個字節存儲。
timestamp,保存了從1970年1月1日午夜以來的秒數,事實上這就是unix的時間戳,但是由於它的存儲空間只有4個字節,因此在mysql中它只能存儲到2038年。有時候人們會使用整型數據保存時間,但是這不會帶來任何收益,比如你用一個int類型存儲時間,消耗了4個字節,跟timestamp一樣,而且也不會方便你的處理。通常我們都說,能用lib庫函數的就不要自己寫了,不要以爲自己寫的會比別人的更高效,應該就是這個道理吧。如果有時間我們的時間要存儲到微妙的話,那就只能用bigint了。

6、位數據類型 bit set
總的來說,位數據類型都是爲了節省空間,使得數據的存儲更加的緊湊,但是就像我們經常說的互聯網一直在追求一個IO/CPU之間的平衡。這種類型用的比較少,通常存在於只有兩種值的場景,比如存儲性別,對錯等等。使用這種類型需要謹慎或者儘量避免,畢竟現在的磁盤不需要你這麼節約的去使用。下面看看一個例子,比如說我們存儲一個數字 57 進入,使用的是bit(8),那麼當你讀取的時候讀取來的是 57對應的ASCII碼字符 ‘9’,這是因爲innodb默認認爲存儲的是字符串而不是數字.所以要存儲57這個數字的話,只能先把57轉換成ASCII碼的形式。set我沒用到過,不講。



接下來我們看看錶結構設計中的一些陷阱
     1、太多的字段。mysql的存儲引擎API工作時需要在服務器層和存儲引擎層之間通過行緩衝的格式拷貝數據,然後在服務器層將緩衝內容解碼成各個字段的內容,這個轉換的代碼相對來說是比較高的,如果僅僅只是定長結構還好,但是對於變長結構來說往往意味着多幾次IO和CPU操作。所以,如果你的表中有幾千個字段,不要以爲你只查詢了幾個字段就沒有問題了,因爲在實際轉換中仍然是轉換了幾千個字段,只是有一些你沒用到。
     2、太多的關聯。
     3、枚舉的數量太多
     4、變相的枚舉,使用set
     5、用一些很奇怪的值表示null。
          比如產品類型, 用1=》電器,2=》生活用品,3=》其他品。 用-1表示未知的類型,那麼這個-1就可能導致代碼更加複雜, 用0表示未知顯然更好。


最後我們來看看一些表結構的常用優化手段
     1、適當的冗餘信息,
     2、非精確的查詢(定時收集數據)而不是每次全表掃描。
     總得來說常用的優化手段就是保證mysql能夠快速讀取,比如犧牲寫的速度(添加索引就會降低寫的速度)




alter table操作。
alter table操作的性能對大表來說是個大問題,mysql執行大部分alter操作都是創建一個新的表,從舊錶中查出所有的數據插入新表,然後刪除舊錶,這樣的操作可能需要花費很長的時間,如果內存不足而表又很大,而且還有索引的情況下,可能需要花費很長的時間,幾個小時甚至幾天。一般而言,大部分的alter table操作將會導致mysql服務終端,因爲它會鎖表。
     對於alter table操作的優化只有以下幾種。
          1、先在一臺不提供服務的機器上執行alter table操作,然後進行主從切換。
          2、另外一種是 “影子拷貝”,影子拷貝是手動創建一張新表,然後通過重命名和刪表操作進行切換(這裏數據實時同步的問題我不太清楚是如何解決的)。
          3、對於一些對現有數據沒有影響的操作可以直接修改.frm文件中的表結構,比如  not null default 3 改成 not null default 5,那麼就無需使用alter進行整個表的重建。比如alter column修改列的名稱而不修改數據等操作。具體的替換操作舉例如下:     
               a、創建一張具有相同表結構的空表,並進行所有的修改。
               b、執行flush table with read lock,給表上鎖,停止服務。
               c、交換.frm文件。
               d、執行UNLOCK TABLES釋放鎖。



總結:
     1、儘量避免複雜的表結構設計
     2、根據你需要存儲的數據選擇正確的數據類型
     3、儘量避免使用null
     4、在關聯中儘量使用相同的數據類型,比如varchar和enum的關聯就儘量避免。
     5、儘量使用整型標識一個列,比如ID 爲int類型。
     6、儘量不要使用mysql已經遺棄的特性,比如double,float等
     7、小心使用enmu,雖然很方便,但是有時候是陷阱。
     8、儘量避免使用bit,除非你的磁盤空間真的不夠用了。
     7、注意可變的長字符串,比如text類型的字符串,他們在排序時讀入內存可能會導致悲觀的按照最大長度分配內存。













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