這裡講得是如何在使用16進制大數據的情況下保持好的性能,主要講的是MySQL數據庫,對其他數據庫應該也起作用。
一、小心你的字符編碼
看一下下面這個SQL語句:
mysql> explain select * from t where id = ’0cc175b9c0f1b6a831c399e269772661′G
*************************** 1. row
***************************
id: 1
select_type: SIMPLE
table: t
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 98
ref: const
rows: 1
Extra: Using index
為什麼索引是98byte?簡單,因為我們用的是UTF-8:
CREATE TABLE `t` (
`id` varchar(32) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
沒有必要用UTF-8存儲16進制數據,采用UTF-8存儲16進制數據不會增加磁盤空間的占用,但是當你使用排序(order by)、統計(group by)、隱式臨時表(MySQL查詢時自建的臨時表)等的時候,需要耗費多達3倍的內存和硬盤空間,至少在MySQL上是這樣的。
二、使用固定長度,不要有空值
可以看到上面那個表采用的是varchar字段,我們都知道varchar是一個變長字段,如果你確認所有的數據都一樣長(比如像md5()出來的,都是32個字節),最好使用char()定長字段,另外就是如果字段中不可能有空值,最好指定為not null
三、使用二進制數據存儲
實際上,你並不需要存儲字符串,16進制字符串不過是數字的另一種表現形式,直接保存數字。比如:00000000000000000000000000002E2A是什麼呢?這正是16進制數字11818,使用一個4字節(或者更少)的整型代替一個32字節的字符存儲更好。
問題是MySQL沒有合適的類型來存儲這麼大的數字,它們比BIGINT還要大很多,不過MySQL允許我們存儲到BINARY字段,數據更緊湊比較起來更快速,可以使用HEX()和UNHEX()來轉換格式,或者16進制操作符’x’
mysql> select x’7861707262′;
+—————+
| x’7861707262′ |
+—————+
| xaprb |
+—————+
用BINARY(16)代替varchar(32)之後:
explain select * from t where id = x’0cc175b9c0f1b6a831c399e269772661′G
*************************** 1. row
***************************
id: 1
select_type: SIMPLE
table: t
type: const
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: const
rows: 1
Extra: Using index
索引長度變成16字節了(對比原來98字節),減小了不少,如果你使用的是UUID(),存入之前先用replace()把”-”題換掉。
四、使用前綴索引
很多時候,我們不需要索引全部字段,索引字段的前8~10個字符就可以了,如果你當前存儲的是字符串,這很有用,不用轉換成BINARY,只是改變索引策略而已。
你可以通過類似下面的SQL語句判斷合適的前綴索引個數:
mysql> select count(distinct id), count(distinct left(id, 8)), count(distinct left(id, 9)) from tG
*************************** 1. row ***************************
count(distinct id): 2
count(distinct left(id, 8)): 2
count(distinct left(id, 9)): 2
找一個差不多行就可以,不一定要索引“唯一”。
五、創建hash索引
直接上代碼,不用多余的解釋:
mysql> alter table t add crc int unsigned not null, add key(crc);
mysql> update t set crc=crc32(id);
mysql> explain select * from t use index(crc) where id = ’0cc175b9c0f1b6a831c399e269772661′ and crc=crc32(’0cc175b9c0f1b6a831c399e269772661′)G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
type: ref
possible_keys: crc
key: crc
key_len: 4
ref: const
rows: 1
Extra: Using where
使用crc32()獲取到字符串的校驗值,一般這樣的碰撞概率不會太大,索引數字比索引字符不知道要快多少,極力推薦,不僅僅適用16進制字符,任意字符也適合:
mysql> select crc32(‘good good study, and day day up!’);
+——————————————-+
| crc32(‘good good study, and day day up!’) |
+——————————————-+
| 2265998365 |
+——————————————-+
1 row in set (0.00 sec)
總結:
16進制標識符讓表和索引的變大,降低比較和查找的速度,建議非不得已不要使用,如果非要使用,希望上面的五條建議對你有用。