這是一個真實的場景,表的定義如下:
CREATE TABLE `user` (
`id` bigint(20) NOT NULL,
`user_nick` varchar(32),
`user_source` tinyint(4) NOT NULL ,
`user_type` tinyint(4) NOT NULL,
........
`version` int(11) DEFAULT '0' COMMENT '版本',
`crc_user_nick` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_user_nick` (`user_nick`),
KEY `idx_crc_user_nick` (`crc_user_nick`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;
為了顯示對比結果,我為user_nick列添加了一個索引,同時添加了一個存放crc32的字段crc_user_nick列,同時在這列上創建了一個索引,
update user set crc_user_nick=crc32(user_nick);
表中有將近200w的數據,並且user_nick不允許重復,隨機抽取一條查詢,根據crc查詢:
root@test 01:25:34>set profiling=1;
Query OK, 0 rows affected (0.00 sec)
root@test 01:25:37>select * from user where crc_user_nick=3741129210;
耗時:1 row in set (0.40 sec)
root@test 01:25:42>show profile cpu,block io for query 1;
+--------------------------------+----------+----------+------------+--------------+---------------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+--------------------------------+----------+----------+------------+--------------+---------------+
| starting | 0.000042 | 0.000000 | 0.000000 | 0 | 0 |
| checking query cache for query | 0.000089 | 0.001000 | 0.000000 | 0 | 0 |
| Opening tables | 0.388417 | 0.014998 | 0.004999 | 0 | 0 |
| System lock | 0.000013 | 0.000000 | 0.000000 | 0 | 0 |
| Table lock | 0.000012 | 0.000000 | 0.000000 | 0 | 0 |
| init | 0.000084 | 0.000000 | 0.000000 | 0 | 0 |
| optimizing | 0.000025 | 0.000000 | 0.000000 | 0 | 0 |
| statistics | 0.003755 | 0.000000 | 0.000000 | 0 | 0 |
| preparing | 0.000025 | 0.000000 | 0.000000 | 0 | 0 |
| executing | 0.000003 | 0.000000 | 0.000000 | 0 | 0 |
| Sending data | 0.001021 | 0.000000 | 0.000000 | 0 | 0 |
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| query end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| freeing items | 0.000043 | 0.000000 | 0.000000 | 0 | 0 |
| logging slow query | 0.000003 | 0.000000 | 0.000000 | 0 | 0 |
| cleaning up | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
+--------------------------------+----------+----------+------------+--------------+---------------+
對比同一條記錄使用user_nick查詢,
root@test 10:59:32>set profiling=1;
Query OK, 0 rows affected (0.00 sec)
root@test 10:59:41>select * from user_nick where user_nick='one001008104075924';
耗時:1 row in set (0.55 sec)
root@test 01:24:24>show profile cpu,block io for query 1;
+--------------------------------+----------+----------+------------+--------------+---------------+
| Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |
+--------------------------------+----------+----------+------------+--------------+---------------+
| starting | 0.000042 | 0.000000 | 0.000000 | 0 | 0 |
| checking query cache for query | 0.000089 | 0.000000 | 0.000000 | 0 | 0 |
| Opening tables | 0.542834 | 0.011998 | 0.003000 | 0 | 0 |
| System lock | 0.000013 | 0.000000 | 0.000000 | 0 | 0 |
| Table lock | 0.000011 | 0.000000 | 0.000000 | 0 | 0 |
| init | 0.000090 | 0.000000 | 0.000000 | 0 | 0 |
| optimizing | 0.000028 | 0.000000 | 0.000000 | 0 | 0 |
| statistics | 0.000315 | 0.000000 | 0.000000 | 0 | 0 |
| preparing | 0.000025 | 0.000000 | 0.000000 | 0 | 0 |
| executing | 0.000003 | 0.000000 | 0.000000 | 0 | 0 |
| Sending data | 0.007554 | 0.000000 | 0.000000 | 0 | 0 |
| end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| query end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
| freeing items | 0.000043 | 0.000000 | 0.000000 | 0 | 0 |
| logging slow query | 0.000002 | 0.000000 | 0.000000 | 0 | 0 |
| cleaning up | 0.000004 | 0.000000 | 0.000000 | 0 | 0 |
+--------------------------------+----------+----------+------------+--------------+---------------+
通過profile我們可以明顯的看到使用user_nick的時候,耗時主要用在opening tables和Sending data,在一些字符類型過濾較高的條件上,我們可以采用這種方法來優化查詢。
參考:《High Performance MySQL》