mysql 优化表的作用_mysql实战优化之三:表优化
對于大多數的數據庫引擎來說,硬盤操作可能是最重大的瓶頸。所以,把你的數據變得緊湊會對這種情況非常有幫助,因為這減少了對硬盤的訪問。
如果一個表只會有幾列罷了(比如說字典表,配置表),那么,我們就沒有理由使用 INT 來做主鍵,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 會更經濟一些。如果你不需要記錄時間,使用 DATE 要比 DATETIME 好得多。
當然,你也需要留夠足夠的擴展空間,不然,你日后來干這個事,你會死的很難看,參看Slashdot的例子(2009年11月06 日),一個簡單的ALTER TABLE語句花了3個多小時,因為里面有一千六百萬條數據。
表結構優化
一、數據類型選擇
數據庫操作中最為耗時的操作就是 IO 處理,大部分數據庫操作 90% 以上的時間都花在了 IO 讀寫上面。所以盡可能減少 IO 讀寫量,可以在很大程度上提高數據庫操作的性能。
我們無法改變數據庫中需要存儲的數據,但是我們可以在這些數據的存儲方式方面花一些心思。下面的這些關于字段類型的優化建議主要適用于記錄條數較多,數據量較大的場景,因為精細化的數據類型設置可能帶來維護成本的提高,過度優化也可能會帶來其他的問題:
1.數字類型:非萬不得已不要使用DOUBLE,不僅僅只是存儲長度的問題,同時還會存在精確性的問題。同樣,固定精度的小數,也不建議使用DECIMAL,建議乘以固定倍數轉換成整數存儲,可以大大節省存儲空間,且不會帶來任何附加維護成本。對于整數的存儲,在數據量較大的情況下,建議區分開 TINYINT / INT / BIGINT 的選擇,因為三者所占用的存儲空間也有很大的差別,能確定不會使用負數的字段,建議添加unsigned定義。當然,如果數據量較小的數據庫,也可以不用嚴格區分三個整數類型。
2.字符類型:非萬不得已不要使用 TEXT 數據類型,其處理方式決定了他的性能要低于char或者是varchar類型的處理。定長字段,建議使用 CHAR 類型,不定長字段盡量使用 VARCHAR,且僅僅設定適當的最大長度,而不是非常隨意的給一個很大的最大長度限定,因為不同的長度范圍,MySQL也會有不一樣的存儲處理。
3.時間類型:盡量使用TIMESTAMP類型,因為其存儲空間只需要 DATETIME 類型的一半。對于只需要精確到某一天的數據類型,建議使用DATE類型,因為他的存儲空間只需要3個字節,比TIMESTAMP還少。不建議通過INT類型類存儲一個unix timestamp 的值,因為這太不直觀,會給維護帶來不必要的麻煩,同時還不會帶來任何好處。
4.ENUM & SET:對于狀態字段,可以嘗試使用 ENUM 來存放,因為可以極大的降低存儲空間,而且即使需要增加新的類型,只要增加于末尾,修改結構也不需要重建表數據。如果是存放可預先定義的屬性數據呢?可以嘗試使用SET類型,即使存在多種屬性,同樣可以游刃有余,同時還可以節省不小的存儲空間。
5.LOB類型:強烈反對在數據庫中存放 LOB 類型數據,雖然數據庫提供了這樣的功能,但這不是他所擅長的,我們更應該讓合適的工具做他擅長的事情,才能將其發揮到極致。在數據庫中存儲 LOB 數據就像讓一個多年前在學校學過一點Java的營銷專業人員來寫 Java 代碼一樣。
二、字符編碼
字符集直接決定了數據在MySQL中的存儲編碼方式,由于同樣的內容使用不同字符集表示所占用的空間大小會有較大的差異,所以通過使用合適的字符集,可以幫助我們盡可能減少數據量,進而減少IO操作次數。
1.純拉丁字符能表示的內容,沒必要選擇 latin1 之外的其他字符編碼,因為這會節省大量的存儲空間
2.如果我們可以確定不需要存放多種語言,就沒必要非得使用UTF8或者其他UNICODE字符類型,這回造成大量的存儲空間浪費
3.MySQL的數據類型可以精確到字段,所以當我們需要大型數據庫中存放多字節數據的時候,可以通過對不同表不同字段使用不同的數據類型來較大程度減小數據存儲量,進而降低 IO 操作次數并提高緩存命中率
三、適當拆分
有些時候,我們可能會希望將一個完整的對象對應于一張數據庫表,這對于應用程序開發來說是很有好的,但是有些時候可能會在性能上帶來較大的問題。
當我們的表中存在類似于 TEXT 或者是很大的 VARCHAR類型的大字段的時候,如果我們大部分訪問這張表的時候都不需要這個字段,我們就該義無反顧的將其拆分到另外的獨立表中,以減少常用數據所占用的存儲空間。這樣做的一個明顯好處就是每個數據塊中可以存儲的數據條數可以大大增加,既減少物理 IO 次數,也能大大提高內存中的緩存命中率。
上面幾點的優化都是為了減少每條記錄的存儲空間大小,讓每個數據庫中能夠存儲更多的記錄條數,以達到減少 IO 操作次數,提高緩存命中率。下面這個優化建議可能很多開發人員都會覺得不太理解,因為這是典型的反范式設計,而且也和上面的幾點優化建議的目標相違背。
四、適度冗余
為什么我們要冗余?這不是增加了每條數據的大小,減少了每個數據塊可存放記錄條數嗎?
確實,這樣做是會增大每條記錄的大小,降低每條記錄中可存放數據的條數,但是在有些場景下我們仍然還是不得不這樣做:
被頻繁引用且只能通過 Join 2張(或者更多)大表的方式才能得到的獨立小字段
這樣的場景由于每次Join僅僅只是為了取得某個小字段的值,Join到的記錄又大,會造成大量不必要的 IO,完全可以通過空間換取時間的方式來優化。不過,冗余的同時需要確保數據的一致性不會遭到破壞,確保更新的同時冗余字段也被更新
五、盡量使用 NOT NULLNULL 類型比較特殊,SQL 難優化。雖然 MySQL NULL類型和 Oracle 的NULL 有差異,會進入索引中,但如果是一個組合索引,那么這個NULL 類型的字段會極大影響整個索引的效率。此外,NULL 在索引中的處理也是特殊的,也會占用額外的存放空間。
很多人覺得 NULL 會節省一些空間,所以盡量讓NULL來達到節省IO的目的,但是大部分時候這會適得其反,雖然空間上可能確實有一定節省,倒是帶來了很多其他的優化問題,不但沒有將IO量省下來,反而加大了SQL的IO量。所以盡量確保 DEFAULT 值不是 NULL,也是一個很好的表結構設計優化習慣。
六、分離冷熱數據
將大字段、訪問頻率低的字段拆分到單獨的表中存儲,分離冷熱數據,有利于有效利用緩存,防止讀入無用的冷數據,較少磁盤IO,同時保證熱數據常駐內存提高緩存命中率。
六、避免大表的DDL操作
MYSQL的新增和修改列的操作相當于重建表,表設計要一步到位,盡量避免大表的DDL操作。 (TIPS:可以預定義一些列留作將來業務擴展,如:當前只需要10個字段,考慮到未來發展,可以預留10個字段,表上總共創建20個字段)
七、定期分析表和檢查表
分析表的語法:ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tb1_name[, tbl_name]...
以上語句用于分析和存儲表的關鍵字分布,分析的結果將可以使得系統得到準確的統計信息,使得SQL能夠生成正確的執行計劃。如果用戶感覺實際執行計 劃并不是預期的執行計劃,執行一次分析表可能會解決問題。在分析期間,使用一個讀取鎖定對表進行鎖定。這對于MyISAM,DBD和InnoDB表有作 用。
例如分析一個數據表:analyze table table_name
檢查表的語法:CHECK TABLE tb1_name[,tbl_name]...[option]...option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
檢查表的作用是檢查一個或多個表是否有錯誤,CHECK TABLE 對MyISAM 和 InnoDB表有作用,對于MyISAM表,關鍵字統計數據被更新
CHECK TABLE 也可以檢查視圖是否有錯誤,比如在視圖定義中被引用的表不存在。
八、定期優化表
定期分析表
ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name]
本語句用于分析和存儲表的關鍵字分布。在分析期間,使用一個讀取鎖定對表進行鎖定。這對于MyISAM, BDB和InnoDB表有作用。對于MyISAM表,本語句與使用myisamchk -a相當。
MySQL使用已存儲的關鍵字分布來決定,當您對除常數以外的對象執行聯合時,表按什么順序進行聯合。
mysql> analyze table a;
+--------+---------+----------+-----------------------------+
| Table ?| Op ? ? ?| Msg_type | Msg_text ? ? ? ? ? ? ? ? ? ?|
+--------+---------+----------+-----------------------------+
| test.a | analyze | status ? | Table is already up to date |
+--------+---------+----------+-----------------------------+
1 row in set (0.00 sec)
定期檢查表
CHECK TABLE tbl_name [, tbl_name] ?[option]
option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
檢查一個或多個表是否有錯誤。CHECK TABLE對MyISAM和InnoDB表有作用。對于MyISAM表,關鍵字統計數據被更新。
mysql> check table a;
+--------+-------+----------+----------+
| Table ?| Op ? ?| Msg_type | Msg_text |
+--------+-------+----------+----------+
| test.a | check | status ? | OK ? ? ? |
+--------+-------+----------+----------+
1 row in set (0.00 sec)
CHECK TABLE也可以檢查視圖是否有錯誤,比如在視圖定義中被引用的表已不存在。
我們為上面的表a創建一個視圖
mysql> create view a_view as select * from a;
Query OK, 0 rows affected (0.02 sec)
然后CHECK一下該視圖,發現沒有問題
mysql> check table a_view;
+-------------+-------+----------+----------+
| Table ? ? ? | Op ? ?| Msg_type | Msg_text |
+-------------+-------+----------+----------+
| test.a_view | check | status ? | OK ? ? ? |
+-------------+-------+----------+----------+
1 row in set (0.00 sec)
現在刪掉視圖依賴的表
mysql> drop table a;
Query OK, 0 rows affected (0.01 sec)
再CHECK一下剛才的視圖,發現報錯了
mysql> check table a_view\G;
*************************** 1. row ***************************
Table: test.a_view
Op: check
Msg_type: Error
Msg_text: Table 'test.a' doesn't exist
*************************** 2. row ***************************
Table: test.a_view
Op: check
Msg_type: Error
Msg_text: View 'test.a_view' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
*************************** 3. row ***************************
Table: test.a_view
Op: check
Msg_type: error
Msg_text: Corrupt
3 rows in set (0.00 sec)
ERROR:
No query specified
定期優化表
OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name]
如果您已經刪除了表的一大部分,或者如果您已經對含有可變長度行的表(含有VARCHAR, BLOB或TEXT列的表)進行了很多更改,則應使用OPTIMIZE TABLE。被刪除的記錄被保持在鏈接清單中,后續的INSERT操作會重新使用舊的記錄位置。您可以使用OPTIMIZE TABLE來重新利用未使用的空間,并整理數據文件的碎片。
在多數的設置中,您根本不需要運行OPTIMIZE TABLE。即使您對可變長度的行進行了大量的更新,您也不需要經常運行,每周一次或每月一次即可,只對特定的表運行。
OPTIMIZE TABLE只對MyISAM, BDB和InnoDB表起作用。
對于MyISAM表,OPTIMIZE TABLE按如下方式操作:
如果表已經刪除或分解了行,則修復表。
如果未對索引頁進行分類,則進行分類。
如果表的統計數據沒有更新(并且通過對索引進行分類不能實現修復),則進行更新。
mysql> OPTIMIZE table a;
+--------+----------+----------+-----------------------------+
| Table ?| Op ? ? ? | Msg_type | Msg_text ? ? ? ? ? ? ? ? ? ?|
+--------+----------+----------+-----------------------------+
| test.a | optimize | status ? | Table is already up to date |
+--------+----------+----------+-----------------------------+
1 row in set (0.00 sec)
****
需要注意的是無論是ANALYZE,CHECK還是OPTIMIZE在執行期間將對表進行鎖定,因此請注意這些操作要在數據庫不繁忙的時候執行
****
表結構優化可以使用Procedure Analyse()幫助分析。詳細見《
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的mysql 优化表的作用_mysql实战优化之三:表优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql pdo 读取字段名_PHP使
- 下一篇: docker容器mysql头文件_在Do