数据库查询——索引优化查询方法
本文讲解在数据库查询的时候,一个优化查询的方法,这个方法就是索引优化,讲解其中的原理和实现方法。
简介
首先这是一个简单的数据库,这个数据库很正常,如果采取mybatis-plus进行查询,也就是跟这篇文章中的代码一样:Java图书目录管理系统CRUD展示(springboot+vue+mybatis-plus)
/* Navicat MySQL Data Transfer Source Server : localhost_3306 Source Server Type : MySQL Source Server Version : 80028 Source Host : localhost:3306 Source Schema : projectdatabase Target Server Type : MySQL Target Server Version : 80028 File Encoding : 65001 Date: 31/01/2023 22:24:02 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for book -- ---------------------------- DROP TABLE IF EXISTS `book`; CREATE TABLE `book` ( `isbn` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `author` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `publisher` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `pubdate` datetime NOT NULL, `price` decimal(10, 2) NOT NULL, `id` int NOT NULL AUTO_INCREMENT, PRIMARY KEY (`id`, `isbn`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; -- ---------------------------- -- Records of book -- ---------------------------- INSERT INTO `book` VALUES ('9780439227148', 'The Call of the Wild', 'Jack London', 'Scholastic Press', '2001-01-01 00:00:00', 39.40, 1); INSERT INTO `book` VALUES ('9787501592401', 'The Old Man and the Sea', 'Ernest Hemingway', 'Knowledge Press', '2023-01-30 00:00:00', 25.80, 2); INSERT INTO `book` VALUES ('9787501592401', 'The Old Man and the Sea', 'Ernest Hemingway', 'Knowledge Press', '2023-01-31 13:02:42', 25.80, 3); INSERT INTO `book` VALUES ('9780439227148', 'The Call of the Wild', 'Jack London', 'Scholastic Press', '2023-01-30 16:00:00', 34.90, 6); INSERT INTO `book` VALUES ('9781772262902', 'Oliver Twist', 'Charles Dickens', 'Engage Books', '2023-01-03 16:00:00', 45.00, 7); SET FOREIGN_KEY_CHECKS = 1;
索引优化原理
索引优化:使用合适的索引可以加快查询速度。例如,在book表中,isbn、title、author和publisher列都是常用作搜索的字段,应为这些字段建立相应的索引。
索引可以大大提高数据库查询效率,例如在book表中的isbn、title、author和publisher列上建立相应的索引,可以极大地优化图书管理系统的CRUD操作。
以下是为book表中的isbn、title、author和publisher列分别建立索引的SQL语句:
ALTER TABLE `book` ADD INDEX `idx_isbn`(`isbn`); ALTER TABLE `book` ADD INDEX `idx_title`(`title`); ALTER TABLE `book` ADD INDEX `idx_author`(`author`); ALTER TABLE `book` ADD INDEX `idx_publisher`(`publisher`);
执行以上SQL语句即可在book表中为指定列建立索引。在查询时,MySQL会首先使用索引来检索符合条件的记录,并返回结果,从而避免全表扫描,提高查询速度。
需要注意的一点是,在建立索引的同时也会增加数据的维护成本和存储空间。因此,在选择索引字段和类型时应该视情况而定,避免过度使用,以免影响系统性能和空间占用。此外,对于频繁更新的表,过多使用索引也会降低更新速度,并且还会产生锁等额外的开销,需要结合实际需求进行选型配置。
添加索引之后,对于这个book类就是这个样子了
@Data @AllArgsConstructor @NoArgsConstructor @TableName("book") public class Book { @TableId(type = IdType.AUTO) private Long id; @TableIndex(name = "idx_isbn", type = IndexType.BTREE) private String isbn; @TableIndex(name = "idx_title", type = IndexType.BTREE) private String title; @TableIndex(name = "idx_author", type = IndexType.BTREE) private String author; @TableIndex(name = "idx_publisher", type = IndexType.BTREE) private String publisher; private Date pubdate; private Double price; }
最后来一个总结:
简单地说,索引就是数据库中用于提高查询效率的一种数据结构。它可以类比于字典的目录,可以帮助我们更快地定位到需要查询的记录。在数据库中,索引一般用B-tree(平衡树)或哈希表实现。其中,B-tree是一种多阶段平衡树,通常用于处理基于磁盘存储的数据检索;哈希表则主要针对内存型数据库,它可以使读取操作达到O(1)的时间复杂度。
在Mybatis-Plus中,通过@TableIndex注解可以为实体类中的列建立相应的索引,如上述Book实体类中的四个字段isbn、title、author和publisher,分别添加了名为idx_isbn、idx_title、idx_author和idx_publisher的BTREE类型索引。
当进行查询操作时,如果查询语句中带有这些具有索引的字段,则MySQL会选择使用相关的索引来定位符合条件的记录。由于索引能够极大地加快查询操作,因此在实际开发中,我们往往需要为需要经常进行查询的字段添加相应的索引,从而提高系统的响应速度。
需要注意的是,在建立索引的过程中,需要根据实际业务需求选择建立哪些字段的索引,同时需要权衡索引会带来的维护和存储开销。过多或不必要的索引反而会拖慢系统查询和写入速度,因此需要谨慎地进行优化。同时,在数据库数据量较大时,也可以采取分区等方式进行优化以提高性能和可用性。
总之,索引是一种重要的数据库优化手段,可以帮助我们更快地查找和定位需要的数据,但也需要根据实际情况进行优化和管理。
实际案例
假设我们有一个业务需求:需要根据作者名查询图书信息。在默认情况下,我们可以通过以下SQL语句进行查询:
SELECT * FROM book WHERE author = '张三';
但如果book表中数据量非常大,则这样的查询操作可能会耗费很长时间。为了优化查询效率,我们可以针对author字段建立索引,使其能够更快地查询到匹配的记录。
在Mybatis-Plus中,我们可以在Book实体类中对author属性添加@TableIndex注解,代码如下:
@Data @AllArgsConstructor @NoArgsConstructor @TableName("book") public class Book { @TableId(type = IdType.AUTO) private Long id; private String isbn; private String title; @TableIndex(name = "idx_author", type = IndexType.BTREE) private String author; private String publisher; private Date pubdate; private Double price; }
然后,在数据库中执行以下SQL语句,为author字段建立相应的BTREE类型的索引:
CREATE INDEX idx_author ON book(author);
这样,当我们通过以下SQL语句查询图书信息时,MySQL数据库就可以使用idx_author索引来提高查询效率:
SELECT * FROM book WHERE author = '张三';
由于索引可以帮助我们更快定位到符合条件的记录,因此当book表中数据量较大时,使用索引会大幅提高查询效率,同时也减轻了数据库的压力。
当然,在实际开发中,我们还需要根据具体业务需求进行优化。例如,如果对多个字段需要进行联合查询,则可以为这些字段创建复合索引等等。
- 原理分析
加入索引对查询效率的提升主要来自于索引的数据结构和位置,它可以有效地减少数据库中需要扫描的数据量。
在MySQL中,每一个索引都是一棵B-tree或者Hash表。当我们为author字段建立了索引之后,MySQL会把Autor字段的值按照索引的数据结构进行存储,在读取时只需要查找到符合条件的记录即可,而不必遍历整张表。
假设book表有1000万条记录,如果没有为author字段建立索引,则MySQL需要遍历整张表来寻找符合条件的记录,这个操作是非常耗时的。而当我们为author字段建立索引时,MySQL只需要在这棵B-tree上进行检索即可,由于它使用的是平衡树的数据结构,所以它每次最多需要比较log(N)次,其中N是这个B-tree的叶子节点数量。因此使用索引查询的速度是非常快的,甚至可以达到近似O(1)的时间复杂度。
需要注意的是,在实际应用中为表的字段添加索引并不是越多越好,过多的索引也可能会拖慢数据库的写入操作,并消耗大量的磁盘空间。因此,我们需要在对具体的业务需求进行分析和优化之后决定是否需要添加索引,以及需要为哪些字段添加索引。