Mysql優化方案

表的設計階段:

字段


  • 儘量使用TINYINT、SMALLINT、MEDIUM_INT作爲整數類型而非INT,如果非負則加上UNSIGNED


  • VARCHAR的長度只分配真正需要的空間


  • 使用枚舉或整數代替字符串類型


  • 儘量使用TIMESTAMP而非DATETIME,


  • 單表不要有太多字段,建議在20以內


  • 避免使用NULL字段,很難查詢優化且佔用額外索引空間


  • 用整型來存IP


索引


  • 索引並不是越多越好,要根據查詢有針對性的創建,考慮在WHERE和ORDER BY命令上涉及的列建立索引,可根據EXPLAIN來查看是否用了索引還是全表掃描


  • 應儘量避免在WHERE子句中對字段進行NULL值判斷,否則將導致引擎放棄使用索引而進行全表掃描


  • 值分佈很稀少的字段不適合建索引,例如”性別”這種只有兩三個值的字段


  • 字符字段只建前綴索引


  • 字符字段最好不要做主鍵


  • 不用外鍵,由程序保證約束


  • 儘量不用UNIQUE,由程序保證約束


  • 使用多列索引時主意順序和查詢條件保持一致,同時刪除不必要的單列索引

表的使用階段:

查詢SQL

  • 可通過開啓慢查詢日誌來找出較慢的SQL


  • 不做列運算:SELECT id WHERE age + 1 = 10,任何對列的操作都將導致表掃描,它包括數據庫教程函數、計算表達式等等,查詢時要儘可能將操作移至等號右邊


  • sql語句儘可能簡單:一條sql只能在一個cpu運算;大語句拆小語句,減少鎖時間;一條大sql可以堵死整個庫


  • 不用SELECT *


  • OR改寫成IN:OR的效率是n級別,IN的效率是log(n)級別,in的個數建議控制在200以內


  • 不用函數和觸發器,在應用程序實現


  • 避免%xxx式查詢


  • 少用JOIN


  • 使用同類型進行比較,比如用'123'和'123'比,123和123比


  • 儘量避免在WHERE子句中使用 != 或 <> 操作符,否則將引擎放棄使用索引而進行全表掃描


  • 對於連續數值,使用BETWEEN不用IN:SELECT id FROM t WHERE num BETWEEN 1 AND 5


  • 列表數據不要拿全表,要使用LIMIT來分頁,每頁數量也不要太大

一、選擇優化的數據類型


MySQL支持的數據類型非常多, 選擇正確的數據類型對於獲得高性能至關重要。


更小的通常更好


更小的數據類型通常更快, 因爲它們佔用更少的磁盤、 內存和CPU緩存, 並且處理時需要的CPU週期也更少。


簡單就好


簡單數據類型的操作通常需要更少的CPU週期。 例如, 整型比字符操作代價更低, 因爲字符集和校對規則(排序規則 )使字符比較比整型比較更復雜。


儘量避免NULL


如果查詢中包含可爲NULL 的列, 對MySQL來說更難優化, 因爲可爲NULL 的列使得索引、 索引統計和值比較都更復雜。 可爲NULL的列會使用更多的存儲空間, 在MySQL裏也需要特殊處理。 當可爲NULL的列被索引時, 每個索引記錄需要一個額外的字節, 在MyISAM裏甚至還可能導致固定大小的索引(例如只有一個整數列的索引)變成可變大小的索引。


當然也有例外, 例如InnoDB 使用單獨的位 (bit) 存儲NULL值, 所以對於稀疏數據有很好的空間效率。


1.整數類型


有兩種類型的數字:整數 (whole number) 和實數 (real number) 。 如果存儲整數, 可以使用這幾種整數類型:TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT。分別使用8,16, 24, 32, 64位存儲空間。


整數類型有可選的 **UNSIGNED ** 屬性,表示不允許負值,這大致可以使正數的上限提高一倍。 例如 TINYINT. UNSIGNED 可以存儲的範圍是 0 – 255, 而 TINYINT 的存儲範圍是 -128 -127 。


有符號和無符號類型使用相同的存儲空間,並具有相同的性能 , 因此可以根據實際情況選擇合適的類型。


你的選擇決定 MySQL 是怎麼在內存和磁盤中保存數據的。 然而, 整數計算一般使用64 位的 BIGINT 整數, 即使在 32 位環境也是如此。( 一些聚合函數是例外, 它們使用DECIMAL 或 DOUBLE 進行計算)。


MySQL 可以爲整數類型指定寬度, 例如 INT(11), 對大多數應用這是沒有意義的:它不會限制值的合法範圍,只是規定了MySQL 的一些交互工具(例如 MySQL 命令行客戶端)用來顯示字符的個數。 對於存儲和計算來說, INT(1) 和 INT(20) 是相同的。


2.實數類型


實數是帶有小數部分的數字。 然而, 它們不只是爲了存儲小數部分,也可以使用DECIMAL 存儲比 BIGINT 還大的整數。


FLOAT和DOUBLE類型支持使用標準的浮點運算進行近似計算。


DECIMAL類型用於存儲精確的小數。


浮點和DECIMAL類型都可以指定精度。 對於DECIMAL列, 可以指定小數點前後所允許的最大位數。這會影響列的空間消耗。


有多種方法可以指定浮點列所需要的精度, 這會使得MySQL選擇不同的數據類型,或者在存儲時對值進行取捨。 這些精度定義是非標準的,所以我們建議只指定數據類型,不指定精度。


浮點類型在存儲同樣範圍的值時, 通常比DECIMAL使用更少的空間。FLOAT使用4個字節存儲。DOUBLE佔用8個字節,相比FLOAT有更高的精度和更大的範圍。和整數類型一樣, 能選擇的只是存儲類型; MySQL使用DOUBLE作爲內部浮點計算的類型。


因爲需要額外的空間和計算開銷,所以應該儘量只在對小數進行精確計算時才使用DECIMAL。但在數據最比較大的時候, 可以考慮使用BIGINT代替DECIMAL, 將需要存儲的貨幣單位根據小數的位數乘以相應的倍數即可。


3.字符串類型


VARCHAR


用於存儲可變⻓字符串,長度支持到65535
需要使用1或2個額外字節記錄字符串的長度
適合:字符串的最大⻓度比平均⻓度⼤很多;更新很少


CHAR


定長,長度範圍是1~255
適合:存儲很短的字符串,或者所有值接近同一個長度;經常變更


慷慨是不明智的


使用VARCHAR(5)和VARCHAR(200)存儲’hello’的空間開銷是一樣的。 那麼使用更短的列有什麼優勢嗎?


事實證明有很大的優勢。 更長的列會消耗更多的內存, 因爲MySQL通常會分配固定大小的內存塊來保存內部值。 尤其是使用內存臨時表進行排序或操作時會特別糟糕。 在利用磁盤臨時表進行排序時也同樣糟糕。


所以最好的策略是隻分配真正需要的空間。


4.BLOB和TEXT類型


BLOB和 TEXT都是爲存儲很大的數據而設計的字符串數據類型, 分別採用 二進制和字符方式存儲 。


與其他類型不同, MySQL把每個BLOB和TEXT值當作一個獨立的對象處理。 存儲引擎在存儲時通常會做特殊處理。 當BLOB和TEXT值太大時,InnoDB會使用專門的 “外部“存儲區域來進行存儲, 此時每個值在行內需要1 – 4個字節存儲 存儲區域存儲實際的值。


BLOB 和 TEXT 之間僅有的不同是 BLOB 類型存儲的是二進制數據, 沒有排序規則或字符集, 而 TEXT類型有字符集和排序規則


5.日期和時間類型


大部分時間類型都沒有替代品, 因此沒有什麼是最佳選擇的問題。 唯一的問題是保存日期和時間的時候需要做什麼。 MySQL提供兩種相似的日期類型: DATE TIME和 TIMESTAMP。


但是目前我們更建議存儲時間戳的方式,因此該處不再對 DATE TIME和 TIMESTAMP做過多說明。


5.其他類型


5.1選擇標識符


在可以滿足值的範圍的需求, 井且預留未來增長空間的前提下, 應該選擇最小的數據類型。


整數類型


整數通常是標識列最好的選擇, 因爲它們很快並且可以使用AUTO_INCREMENT。


ENUM和SET類型


對於標識列來說,EMUM和SET類型通常是一個糟糕的選擇, 儘管對某些只包含固定狀態或者類型的靜態 ”定義表” 來說可能是沒有問題的。ENUM和SET列適合存儲固定信息, 例如有序的狀態、 產品類型、 人的性別。


字符串類型


如果可能, 應該避免使用字符串類型作爲標識列, 因爲它們很消耗空間, 並且通常比數字類型慢。


對於完全 “隨機” 的字符串也需要多加註意, 例如 MDS() 、 SHAl() 或者 UUID() 產生的字符串。 這些函數生成的新值會任意分佈在很大的空間內, 這會導致 INSERT 以及一些SELECT語句變得很慢。如果存儲 UUID 值, 則應該移除 “-“符號。


5.2特殊類型數據


某些類型的數據井不直接與內置類型一致。 低千秒級精度的時間戳就是一個例子,另一個例子是以個1Pv4地址,人們經常使用VARCHAR(15)列來存儲IP地址,然而, 它們實際上是32位無符號整數, 不是字符串。用小數點將地址分成四段的表示方法只是爲了讓人們閱讀容易。所以應該用無符號整數存儲IP地址。MySQL提供INET_ATON()和INET_NTOA()函數在這兩種表示方法之間轉換。


二、表結構設計


1.範式和反範式


對於任何給定的數據通常都有很多種表示方法, 從完全的範式化到完全的反範式化, 以及兩者的折中。 在範式化的數據庫中, 每個事實數據會出現並且只出現一次。 相反, 在反範式化的數據庫中, 信息是冗餘的, 可能會存儲在多個地方。


範式的優點和缺點


爲性能提升考慮時,經常會被建議對 schema 進行範式化設計,尤其是寫密集的場景。


  • 範式化的更新操作通常比反範式化要快。


  • 當數據較好地範式化時,就只有很少或者沒有重複數據,所以只需要修改更少的數據。


  • 範式化的表通常更小,可以更好地放在內存裏,所以執行操作會更快。


  • 很少有多餘的數據意味着檢索列表數據時更少需要 DISTINCT 或者 GROUP BY語句。


反範式的優點和缺點


不需要關聯表,則對大部分查詢最差的情況——即使表沒有使用索引——是全表掃描。 當數據比內存大時這可能比關聯要快得多,因爲這樣避免了隨機I/0。

單獨的表也能使用更有效的索引策略。


混用範式化和反範式化


在實際應用中經常需要混用,可能使用部分範式化的 schema 、 緩存表,以及其他技巧。


表適當增加冗餘字段,如性能優先,但會增加複雜度。可避免表關聯查詢。


簡單熟悉數據庫範式


第一範式(1NF):字段值具有原子性,不能再分(所有關係型數據庫系統都滿足第一範式);

例如:姓名字段,其中姓和名是一個整體,如果區分姓和名那麼必須設立兩個獨立字段;


第二範式(2NF):一個表必須有主鍵,即每行數據都能被唯一的區分;

備註:必須先滿足第一範式;


第三範式(3NF):一個表中不能包涵其他相關表中非關鍵字段的信息,即數據表不能有冗餘字段;

備註:必須先滿足第二範式;


2.表字段少而精


  • I/O高效


  • 字段分開維護簡單


  • 單表1G體積 500W行評估


  • 單行不超過200Byte


  • 單表不超過50個INT字段


  • 單表不超過20個CHAR(10)字段


  • 建議單表字段數控制在20個以內


  • 拆分TEXT/BLOB,TEXT類型處理性能遠低於VARCHAR,強制生成硬盤臨時表浪費更多空間。


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