MySQL優化(表結構和系統配置優化)
在前一篇文章中,我總結了關於mysql優化中的sql以及索引的優化,文章見sql以及索引的優化
一,表結構優化
對於數據庫表的設計,通常需要根據具體的業務流程畫出E-R圖,確定每個表中基本的字段,然後確定表和表之間的關係,下面是對錶的設計優化的一些簡單總結:
1.選擇合適的數據類型
表設計的第一步肯定是設計出這張表的基本的字段,關於表字段設計的基本規約如下:
- 一張表必須有一個唯一主鍵(一般是無符號數自增,或者是經過特定算法生成的唯一數或字符串)
- 記錄的創建時間,字段名:gmt_create,類型:datetime
- 記錄的更新時間,字段名:gmt_modify,類型:datetime
下邊是具體業務字段的定義,我們需要爲這些字段選擇合適的數據類型:
- 使用可存下數據的最小的數據類型
- 使用簡單的數據類型,int要比varchar在mysql處理上更簡單
- 儘可能使用not null定義字段,這是innodb的特性決定的,因爲非 not null的數據可能需要一些額外的字段進行存儲,這樣會增加一些IO
- 儘量少用text,非用不可最好分表,將text字段存放在另一張表,在需要的時候在使用聯合查詢,這樣可以提高查詢主表的效率
示例1:
使用int 存儲日期時間,利用下邊兩個函數完成轉換
select FROM_UNIXTIME(1392178320);#將int類型時間戳轉換爲時間格式
SELECT UNIX_TIMESTAMP(2014-02-12 12:12:00);#將時間格式轉換爲int
結果:
示例2:
使用bigint存儲ip地址,利用下邊兩個函數完成轉換
select INET_ATON('192.168.1.1');
select INET_NTOA('3232235777');
2.表的垂直拆分
所謂表的垂直拆分就是把原來一個有很多列的表拆分成多個表來解決表的寬度問題
拆分原則:
- 把不常用的字段單獨放在一個表中
- 把大字段獨立放在一個表中
- 把經常一起使用的字段放到一起
比如:現在有一張學生表tb_stu已經確定需要11個字段:
學生號,姓名,年齡,性別,所在年級,所在班級,興趣愛好,檔案簡歷,創建時間,修改時間
-
這些字段中,經常需要被查詢的數據有
學生號,姓名,年齡,性別,所在年級,所在班級
-
不常用字段有
興趣愛好,檔案簡歷
並且這兩個字段很可能要採用blog或者text類型,每次查詢都需要去獲取這些數據的話會給查詢帶來效率問題
把常用和不常用字段分出來後,我們開始將tb_stu進行切分
我們新建一張表tb_stu_info,字段有:學生號,興趣愛好,檔案簡歷,創建時間,修改時間
原來的tb_stu保留這些字段: 學生號,姓名,年齡,性別,所在年級,所在班級,創建時間,修改時間
當需要查詢完整的學生信息時可以使用關聯查詢:
select * from tb_stu s1 left outer join tb_info s2 on s1.id = s2.id
3.表的水平拆分
爲什麼進行水平拆分?
- 表的垂直拆分:將表中的不常用的列和大字段的列拆分到另外一個表或者多個表中,減少表的寬度;
- 表的水平拆分:主要是解決數據量過大的問題,水平拆分每個表的表結構都是完全一致的(當單表的數據大於一億時,儘管加了索引,還是會比較慢);
表的水平拆分:
常用的方法是:hash取模拆分
1、對大表的主鍵id值進行hash運算,比如要拆分爲5張表,可以使用mod(主鍵id,5)取出0-4個值
2、針對不同的hashID把數據存到不同的表中。
二,系統配置優化
1.開啓數據庫緩存
先看看緩存是否開啓
SELECT @@QUERY_CACHE_TYPE
現在開啓緩存
SET @@QUERY_CACHE_TYPE = ON;
注意:寫入頻繁的數據庫,不要開查詢緩存
2.操作系統配置優化
引用: https://blog.csdn.net/liuxuli232/article/details/81354665
#默認爲256KB
# Sort_Buffer_Size 是一個connection級參數,在每個connection(session)第一次需要使用這個buffer的時候,一次性分配設置的內存。
#Sort_Buffer_Size 並不是越大越好,由於是connection級的參數,過大的設置+高併發可能會耗盡系統內存資源。例如:500個連接將會消耗 500*sort_buffer_size(8M)=4G內存
#Sort_Buffer_Size 超過2KB的時候,就會使用mmap() 而不是 malloc() 來進行內存分配,導致效率降低。
sort_buffer_size = 4M
#默認爲256K
#用於表間關聯緩存的大小,和sort_buffer_size一樣,該參數對應的分配內存也是每個連接獨享。
#如果應用中,很少出現join語句,則可以不用太在乎join_buffer_size參數的設置大小。
#如果join語句不是很少的話,個人建議可以適當增大join_buffer_size到1MB左右,如果內存充足可以設置爲2MB
join_buffer_size = 2M
#默認爲18
thread_cache_size = 512
#默認值爲1M
query_cache_size = 32M
#默認1M
query_cache_limit = 2M
#默認是8M
#當自動擴展表空間被填滿之時,爲擴展而增加的尺寸(MB爲單位)
# mysql 5.6.5版本之前默認值是8Mb,從5.6.6版本之後默認爲64Mb,最小值爲1Mb最大值爲1000Mb。
#這個參數受到innodb_file_per_table參數的影響
innodb_autoextend_increment = 256
#默認4M
max_allowed_packet = 100M
#使用LOCK TABLES雖然可以給InnoDB加表級鎖,但必須說明的是,表鎖不是由InnoDB存儲引擎層管理的,而是由其上一層──MySQL Server負責的,僅當autocommit=0、innodb_table_locks=1(默認設置)InnoDB層才能知道MySQL加的表鎖,MySQL Server也才能感知InnoDB加的行鎖,這種情況下,InnoDB才能自動識別涉及表級鎖的死鎖;否則,InnoDB將無法自動檢測並處理這種死鎖。
#如果autocommit=1,Innodb的內部表鎖可能會導致deadlock,可以通過設置innodb_table_locks=0來解決這個問題
innodb_table_locks = 0
#默認爲8M
#InnoDB 用來高速緩衝數據和索引內存緩衝大小
#InnoDB最重要的設置,對InnoDB性能有決定性的影響
#可以設置60-80%的內存
innodb_buffer_pool_size = 16G(此參數爲解決問題的關鍵,最初有的統計報表打開需要十幾秒,此參數調整後,最多兩三秒就打開了)
innodb_read_io_threads = 6 #讀線程數
innodb_write_io_threads = 6 #寫線程數
innodb_log_buffer_size = 48M #默認爲16M
#當事務提交時,保存髒數據到內存中,後續再刷新保存到磁盤
#適當調整此參數大小,可以減少磁盤I/O