一个索引提高600倍查询速度?首先准备一张books表
create table books(id int not null primary key auto_increment,name varchar(255) not null,author varchar(255) not null,created_at datetime not null default current_timestamp,updated_at datetime not null default current_timestamp on update current_timestamp)engine=InnoDB;
然后插入100w条数据
drop procedure prepare_data;delimiter //create procedure prepare_data()begindeclare i int;set i = 0;while i < 1000000doinsert into books(name, author) value (concat('name', i), concat('author', i));set i = i + 1;end while;end //delimiter ;call prepare_data();
那么问题来了,现在我们要在这100w本书中找到name为name9000000的书,来看看大概需要多久 。
set profiling = 1;select * from books where name = 'name900000';show profiles;set profiling = 0;
文章插图
(图一)
大概在400ms左右,我不是很满意这个查询的速度,那么如何提升查询速度呢?建个索引吧!
create index idx_books_name on books(name);
创建索引后我们再看看查询的速度set profiling = 1;select * from books where name = 'name900000';show profiles;set profiling = 0;
文章插图
(图二)
可以发现,只需要6ms,索引为我们带来600倍的速度提升,那么为什么索引可以带来这么大的查询速度提升呢?
索引揭秘想象一下,现在我们有100w条数据,如何快速的通过name找到符合条件的数据
如果这100w条数据是按照name有序排列的,那么我们就可以使用二分搜索,这样每次可以排除一半数据 。那么100w数据最多只需要查询
文章插图
【带你玩转MySQL,索引揭秘,看我是如何让你的查询性能指数提升的】
~=%2020次就可以找到
运行过程类型下图
文章插图
(图三)
这里可以发现一个问题,在比较过程中,我们只用到了name字段,但是却需要把name和其他字段一起加载到内存,这样显然会浪费很多内存,所以我们可以修改结构为下图
文章插图
(图四)
我们把原来表中的name和id字段进行一份复制形成了一个新的表,这样的话,当我们根据name来查询数据时,只需要把name和id两个数据加载到内存就行了,当找到数据后再根据id找到对应行的其他数据 。
其实这个冗余表就是我们常说的索引,索引表会把我们指定的列的数据进行拷贝形成一个新的表,这个表中的数据是有序排列的,如果有多列,则是按声明的前后关系依次比较 。
例如,有一个商品表items,其中有名称、价格、创建日期等字段
create table items(id int not null primary key auto_increment,title varchar(255) not null,price decimal(12,2) not null,created_at datetime not null,updated_at datetime not null) engine = innodb;
(图五)由于用户喜欢按价格和创建时间查找商品,我们可以创建一个idx_items_price_created_at(price, created_at)的索引,那么他的数据结构就是这样的:先按price排序,再按created_at排序,如图六
文章插图
(图六)
通过图六的数据结构我们可以学习到索引使用的一个原则和一个优化
一个原则:最左匹配原则:如果要触发索引使用,需要按索引字段的声明顺序来添加条件过滤
以items表中的idx_items_price_created_at索引使用举例:
# sql1:price + created_at条件,可以使用索引select * from items where price = "20" and created_at = '2020-01-04';# sql2:created_at + price条件,可以使用索引,注意虽然此处查询条件顺序和索引顺序不一样,但其实MySQL在执行sql前,会先对sql进行语法分析,最终的结果是和sql1一样的 。但是我不推荐这种写法,因为对于看代码的人来说没有sql1直观 。select * from items where created_at = "2020-01-04" and price = "20";# sql3:price 可以使用索引,因为索引表即使只考虑price字段,顺序也是有序的select * from items where price = "20";# sql4:crated_at 不可以使用索引,因为索引中如果只考虑craeted_at字段,顺序不能保证有序select * from items where created_at = "2020-01-04";
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 测试人员不知道密码,该怎么使用Linux中的mysql数据库?
- 手把手带你搭建一个自己的云服务器并部署Web程序
- 测试人员如何在linux服务器中查询mysql日志?
- MySQL内存管理,内存分配器和操作系统
- 基于 Canal 和 Kafka 实现 MySQL 的 Binlog 近实时同步
- 面试官:你说对 MySQL 事务很熟?那我问你 10 个问题
- MySQL到底能有多少个字段?
- MySQL数据库备份之主从同步配置
- 虚拟主机能用mysql么
- python3快速爬取房源信息,并存入mysql数据库,超详细