程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> 關於MYSQL數據庫 >> MySQL表設計優化與索引 (十)

MySQL表設計優化與索引 (十)

編輯:關於MYSQL數據庫
Bit-Packed Data Types

  MySQL有一些存儲類型使用一個值中的一些單個的比特位來緊湊的存儲數據。純技術上將,不管是底層的存儲格式還是操作,所有這些類型都是字符串類型。

  BIT

  MySQL5.0以前, BIT只是TINYINT的同義詞而已。但是在MySQL5.0以及之後的版本,BIT是一個完全不同的數據類型了, 有著自己的一些特點, 這裡討論一些新的行為和屬性:

  可以用BIT字段在單列裡面來存儲一個或多個true/false值, BIT(1)定義一個了只包含單個比特位的字段, BIT(2)是存儲2個比特位的字段, 如此類推;BIT字段的最大長度可以是64個比特。

  BIT類型的行為與存儲引擎有關。MyISAM把一些列為了存儲的目的打包到一起, 所以17個單獨的BIT列需要17個比特來存儲(假定這些列都不允許NULL),MyISAM會近似算成3個字節來存儲。其他的一些存儲引擎, 比如Memory和InnoDB, 把每個列都用有足夠長度存儲這些比特位的最小整數來存儲,所以無法節省存儲空間。

  * TIMESTAMP類型的一些行為的規則比較復雜並隨著不同的MySQL版本而變化,所以在使用時應當確認是自己所期望的行為。通常, 在對TIMESTAMP的列做了改變後通過查看SHOW CREATE TABALE的結果來確認是一個的主意。

  MySQL把BIT當做字符串類型, 而不是數據類型。當檢索BIT(1)列的值, 結果是一個字符串而內容是二進制位0或1, 而不是ASCII值”0″或”1″.然而, 如果在一個數值上下文檢索的話, 結果是比特串轉化而成的數字。 當需要與另一個值進行比較時, 記住這一點。比如, 如果存儲值’00111001′(是57的二進制表示)到一個BIT(8)的字段中然後檢索出來,得到的是字符編碼值為57字符串, 而這值就是“9”的ASCII編碼。但是在數值環境中, 得到的是值57:s

  MySQL> CREATE TABLE bittest(a bit(8));

  MySQL> INSERT INTO bittest VALUES(b’00111001′);

  MySQL> SELECT a, a + 0 FROM bittest;

  +——+——-+

  | a | a + 0 |

  +——+——-+

  | 9 | 57 |

  +——+——-+

  這非常容易引起混淆, 所以我們提醒小心使用BIT類型。對於大多數應用程序來說,避免使用這個類型比較的好。

  如果想在單個比特位的存儲空間中存儲true/false值的另一個選擇是使用可以為NULL的CHAR(0)列。這個列能夠存儲NULL和長度為0的空串。

  SET

  如果需要存儲多個true/false的值, 可以考慮把多個列放到一個MySQL所支持的SET數據類型,而MySQL內部通過一些比特位來表示的。這種類型有效的使用存儲空間, MySQL也有一些函數如FIND_IN_SET( )和FIELD( )來方便查詢。 最主要的缺點是改變列定義的開銷: 需要ALTER TABLE, 而這個操作在一個大表上則是開銷非常大的(參考後面有關於替換方法的討論)。一般來說, 也無法在SET列上使用索引。

  Bitwise Operations on integer columns

  整型列上的位操作

  SET類型的一個替代辦法是把一個整數當做一些比特位的集合。 比如,可以把一個TINYINT數當做8個比特位, 用位運算來操作其中的比特位, 可以通過在應用程序中位每一個比特位定義命名常數來簡化理解。

  這種方法相對於SET的主要的好處是可以不需要ALTER TABLE就能改變枚舉值。缺點是查詢寫起來麻煩且不容易理解(當第5個比特位為1是什麼意思?)。有些人喜歡使用位操作而有些人不喜歡,因而是否使用這個技巧很大程度上是個人口味的問題。

  把比特位打成包的一個例子應用程序是存儲權限的訪問控制列表(ACL).每個比特或SET元素表示一個CAN_READ, CAN_WRITE或者CAN_DELETE之類的值。 如果使用SET列, 需要在MySQL的列定義中存儲比特到值得映射關系; 如果使用整數列, 則需要在應用中存儲這個映射關系。下面是一些使用SET列的查詢語句:

  MySQL> CREATE TABLE acl (

  -> perms SET(‘CAN_READ’, ‘CAN_WRITE’, ‘CAN_DELETE’) NOT NULL

  -> );

  MySQL> INSERT INTO acl(perms) VALUES (‘CAN_READ,CAN_DELETE’);

  MySQL> SELECT perms FROM acl WHERE FIND_IN_SET(‘CAN_READ’, perms);

  +———————+

  | perms |

  +———————+

  | CAN_READ,CAN_DELETE |

  +———————+

  如果使用整數, 則大概會以如下的方式處理;

  MySQL> SET @CAN_READ := 1 << 0,

  -> @CAN_WRITE := 1 << 1,

  -> @CAN_DELETE := 1 << 2;

  MySQL> CREATE TABLE acl (

  -> perms TINYINT UNSIGNED NOT NULL DEFAULT 0

  -> );

  MySQL> INSERT INTO acl(perms) VALUES(@CAN_READ + @CAN_DELETE);

  MySQL> SELECT perms FROM acl WHERE perms & @CAN_READ;

  +——-+

  | perms |

  +——-+

  | 5 |

  +——-+

  使用了變量來存儲值, 不過在代碼中可以使用常數來代替。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved