資料庫與資料型別的優化
1. 選擇優化的資料型別
- 最小資料型別
- 簡單資料型別
- 儘量避免NULL
選擇資料型別時:
- 需要確定合適的大型別:數字、字串、時間。
- 選擇具體的型別。考慮長度、範圍,允許的精度,需要的物理空間。
例如
選擇時間時,DATETIME
和 TIMESAMP
都可以儲存相同型別的資料:日期,時間,精確到秒。
然而TIMESAMP
只使用 DATETIME
一半的儲存空間,並且會根據時區變化,具有特殊的自動更新能力。
另一方面,TIMESAMP
允許的時間範圍要小得多,有時候它的特殊能力會成為障礙。
1.1 整數型別
有兩種型別的數字:
- 整數
- 實數
如果是儲存整數:
- TINYINT (8)
- SMALLINT (16)
- MEDIUMINT (24)
- INT (32)
- BIGINT (64)
整數型別有可選的 UNSIGNED 屬性,表示不允許負值,這大致可以使正數的上限提高一倍。
例如
TINYINT
的儲存範圍是 -128 ~ 127
,UNSIGNED TINYINT
可以儲存範圍是 0 ~ 255
。
1.2 實數型別
實數是帶有小數部分的數字。
FLOAT
(4位元組)DOUBLE
(8位元組)
FLOAT
和 DOUBLE
型別只支援使用標準的浮點運算進行近似計算。
DECIMAL
型別用於儲存精確的小數。
因為 CPU不支援對 DECIMAL 的直接計算,所以在 MySQL 5.0 以及更高版本中,MySQL伺服器自身實現了 DECIMAL 的高精度計算。相對而言,CPU直接支援原生浮點計算,所以浮點運算明顯更快。
因為需要額外的空間和計算開銷,所以應該儘量只在對小數進行精確計算時才使用DECIMAL—例如儲存財務資料。
但在資料量比較大的時候,可以考慮使用 BIGINT 代替 DECIMAL,將需要儲存的貨幣單位根據小數的位數乘以相應的倍數即可。
1.3 字串型別
varchar 和 char 是兩種最主要的字串型別。
varchar
varchar 型別用於儲存可變長字串,是最常見的字串資料型別。
它比定長型別更節省空間,因為它僅使用必要的空間(越短的字串使用越少的空間)。
varchar 需要1或2個額外位元組記錄字串的長度。
下面這些情況下使用 varchar是合適的:
- 字串列的最大長度比平均長度大很多。
- 列的更新很少,所以碎片不是問題。
- 使用了像 UTF-8 這樣複雜的字符集,每個字元都使用不同的位元組數進行儲存。
char
char 型別是定長的: MySQL總是根據定義的字串長度分配足夠的空間。
下面這些情況下使用 varchar是合適的:
- char適合儲存很短的字串,或者所有值都接近一個長度。(如密碼的MD5值,定長值)
- 對於經常變更的資料,char也是比varchar更好,因為定長的char型別不容易產生碎片。
- 對於非常短的列,char 比varchar在儲存空間上也更有效率。(如char(1)來儲存Y和N,只需要一個位元組,但是varchar(1)卻需要兩個位元組,因為還需要一個記錄長度的額外位元組)
與 char 和 varchar 類似的型別還有 binary 和 varbinary ,它們儲存的是二進位制字串。
使用 varchar(5) 和 varchar(200) 儲存“hello” 的空間開銷是一樣的。那麼使用更短的列有什麼優勢嗎?
事實上有很大的優勢。更長的列會消耗更多的記憶體,因為MySQL通常會分配固定大小的記憶體塊來儲存內部值。
尤其是使用記憶體臨時表進行排序或操作時會特別糟糕。所以,最好的策略是隻分配真正需要的空間。
blob 和 text 型別
blob 和 text 都是為儲存很大的資料而設計的字串資料型別,分別採用二進位制和字串方式儲存。
1.4 日期和時間型別
datetime
使用8個位元組的儲存空間。這個型別能儲存大範圍的值,從1001年到9999年,精度為秒。
timestamp
使用4個位元組的儲存空間。只能表示從1970年到2038年。
除特殊行為之外,通常應該儘量使用 timestamp,因為它比 datetime 空間效率更高。
如果需要儲存比秒更小粒度的日期和時間值怎麼辦?
那麼就可以使用BIGINT
型別儲存微秒級別的時間戳。
1.5 位資料型別
MySQL有少數幾種儲存型別使用緊湊的位儲存資料。所有這些位型別,不管底層儲存格式和處理方式如何,比技術上來說都是字串型別。
BIT
MySQL 把 BIT 當作字串型別,而不是數字型別。當檢索 BIT(1) 的值時,結果是一個包含二進位制0或1值的字串,而不是 ASCII 碼的“0”或“1”。
應該謹慎使用 BIT 型別。對於大部分應用,最好避免使用這種型別。
SET
如果需要儲存很多 true/ false值,可以考慮合併這些列到一個SET 資料型別,它在 MySQL 內部是以一系列打包的位的集合來表示的。
1.6 選擇識別符號
選擇標識列的型別時,不僅僅需要考慮儲存型別,還需要考慮MySQL對這種型別怎麼執行計算和比較。
整數通常是標識列最好的選擇,因為它們很快並且可以使用 AUTO_INCREMENT.
如果可能,應該避免使用字串型別作為標識列,因為它們很消耗空間。
如果儲存 UUID 值,則應該移除“-”符號,或者更好的做法是,使用 UNHEX() 函式轉換 UUID 值為16位元組的數字,並且儲存在一個 BINARY(16)中,檢索時可以通過HEX() 函式來格式化為十六進位制格式。
IP地址,人們經常使用 varchar(15) 列來儲存 IP 地址。
然而,它們實際上是32位無符號整數,不是字串。用小數點將地址分為四段的表示方法也只是為了讓人們閱讀容易。
所以應該用無符號整數儲存IP地址。MySQL提供 INET_ATON() 和 INET_NTOA() 函式在這兩種表示方法之間轉換。
2. MySQL 資料庫設計中的陷阱
設計MySQL 的資料庫的問題。
不好的設計:
- 太多列
- 太多關聯
- 過度使用列舉
- 不要怕使用NULL
3. 正規化和反正規化
3.1 正規化
正規化的優點
- 正規化化的更新操作通常比反正規化要快。
- 當資料較好地正規化化時,就只有很少或者沒有重複資料,所以只需要修改更少的資料。
- 正規化化的表通常更小,可以更好地放在記憶體裡,所以執行操作會更快。
- 很少有多餘的資料意味著檢索列表資料時更少需要DISTINCT 或者 GROUP BY 語句。
正規化的缺點
- 通常需要關聯。
3.2 反正規化
反正規化的優點
- 反正規化化的資料都在一張表中,可以很好的避免關聯。
反正規化的缺點
- 更新資料會變複雜。
3.3 混用正規化化和反正規化化
實際應用中經常需要混用。
最常見的反正規化化資料的方法是複製或者快取,在不同的表中儲存相同的特定列,也就是冗餘資料列,減少關聯表。
另一個從父表冗餘一些資料到子表的理由是排序的需要。
4. 快取表和彙總表
有時提升效能最好的方法是在同一張表中儲存衍生的冗餘資料。
然而,有時也需要建立一張完全獨立的彙總表或快取表(特別是滿足檢索的需求時)。
快取表:表示儲存那些可以比較簡單地從資料庫其它表獲取(但每次獲取的速度比較慢)資料的表。
彙總表:儲存的是使用 GROUP BY 語句聚合資料的表。
不嚴格的計數或通過小範圍查詢填滿間隙的嚴格計數,都比實時計算統計值速度快很多。
計數器表
如果應用在表中儲存計數器,則在更新計數器時可能碰到併發問題。
更快地讀,更慢的寫
為了提升讀查詢的速度,經常會需要建一些額外索引,增加冗餘列,甚至是建立快取表和彙總表。這些方法會增加寫查詢的負擔,也需要額外的維護任務,但在設計高效能資料庫時,這些都是常見的技巧:雖然寫操作變得更慢了,但更顯著地提高了讀操作的效能。
5. 加快ALTER TABLE 操作的速度
ALTER TABLE 操作的效能對大表來說是個大問題。
MySQL執行大部分修改表結構操作的方法是用新的結構建立一個空表,從舊錶中查出所有資料插入新表,然後刪除舊錶。這樣操作可能需要花費很長時間,如果記憶體不足而表又很大,而且還有很多索引的情況下尤其如此。
使用方法有兩種:
- 先在一臺不提供服務的機器上執行ALTER TABLE操作,然後和提供服務的主庫進行切換。
- 影子拷貝。用要求的表結構建立一張和源表無關的新表,然後通過重新命名和刪表操作交換兩張表。
6. 總結
良好的資料庫設計原則是普遍適用的,但MySQL有它自己的實現細節要注意。
概括來說,儘可能保持任何東西小而簡單總是好的。
MySQL喜歡簡單,需要使用資料庫的人應該也同樣喜歡簡單的原則:
- 儘量避免過度設計,
- 使用小而簡單的合適資料型別,除非真實資料模型中有確切的需要,否則應該儘可能避免使用NULL值。
- 儘量使用相同的資料型別儲存相似或相關的值,尤其是要在關聯條件中使用的列。
- 注意可變長字串,其在臨時表和排序時可能導致悲觀的按最大長度分配記憶體。
- 儘量使用整型定義標識列。
- 以免使用MySQL已經遺棄的特性,如指定浮點數的精度,或者整數的顯示寬度。
- 小心使用ENUM和SET。最好避免使用BIT。
正規化是好的,但是反正規化有時也是必需的,並且能帶來好處。
最後,ALTER TABLE 是讓人痛苦的操作,因為在大部分情況下,它都會鎖表並且重建整張表。
相關推薦
資料庫與資料型別的優化
1. 選擇優化的資料型別 最小資料型別 簡單資料型別 儘量避免NULL 選擇資料型別時: 需要確定合適的大型別:數字、字串、時間。 選擇具體的型別。考慮長度、範圍,允許的精度,需要的物理空間。 例如 選擇時間時,DATETIME 和 TIMESAMP
讀高效能Mysql---4--Schema與資料型別優化 有感
Schema與資料型別優化 選擇優化的資料型別 1.更小的通常更好 佔用更少磁碟,記憶體和CPU快取,處理的CPU週期也更少 2.簡單就好 &n
資料庫的資料型別優化
mysql支援非常多的資料型別,在設計表的時候需要精心的為每個列選擇合適的資料型別以提高資料庫的效能,這篇文章回顧了資料庫中常用的幾種資料型別,並總結了一些資料型別優化的技巧。 1.選擇優化的資料型別 mysql支援非常多的資料型別,選擇正確的資料型別對優化
Oracle資料庫入門資料型別與表操作(三)
目錄 基本資料型別 建立表 修改表操作 刪除表操作 基本資料型別 字元型 NCHAR CHAR 區別在於 NCHAR儲存2000個字元,而CHAR只能儲存1000個字元 VARCHAR2  
四、資料庫之資料型別
首先補充點了解的小知識; select * from mysql.user #顯示出來亂了 select * from mysql.user\G #加了\G後一行一行顯示了 一、資料型別:分不同種類去存不同型別的資料 儲存引
MySQL資料庫與資料表的基本操作
初學小建議 MySQL是不區分大小寫的,大家在初學的時候希望能養成習慣,把保留詞,關鍵字統一採用大寫的形式書寫,其他的使用小寫字母,方便區分。 初期這個習慣可能不太容易養成,但是一旦習慣,對工作的規範性會好很多,統一的規範方便大家一起工作! 選單
Java的識別符號與資料型別——有C++基礎的Java入門(二)
目錄 一、 識別符號 1、 概念 2、 識別符號的規範 (1) 類和介面 (2) 變數和方法 (3) 常量 二、 資料型別 1、 資料型別定義及預設值 2、資料型別自動轉換 (1) 總結 (2) 與C++的不同點 (3) 原理 3、 強制轉換
大資料導論(4)——OLTP與OLAP、資料庫與資料倉庫
公司內部的資料自下而上流動,同時完成資料到資訊、知識、洞察的轉化過程。 而企業內部資料,從日常OLTP流程中產生,實時儲存進不同的資料庫中。同時定期被提取、經格式轉化、清洗和載入(ETL),以統一的格式儲存進資料倉庫,以供決策者進行OLAP處理,並將處理結果視覺化。 OLTP & OLAP 企業
《SQL入門經典》筆記(第二章:建立資料庫之資料型別)
“建立資料庫”包括五個內容:定義資料結構、管理資料庫物件、規格化過程、操作資料以及管理資料庫事務 1. 什麼是資料型別? 資料型別用於指定特定列所包含資料的規則,它決定了資料儲存在列裡的方式。SQL最基本的資料型別有字串、數值、日期和時間(其實每個實現都有自己的資料型別
資料庫之資料型別
首先補充點了解的小知識; select * from mysql.user #顯示出來亂了 select * from mysql.user\G #加了\G後一行一行顯示了 一、資料型別:分不同種類去存不同型別的資料 儲存引擎決定了表的型別,而表記憶體放的資料也要有不同的型別,每種資料型別
Mysql效能優化之資料型別優化
一、選擇正確的資料型別對於獲得高效能至關重要 1.1更小的通常更好 佔用更少的磁碟、記憶體和CPU快取 1.2儘量避免null 如果查詢中包含可為null的列,對Mysql來說更難優化,因為可為null的列使得索引、索引統計和值都更復雜。會使用更多的儲存空間. 2、整數和實數
SQL 用於各種資料庫的資料型別(轉載) sqlserver 資料型別 取值範圍 長度
SQL 用於各種資料庫的資料型別 來源 http://www.runoob.com/sql/sql-datatypes.html 面向資料庫程式設計中,資料型別的取值範圍、長度,可能是需要經常檢視的資料。 Microsoft Access、MySQL 和 SQL S
Python運維開發:運算子與資料型別(二)
python物件的相關術語: python程式中儲存的所有資料都是圍繞物件這個概念展開的: 程式中儲存的所有資料都是物件 每個物件都有一個身份、一個型別和一個值 例如,school='MaGe Linux'會以'MaGe Linux'建立一個字串物件,其身份是指向它在記憶體中所處位
Oracle 資料庫 全部資料型別詳解
資料型別 描述 VARCHAR2(size) 可變長度的字串,其最大長度為size個位元組;size的最大值是4000,而最小值是1;你必須指定一個VARCHAR2的size;
MySQL進階(五)資料型別優化
優化的資料型別 (一)更小的通常更好 更小的資料型別通常更快,因為它們佔用更少的磁碟、記憶體和CPU快取 (二)簡單就好 簡單資料型別通常需要更少的CPU週期。例如,整型比字元操作代價更低,因為字符集和校對規則使字元比整型更復雜 (三)儘量避免使用NULL 如果查詢中包含可為NULL
cin輸入型別與資料型別不符
istream類過載了抽取運算子<< ,>>, 所以cin >> 支援c++內建的所有基本資料型別。cin物件將標準輸入表示為位元組流,然後根據抽取 運算子<<(本質就是一個函式)的引數型別對位元組流進行型別轉換,轉換為所需的型別。 不同版
JavaScript變數與資料型別詳解
變數 變數來源於數學,是計算機語言中能儲存計算結果或能表示值抽象概念。變數可以通過變數名訪問。 變數的作用就是用於儲存值。 語法: 宣告變數時,總是以關鍵字var打頭。任何情況下都應該這樣做。然後給變數指定名稱。在宣告變數時,也可以給它賦值,方法是在變數名後面加上等號和值。賦值語句總是以分號
numpy 學習彙總12-Matrix矩陣運算與資料型別轉換 ( 基礎學習 tcy)
python中的矩陣運算 2018/11/21 ===================================================================== 1.矩陣的建立 # 由一維或二維資料建立矩陣 from numpy import * a=
約束條件與資料型別的關係
建立表___約束條件(語法): 約束條件與資料型別的寬度一樣,都是可選引數 作用:用於保證資料的完整性和一致性 一: not null: 不允許傳空 default: 預設值 比如建立一個為t11的表: create table t11( id int, name char(6),
Java學習筆記之——變數與資料型別
一、變數 1.變數:變化的值 變數在程式碼執行期間,開闢了一塊空間 。這塊空間是有地址的,給這塊取了個名字, 這個名字就叫做變數名,這塊空間放的東西叫做變數值 2.變數的初始化: (1)先宣告再賦值: ***宣告變數:資料型別 變數名*** 宣告:int i; 賦值:i=1;