為什么標題要起這個名字呢?commen sence指的是那些大家都應該知道的事情,但往往大家又會會略這些東西,或者對這些東西一知半解,今天我總結下自己在mysql中遇到的一些commen sense類型的問題。
1、varchar(5)可以存儲多少個漢字,多少個字母數字?
相信有好多人應該跟我一樣,對這個已經很熟悉了,根據經驗我們能很快的做出決定,比如說用varchar(200)去存儲url等等,但是,即使你用了很多次也很熟悉了,也有可能對上面的問題做出錯誤的回答。
這個問題我查了好多資料,有的人說是可以存儲5個字符,2.5個漢字(每個漢字占用兩個字節的話),有的人說這個要區分版本,5.0是個分界限,5.0之前是前面說的那樣,5.0之后是可以存儲5個“字”,不區分是數字、英文、漢字,果真是這樣嗎,我們來做個實驗:
CREATE TABLE `test` ( `name` varchar(5) NOT NULL DEFAULT '', `info` char(5) NOT NULL DEFAULT '', PRIMARY KEY (`name`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
可以看出varchar(5)中的5代表的是5個“字”,而不是5個字節(bytes),當我們存儲長度超過制定長度的時候會將超過的部分“咔嚓”掉,我的mysql版本是5.6,字符集(charset)utf8和gbk是一樣的。
其他版本我電腦上沒有,去官方文檔看看有沒有什么說明,在官方文檔中查了半天終於發現了點區別:
下面這段來自http://dev.mysql.com/doc/refman/4.1/en/char.html,是對mysq4.1的說明:
The
CHAR
andVARCHAR
types are declared with a length that indicates the maximum number of characters you want to store. For example,CHAR(30)
can hold up to 30 characters. (Before MySQL 4.1, the length is interpreted as number of bytes.)
再看看其他版本的類似的說明:
The
CHAR
andVARCHAR
types are declared with a length that indicates the maximum number of characters you want to store. For example,CHAR(30)
can hold up to 30 characters.
顯而易見了,官方文檔說了,mysql版本小於4.1的時候存儲的時候符合說法:varchar(5)保存5個bytes,及5個英文數字或者2.5個漢字(假設一個漢字2個字節);
mysql版本大於等於4.1的時候varchar(5)中的5不再是字節數了,應該理解為“字”這里的字的意思是一個漢字和一個英文或者數字“相同對待”
還有一點要注意,經過測試text類型的字段還是表示原始的字節含義。
2、mysql中的limit,你真的會用嗎?
你在項目中怎么使用limit?limit num?還是limit num1,num2?還是其他的?要知道limit使用不同的形式性能差距很大的。
我自己測試了下,在一張innodb表中去使用limit,表中10000條數據,四個字段,id(int)、time(int)、title(varchar)、body(mediumtext),大小大約170M左右,首先關掉查詢緩存,免得查詢緩存對查詢時間有影響,這里要注意time字段上面加了索引,
SET @@query_cache_type=ON; SET GLOBAL query_cache_size=0;
打開Query profiler來查看語句執行所花費的時間
set profiling=1;
接下來對下面幾個語句進行執行
a、SELECT id,TIME,title FROM cnblogs WHERE TIME>=1315646940 ORDER BY TIME ASC LIMIT 2000,10
b、SELECT id,TIME,title FROM cnblogs WHERE TIME>=1315646940 ORDER BY TIME ASC LIMIT 10
c、 SELECT id,TIME,title FROM cnblogs ORDER BY TIME ASC LIMIT 3000,10
執行順序a,b,c,a,b,c,c,a,a(這里需要注意下,雖然我關閉了緩存,但是上一次的查詢還是會緩存,這個可以從Query profiler中看出來,所以進行交叉執行),使用下面的語句查看結果
SHOW profiles;
從上面的語句執行時間分析可以看出,不考慮緩存因素,當使用limit的時候,"limit begin,num"這種形式比"limit num"這種形式效率低很多,因此,在使用的時候盡可能的使用第二種形式,比如說要循環獲取一個表里面的數據,一次取出來內從放不下,這個時候就要按照id(或者其他排序字段)進行limit了,我們就可以通過獲取上次的該字段臨界值作為下次取數據的最小值,使用limit num這種形式效率會高很多。
3、mysql字段數目和行大小的限制
a) 最大row size(65535 bytes)限制了字段的數目,因為所有字段的長度總和不能超過最大row size限制,舉個例子
utf8字符集中,每個字元需要3個bytes,所以對於一個char(255)的字段,mysql會給每一個值分配255 x 3 = 765 bytes,所以
一張表包含char(255)類型的字段不能超過65535/765=85個。
b)存儲字段長度也包含在上面的長度中,舉個例子,varchar(255)會花費2個字段存儲值的長度,所以每個值占用的空間上升為767個bytes。
長度小於255的時候需要1 bytes。
c) 編碼長度限制
字符類型若為gbk,每個字符最多占2個字節,最大長度不能超過32766;
字符類型若為utf8,每個字符最多占3個字節,最大長度不能超過21845。
若定義的時候超過上述限制,則varchar字段會被強行轉為text類型,並產生warning。
舉例:
導致實際應用中varchar長度限制的是一個行定義的長度。 MySQL要求一個行的定義長度不能超過65535。若定義的表長度超過這個值,則提示
a)) 若一個表只有一個varchar類型,如定義為
create table t4(c varchar(N)) charset=gbk;
則此處N的最大值為(65535-1-2)/2= 32766。
減1的原因是實際行存儲從第二個字節開始';
減2的原因是varchar頭部的2個字節表示長度;
除2的原因是字符編碼是gbk。
b)) 若一個表定義為
create table t4(c int, c2 char(30), c3 varchar(N)) charset=utf8;
則此處N的最大值為 (65535-1-2-4-30*3)/3=21812
減1和減2與上例相同;
減4的原因是int類型的c占4個字節;
減30*3的原因是char(30)占用90個字節,編碼是utf8。
如果被varchar超過上述的b規則,被強轉成text類型,則每個字段占用定義長度為11字節,當然這已經不是“varchar”了。
參考文章:
http://www.jb51.net/article/31589.htm
https://dev.mysql.com/doc/refman/5.1/en/column-count-limit.html
本文版權歸作者iforever(luluyrt@163.com)所有,未經作者本人同意禁止任何形式的轉載,轉載文章之后必須在文章頁面明顯位置給出作者和原文連接,否則保留追究法律責任的權利。