MySQL 加入中间表和索引提高搜索效率以及触发器的使用

130 阅读6分钟

索引

 

索引的主要作用是加快数据的查找,但是索引本身也是需要存储的,由于索引文件可能很大,因此不能常驻内存,在用到的时候需要从硬盘种加载,常识性我们都知道,计算机io是非常耗时的操作,那么如何减少io便是索引设计的重点。

 

mysql的索引使用的是b+树(数据结构不详细介绍,请自行查阅资料),那么为什么要用b+树,不用b-树或者红黑树。假设树每访问一层需要一次io,那这样首先把红黑树给排除掉。再来对比b-tree和其变形b+tree,首先b-tree路由节点也可能保存数据本身,这就导致同样大小的路由节点保存的路由信息就会减少,一个节点的数据太大,一次io读取不了完整的节点信息,那么就需要多次io耗时增加。由于b+tree路由节点只保存路由信息,那么相同的空间能放更多的路由信息,这也就意味着更少的io。

mysql索引属于存储引擎,不同存储引擎实现方式不同。

 

MyISAM引擎使用b+tree作为索引,叶子节点data存放的是记录地址。MyISAM中主索引与辅助索引形式是一样的,主索引要求key不能重复,辅助索引key可以重复。这种索引方式叫非聚集索引。

 

InnoDB引擎,与MyISAM索引与数据分开存放不同的是,InnoDB引擎数据文件本身就是一个索引,InnoDB引擎数据存放是按b+tree结构组织存放的,叶子节点包含全部的数据信息,这个树的key就是主键,这样的设计会导致数据按照主键聚集,所以这种方式叫聚集索引,正是因为这样,InnoDB引擎要求表必须有主键,这样的设计可以使按主键的查找非常高效。
InnoDB引擎辅助索引叶子节点存放的是主键,正式这个设计,所以不建议主键使用长字段,因为会导致辅助索引data占用空间太大。

创建二张测试表

DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) NOT NULL,
  `user_password` varchar(255) NOT NULL,
  `phone` varchar(255) NOT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=113418 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_details`;
CREATE TABLE `t_details` (
  `details_id` bigint(8) NOT NULL AUTO_INCREMENT,
  `details_name` varchar(255) DEFAULT NULL,
  `details_phone` varchar(255) DEFAULT NULL,
  `details_gender` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`details_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

写个函数往t_user表里插入2万条数据

begin                                                                 /*开始*/

declare num001 , num002 int(11);                                /*定义num001和num002的数据类型为int*/
declare sessionid VARCHAR(50);

set num001 = 137 , num002 = 10020000;                            /*设置num001=137,num002=10000001*/
SET sessionid = 'CD9A5B83DB39E152CBE7EE';
while num002 > 10000000 do                                     /*num002大于10000000时一直添加*/

insert into t_user(user_name,user_password,phone)

values(concat("克隆人" , num001) ,sessionid,  concat(num001 , num002));        /*在t_user表中插入数据*/

set num002 = num002-1;             /*设置num002=num002+1*/

end while;                                                          /*循环2万次*/

end

把t_user表数据同步到t_details中

insert into t_details(details_name,details_phone,details_gender) 
select user_name,phone,'男' from t_user

测试了二次未加索引时平均查询时间44秒

现在对二张表分别加上索引

 

0.1秒中不到

在二个关联字段为纯数字类型时,加索引会提高很高效率

中间表

 

把t_user表和t_details表数据清空,手机号存VARCHAR类型的数据

继续用函数添加20万条t_user表数据

begin                                                                 /*开始*/

declare num001 VARCHAR(50);
declare num002 int(11);                                
declare sessionid VARCHAR(50);


SET num001 = '13***';
SET num002 = 1200000;                            
SET sessionid = 'CD9A5B83DB39E152CBE7EE';
while num002 > 1000000 do                                     /*num002一直大于0 所以无限循环添加*/

insert into t_user(user_name,user_password,phone)

values(concat("克隆人" , num002) ,sessionid,  concat(num001 , num002));        /*在t_user表中插入数据*/

set num002 = num002-1;             /*设置num002=num002+1*/

end while;                                                          /*当num<1000000时,不再执行插入操作循环结束*/

end

 

和上面一样,把t_user表数据同步到t_details中

通过details_phone = phone关联查询二张表的数据,本次直接加了索引后的开始

创建中间表

DROP TABLE IF EXISTS `user_details_ext`;
CREATE TABLE `user_details_ext` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` bigint(20) NOT NULL,
  `phone_crc_32` bigint(20) NOT NULL,
  `phone` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `phone_crc_32` (`phone_crc_32`) USING BTREE,
  KEY `user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=270332 DEFAULT CHARSET=utf8mb4;

t_user表中的phone转换成crc32存储到user_details_ext中

CRC是什么东西呢?

其实我们大家都不应该会对它陌生,回忆一下?你用过RAR和ZIP等压缩软件吗?它们是不是常常会给你一个恼人的“CRC校验错误”信息呢?我想你应该明白了吧,CRC就是块数据的计算值,它的全称是“Cyclic Redundancy Check”,中文名是“循环冗余码”,“CRC校验”就是“循环冗余校验”。

CRC有什么用呢?

在数据存储和数据通讯领域,为了保证数据的正确,就不得不采用检错的手段

在诸多检错手段中,CRC是最著名的一种。

它的应用范围很广泛,最常见的就是在网络传输中进行信息的校对。其实我们大可以把它应用到软件保护中去,因为它的计算是非常非常非常严格的。严格到什么程度呢?你的程序只要被改动了一个字节(甚至只是大小写的改动),它的值就会跟原来的不同。所以只要给你的“原”程序计算好CRC值,储存在某个地方,然后在程序中随机地再对文件进行CRC校验,接着跟第一次生成并保存好的CRC值进行比较,如果相等的话就说明你的程序没有被修改/破解过,如果不等的话,那么很可能你的程序遭到了病毒的感染,或者被Cracker用16进制工具暴力破解过了。

CRC的原理。由于CRC实现起来有一定的难度,所以具体怎样用它来保护文件,留待下一节再讲。

insert into user_details_ext(user_id,phone_crc_32,phone) 
select user_id,crc32(phone),phone from t_user

user_details_ext中加入索引

再次查询

然后我就懵逼了,为啥反而还慢了?可能crc32(details_phone)转换时占用的时间和数据量不够吧

 

触发器

t_user表中加入一条数据

user_details_ext表刷新查看

完成