MySQL性能優化(二):優化數據庫的設計


數據庫設計java


數據庫命名:數據庫名的命名通常和項目的名稱保持一致,不要隨意的起名字。mysql

數據庫編碼:  儘可能採用utf8mb4而不使用utf8。MySQL 的「utf8」實際上不是真正的UTF-8,真正的UTF-8是每一個字符最多四個字節,而MySQL的「utf8」只支持每一個字符最多三個字節。sql

表的設計數據庫


數據庫表結構的設計是最基礎也是最重要的,由於一旦數據庫表設計完畢並投入使用,未來再進行修改就相對比較麻煩,特別數據量大時增長字段修改字段類型都比較麻煩,所以在進行數據庫設計的時候必定要儘量的考慮周到。緩存


數據庫表設計要遵照以下原則:數據結構


表名

  • 表的命名通常遵照 「業務名稱 _ 表名「或者是「項目名_ 表名「的格式,對於業務名稱通常都是簡寫,不全拼,全拼表名會太長,如sys_user(系統模塊對應的用戶表),對於一些公用的可使用tbl(table簡寫)做爲模塊名,如字典表 tbl_dictionary。併發

  • 表名不使用複數形式,表名應該僅僅表示表裏面的實體內容,不該該表示實體數量。如sys_user不要命名爲sys_users。數據庫設計

  • 爲何要使用前綴?若是多個項目都使用同一個數據庫的話,能夠防止命名衝突,例如用戶表,若是沒有設置前綴,估計你們都會命名爲user,其它項目要使用這個名字就衝突了,爲了解決這種問題,能夠在表名上增長一個前綴,前綴爲項目名稱,如xxx_user, yyy_user這樣就解決了這種命名衝突問題。
    ide

  • 在比較複雜的系統中,經過表名前綴能夠大概瞭解到表所在的模塊,相同的業務表是在一塊兒的,這樣作平常開發和看的時候會比較方便,新人瞭解系統數據結構的時候也有章可循。高併發


字段名

  • MySQL 在 Windows 下不區分大小寫,但在 Linux 下默認是區分大小寫。所以,數據庫名、 表名、字段名,最好都統一爲小寫字母,避免節外生枝。爲了便於肉眼識別表名,通常建議表名爲小寫字母。

  • 通常全部表都要有id, id必爲主鍵,類型爲bigint unsigned,單表時自增、步長爲1; 有些特殊場景下(如在高併發的狀況下該字段的自增可能對效率有比價大的影響)。

  • 通常狀況下主鍵id和業務不要緊的,例如訂單號不是主鍵id,通常是訂單表中的其餘字段,通常訂單號order_code爲字符類型。

  • 通常狀況下每張表都有着四個字段create_id,create_time,update_id,update_time, 其中create_id表示建立者id,create_time表示建立時間,update_id表示更新者id,update_time表示更是時間,這四個字段的做用是爲了可以追蹤數據的來源和修改。

  • 最好不要使用備用字段(我的觀點), 禁用保留字,如 desc、range、match、delayed 等。

  • 表達是與否概念的字段,必須使用 is_xxx 的方式命名,數據類型是 unsigned tinyint (1 表示是,0 表示否), 任何字段若是爲非負數,必須是unsigned。表達邏輯刪除的字段名 is_deleted,1 表示刪除,0 表示未刪除。

  • 若是某個值能經過其餘字段能計算出來就不須要用個字段來存儲,減小存儲的數據。

  • 爲了提升查詢效率,能夠適當的數據冗餘,注意是適當。

  • 強烈建議不使用外鍵, 數據的完整性靠程序來保證。

  • 單條記錄大小禁止超過8k, 一方面字段不要太多,有的都能上百,甚至幾百個,另外一方面字段的內容不易過大像文章內容等這種超長內容的須要單獨存到另外一張表中。


字段的數據類型

不一樣的數據類型搜索的方式不一樣,因此說要選擇合適的數據類型。用盡可能少的存儲空間來存數一個字段的數據, 縮小存儲空間換取查詢時間,能用int的就不用char或者varchar,能用tinyint的就不用int,使用UNSIGNED存儲非負數值,其中無符號值能夠避免誤存負數,且擴大了表示範圍。合適的字符存儲長度,不但節約數據庫表的存儲空間、節約索引存儲,更重要的是提高檢索速度。儘可能使用數字型字段,提升數據比對效率。

①字符類型

  • char是固定長度的字符類型,它的處理速度比varchar快,缺點是浪費存儲空間,當實際存儲的值小於指定的長度時會以空格來填充,對於長度變化不大而且對查詢速度有較高的要求能夠選擇char。適合存儲用戶密碼的MD5哈希值,手機號,性別,由於它的長度老是同樣的。對於常常改變的值,char也好於varchar,由於固定長度的行不容易產生碎片,對於很短的列,char的效率也高於varchar。char(1)字符串對於單字節字符集只會佔用一個字節,可是varchar(1)則會佔用2個字節,由於1個字節用來存儲長度信息 。若是存儲的字符串長度幾乎相等,使用char定長字符串類型。

  • varchar是可變長字符串,不預先分配存儲空間,長度不要超過 5000,若是存儲長度大於此值,定義字段類型爲 text,獨立出來一張表,用主鍵來對應,避免影響其它字段索引效率。varchar的長度是字符長度,而不是字節長度。varchar還會使用額外的存儲空間來記錄可變字符串的長度

    • 列的最大長度小於255則只須要額外佔用一個字節來記錄字符串的長度

    • 列的最大長度大於255則須要額外佔用兩個字節來記錄字符串的長度

  • 不一樣存儲引擎對char和varchar的使用原則不一樣,myisam:建議使用國定長度的數據列代替可變長度。innodb:建議使用varchar,大部分表都是使用innodb,因此varchar的使用頻率更高

②數值類型

  • 選用合適的長度很是重要,能用tinyint就不用integer

  • 金額類型的字段儘可能使用long用分表示,儘可能不要使用bigdecimal,嚴謹使用float和double由於計算時會丟失經度

  • 若是須要使用小數嚴謹使用float,double,使用定點數decimal,decimal其實是以字符串的形式存儲的,因此更加精確,java中與之對應的數據類型爲BigDecimal

  • 若是值爲非負數,必定要使用unsigned,無符號不只能防止負數非法數據的保存,並且還能增大存儲的範圍

  • 不建議使用ENUM、SET類型,使用TINYINT來代替

是否爲NULL

MySQL字段屬性應該儘可能設置爲NOT NULL,除非你有一個很特別的緣由去使用 NULL 值,你應該老是讓你的字段保持 NOT NULL,對於沒有值的指定一個默認值,如以前使用null的varchar能夠默認爲空字符串「」,以前是數字類型的能夠用0作爲默認值 。

  • 在MySQL中NULL實際上是佔用空間的,「可空列須要更多的存儲空間」:須要一個額外字節做爲判斷是否爲NULL的標誌位「須要mysql內部進行特殊處理」, 而空值""是不佔用空間的。

  • 含有空值的列很難進行查詢優化,並且對錶索引時不會存儲NULL值的,因此若是索引的字段能夠爲NULL,索引的效率會降低不少。由於它們使得索引、索引的統計信息以及比較運算更加複雜。你應該用0、一個特殊的值或者一個空串代替null。

  • 聯表查詢的時候,例如SELECT user.username, info.introduction FROM tbl_user user LEFT JOIN tbl_userinfo info ON user.id = info.user_id; 若是tbl_userinfo.introduction設置的能夠爲null, 假如這條sql查詢出了對應的記錄,可是username有值,introduction沒有值,那麼就不是很清楚這個introduction是沒有關聯到對應的記錄,仍是關聯上了而這個值爲null,null意思表示不明確,有歧義

存儲引擎


經常使用的存儲引擎的選擇有MYISAM、InnoDB、MEMORY,不一樣的存儲引擎支持的功能不同,MySQL5.5以後默認的是InnoDB。絕大部分場景都是使用InnoDB引擎。

  • MYISAM 不支持事務, 不支持外鍵,其優點是訪問速度快,對事務完整性沒有要求或者以select、insert爲主的應用程序能夠選擇這個引擎,支持全文索引,表鎖,注意:MYISAM 在刪除數據時好像相似於邏輯刪除,須要定時物理刪除,清理碎片:optimize table 名稱;

  • InnoDB 支持事務,不支持全文索引,標鎖,支持外鍵

  • MEMORY:查詢速度極快,數據在內存中不持久化,數據庫重啓數據就消失,相似於緩存的做用memcache

表引擎取決於實際應用場景;日誌及報表類這種只涉及到插入和查詢而且查詢操做更多的建議用myisam;對事務要求高的使用innodb引擎。


建議:不要混合使用存儲引擎,實際場景中會有MyISAM和InnoDB混合使用的狀況,可是這樣有問題,好比一個事務同時操做了myisam引擎的表和innodb引擎的表,而myisam是不支持事務的,就會形成myisam表沒有回滾。如今開發中絕大部分都是使用InnoDB,也不常常見到myisam,至少我工做中沒見到過。

圖片

圖片

圖片

相關文章
相關標籤/搜索