有哪些常见的数据库优化方法

article/2025/11/8 13:49:48

数据库优化这个话题很大,我从最常见的也是最有效的优化手段索引优化的角度来回答一下:

系统的性能瓶颈很多时候都出现在数据库,而数据库的性能优化最先入手之处应当是索引,通过索引的优化可以用最少的成本获得最大的性能提升。

我们来通过一个例子看看索引对数据库查询效率的影响:

先创建一个数据表:

CREATE TABLE `tb_user` (
 `id` BIGINT (20),
 `user_name` VARCHAR (200)
 
) ENGINE=MYISAM;
编写存储过程插入300万条记录

DELIMITER $$
CREATE
 PROCEDURE `pro_tb_user`()
 BEGIN
 DECLARE i INT;
 SET i=0;
 WHILE i>=0 && i<= 3000000 DO
 INSERT INTO `tb_user`
 (`id`, `user_name`) VALUES
 (i,'admin');
 SET i=i + 1;
 END WHILE;
 
 END$$
DELIMITER ;
调用存储过程

CALL pro_tb_user();
根据id查询:

SELECT * FROM tb_user WHERE id = 123
查询速度很快,接近0秒,因为id是主键,会添加索引。

根据user_name查询:

SELECT * FROM tb_user WHERE user_name = 'aaab'
耗时:0.69秒

查询速度较慢,因为user_name上没有索引。

现在在user_name上建立索引:

CREATE INDEX idx_item_name ON tb_user(user_name);
再来查询一次,发现耗时接近0秒,效率提升了六十多倍,这就是索引带来的巨大效率提升。

既然索引能带来如此多的性能提升,索引如何用呢?

先准备环境:

create table `tb_seller` (
 `sellerid` varchar (100),
 `name` varchar (100),
 `nickname` varchar (50),
 `password` varchar (60),
 `status` varchar (1),
 `address` varchar (100),
 `createtime` datetime,
 primary key(`sellerid`)
)engine=innodb default charset=utf8mb4;
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('alibaba','阿里巴巴','阿里小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('baidu','百度科技有限公司','百度小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('huawei','华为科技有限公司','华为小店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('luoji','罗技科技有限公司','罗技小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('oppo','OPPO科技有限公司','OPPO官方旗舰店','e10adc3949ba59abbe56e057f20f883e','0','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('ourpalm','掌趣科技股份有限公司','掌趣小店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('qiandu','千度科技','千度小店','e10adc3949ba59abbe56e057f20f883e','2','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('sina','新浪科技有限公司','新浪官方旗舰店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('xiaomi','小米科技','小米官方旗舰店','e10adc3949ba59abbe56e057f20f883e','1','西安市','2088-01-01 12:00:00');
insert into `tb_seller` (`sellerid`, `name`, `nickname`, `password`, `status`, `address`, `createtime`) values('yijia','宜家家居','宜家家居旗舰店','e10adc3949ba59abbe56e057f20f883e','1','北京市','2088-01-01 12:00:00');
我们可以创建单列索引和组合索引,究竟优先选择哪种呢?答案是组合索引,当创建一个组合索引的时候就相当于创建了多个索引。例如:

创建name,status,address三个字段的组合索引:

CREATE INDEX idx_seller_name_sta_addr ON tb_seller(NAME,STATUS,address);
相当于创建了三个索引:

name
name+status
name+status+address
在查询的时候数据库会选择最优索引。

如果查询的时候使用了索引则效率高,反之效率低,在什么情况下会使用索引什么情况下不会使用索引呢?我们来看看下面几种情况

查询的时候对组合索引中的每一列都指定具体的值,此种情况下会使用索引,效率高:

例如:

EXPLAIN SELECT * FROM tb_seller WHERE NAME='小米科技' AND STATUS='1' AND address='北京市'

5b04b4349b1049a7aa85092114e8d810.png 

1)最左前缀法则:

如果使用多个列创建了组合索引,则必须满足最左前缀法则才会使用索引,即查询条件中使用了组合索引靠左边的列就会使用索引,不能跳过组合索引的列。

例如:

EXPLAIN SELECT * FROM tb_seller WHERE NAME = '小米科技'
这条查询语句的条件使用了name,组合索引为:“name,status,address”,属于组合索引靠左边的列。

再比如:

EXPLAIN SELECT * FROM tb_seller WHERE NAME = '小米科技' AND STATUS = 1
这条查询语句的条件使用了name和status,属于组合索引靠左边的列。

再比如:

  EXPLAIN SELECT * FROM tb_seller WHERE NAME = '小米科技' AND STATUS = 1 AND address = '北京市'
这条查询语句的条件使用了name,status和address属于组合索引靠左边的列。

这三条查询语句都满足最左前缀法则会使用索引。

再来看看不符合最左前缀法则的例子:

例如:

  EXPLAIN SELECT * FROM tb_seller WHERE STATUS = 1
这条sql语句的查询条件跳过了name,直接使用status不符合最左前缀法则

  EXPLAIN SELECT * FROM tb_seller WHERE STATUS = 1 AND address='北京市'
这条sql语句同样跳过了name不符合最左前缀法则

如果查询条件跳过了组合索引的某列则只有左边的索引会生效

例如:

EXPLAIN SELECT * FROM tb_seller WHERE NAME = '小米科技' AND address='北京市'
只有name上的索引会生效

2)范围查询右边的列不能使用索引

例如:

EXPLAIN SELECT * FROM tb_seller WHERE NAME = '小米科技' AND STATUS='1' AND address = '北京市'
这条sql语句会使用组合索引中的每一列:

b516ef14b8bb4950a25a53ea040af5a8.png
下面这条sql语句使用了范围查询:

EXPLAIN SELECT * FROM tb_seller WHERE NAME = '小米科技' AND STATUS>'1' AND address = '北京市'

f67ddd53c381464daaea3ee16c3f14bc.png
索引只能使用name和status索引,不能使用address索引,因此key_len 为410 

3)如果在索引列上进行运算操作索引会失效:

例如:

EXPLAIN SELECT * FROM tb_seller WHERE SUBSTRING(NAME,3,2) = '科技' 
这个sql语句的索引列name使用了substring函数所以索引会失效。

4)字符串不加单引号会导致索引失效:

例如:

EXPLAIN SELECT * FROM tb_seller WHERE NAME='科技' AND STATUS = '0'

0101a00f02204f9aa6109cf90b00a5ac.png 

字符串’0’加了单引号,会使用索引列name和status查询

 EXPLAIN SELECT * FROM tb_seller WHERE NAME='科技' AND STATUS = '0'

27362207b2994d3e88d53562d2139e81.png  

如果使用下面的sql语句,0没有加单引号,只会使用索引列name来查询:

EXPLAIN SELECT * FROM tb_seller WHERE NAME='科技' AND STATUS = 0
5.尽量使用覆盖索引即查询的列都是索引中的列避免使用 select * :

例如:

EXPLAIN SELECT NAME,STATUS FROM tb_seller WHERE NAME='科技' AND STATUS = '0' AND address='西安市'
效率比:

EXPLAIN SELECT * FROM tb_seller WHERE NAME='科技' AND STATUS = '0' AND address='西安市'
要高。

6.用or分割开的条件当中只要有一个非索引列则不会使用索引:

例如:

EXPLAIN SELECT NAME,STATUS FROM tb_seller WHERE STATUS = '0' OR PASSWORD='123'
会导致全表扫描

7.以%开头的模糊查询索引失效。

例如:

EXPLAIN SELECT * FROM tb_seller WHERE NAME LIKE '%米'
这种情况可以采用覆盖索引来解决:

EXPLAIN SELECT NAME FROM tb_seller WHERE NAME = '小米科技'


http://chatgpt.dhexx.cn/article/YcwP2E2E.shtml

相关文章

数据库优化方案整理

一&#xff1a;优化说明 A&#xff1a;有数据表明&#xff0c;用户可以承受的最大等待时间为8秒。数据库优化策略有很多&#xff0c;设计初期&#xff0c;建立好的数据结构对于后期性能优化至关重要。因为数据库结构是系统的基石&#xff0c;基础打不好&#xff0c;使用各种优…

Mysql数据库优化

1.存储引擎 什么是存储引擎 存储引擎:可以看作是数据表存储数据的一种格式&#xff0c;不同的格式具有的特性也各不相同。 举例说明:只有InnoDB存储引擎支持事务、外键、行级锁等特性&#xff0c;而MyISAM则支持压缩机制等特性。 存储引擎的特点:本身是MySQL数据库服务器的底…

8大数据库性能优化方案,YYDS!

文章来源&#xff1a;https://c1n.cn/dLkfg 目录 前言为什么数据库会慢&#xff1f;应该站在哪个层面思考优化&#xff1f;八大方案总结结束 前言 毫不夸张的说咱们后端工程师&#xff0c;无论在哪家公司&#xff0c;呆在哪个团队&#xff0c;做哪个系统&#xff0c;遇到的第一…

Java之流水号生成器

开心一笑 视频教程 CSDN学院&#xff1a; http://edu.csdn.net/lecturer/994 腾讯学院&#xff1a; https://huangwy.ke.qq.com/ 网易学院&#xff1a; http://study.163.com/instructor/1035331499.htm 提出问题 如何使用jAVA生成流水号&#xff0c;同时支持可配置和…

业务流水号规则生成组件

对于很多业务系统都需要生成业务流水号&#xff0c;如果订单号、购采单号等等&#xff1b;而这些业务流水号并不是简单的一个增长数值&#xff0c;它们很多时候都有一些不同的规则来定义&#xff0c;如不同类型的字母或地区拼音简写等。为了更灵活生成这些有规则的业务流水号Be…

怎样生成全局唯一流水号?UUID、自增主键,你已经Out啦,快来学习定制化雪花算法。

前言 流水号是每个系统永远都绕不开的一个话题&#xff0c;如订单系统中的订单号&#xff0c;物流系统的运单号、银行系统的业务单号等等&#xff0c;不难发现这些单号虽然叫法不一样&#xff0c;但都有着一些相同的共性&#xff0c;那就是全局唯一性。除此之外&#xff0c;一…

Java自动生成订单编号+流水号

介绍 这里是小编成长之路的历程&#xff0c;也是小编的学习之路。希望和各位大佬们一起成长&#xff01; 以下为小编最喜欢的两句话&#xff1a; 要有最朴素的生活和最遥远的梦想&#xff0c;即使明天天寒地冻&#xff0c;山高水远&#xff0c;路远马亡。 一个人为什么要努力&a…

JAVA如何利用Lock实现多线程并发生成唯一的流水号

本文记录在开发过程&#xff0c;JAVA如何利用ReentrantLock实现多线程并发生成唯一的流水号。 在实际的开发中&#xff0c;我们会经常碰到需要生成唯一流水号的业务场景。有些情况可以采用数据库自定义序列号自增生成流水号&#xff0c;亦或是自己编写数据库触发器生成流水号。…

mysql 生成流水号 存储过程 订单编号

用存储过程生成流水号是很常用的&#xff0c;这里以生成订单编号的流水号作为示例。&#xff08;新的一天的流水号从1开始&#xff0c;如&#xff1a;今天的订单编号是CD2013010900014&#xff0c;下一个订单编号将是CD2013010900015&#xff1b;明天的订单编号将从CD201301100…

流水号生成规则

流水号生成规则 从“0001”号起始&#xff0c;依序不跳跃不间断地编号&#xff0c;形成流水编码&#xff0c;依次为0001、0002、0003、0004、0005、0006…等。当编至“9999”号&#xff0c;仍需继续编号时&#xff0c;从“A000”号&#xff08;A000代表10000&#xff09;起始重…

一种生成流水号的方法

1.介绍 今天做了一个功能&#xff0c;生成订单流水号&#xff0c;当然这其实这并不是一个很难的功能&#xff0c;最直接的方式就是日期主机Id随机字符串来拼接一个流水号。但是今天有个我认为比较优雅方式来实现。我要介绍是日期 long&#xff08;商家Id订单类型主机IDAtomicIn…

简单介绍订单号或者流水号的生成方法

一般订单号或者流水号等可能在一些平台会用到&#xff0c;然后我就简单的介绍一个我自己生成订单号和流水号的一个方法吧&#xff0c;如果程序有问题或者你有更好的生成办法&#xff0c;欢迎留言&#xff0c;留下你的文章链接&#xff0c;我们一起学习和进步哈。 方法简介&…

如何使用redis生成流水号

概述 本文讲述如何使用redis生成流水号。本文是在Springboot中实现的。知道原理之后其他框架也可以轻松实现。 原理介绍 本文主要是使用redis的incr方法进行自增补零。然后结合时间、随机数、前缀组成唯一的流水号。 下面是流水号的结构。 在文章的最后还是简单介绍一下redis的…

谈谈订单号和流水号的关系

订单号和流水号是不同的。 首先订单号是订单唯一的编号&#xff0c;而且电商平台的各种子系统也是根据订单来统计业务完成的情况&#xff0c;订单编号经常用来被查询&#xff0c;所以数据类型必须是数字&#xff0c;而且是全局唯一&#xff0c;那肯定就得主键字段了。 然后流水…

低代码学习教程:生成固定格式流水号

方法1&#xff1a;RECNO()方法2&#xff1a;MAPX() 表单设计中经常涉及流水号的制作问题&#xff0c;下面就分别介绍下两种编号的实现方法&#xff0c;大家可以根据需要自行选择。 注意&#xff1a; 百数已支持【流水号】控件&#xff0c;如有特殊要求可参考文档&#xff1a;…

【26天高效学习Java编程】Day19:Java 多线程

本专栏将从基础开始&#xff0c;循序渐进&#xff0c;由浅入深讲解Java的基本使用&#xff0c;希望大家都能够从中有所收获&#xff0c;也请大家多多支持。 专栏地址:26天高效学习Java编程 相关软件地址:软件地址 所有代码地址:代码地址 如果文章知识点有错误的地方&#x…

怎么入门学习Java编程

因为目前java非常火,应用非常的广泛,是目前最火的行业之一,竞争很大,工资很高,未来发展也极好。 如条件还可以,负担不是那么大,可以选择培训,培训一定会比你自学的好,如果培训都学不好,自学肯定更难。目前java的培训费用都是2W+,这还只是培训费而已,加上一些其他的…

Java学习

集合 什么是集合&#xff1f; 集合&#xff1a;集合是java中提供的一种容器&#xff0c;可以用来存储多个数据。 集合和数组的区别 数组的长度是固定的。集合的长度是可变的。 数组中存储的是同一类型的元素&#xff0c;可以存储任意类型数据。集合存储的都是引用数据类型。如…

想学习Java编程,看书还是看视频更合适?

首先&#xff1a;自己本身就是初级或者零基础的&#xff0c;自己对软件了解的都不足够&#xff0c;跟着视频学&#xff0c;老师操作操作一步你就能看着他操作&#xff0c;这样心里更有谱。 第二&#xff1a;跟着视频学能学的更好&#xff0c;知识体系更全&#xff0c;一般视频…

自学过来人告诉你,初学者应该怎么快速的学习Java编程?

我说说我个人的案例吧&#xff0c;我电子信息专业&#xff0c;后来选择做了Java开发&#xff0c;在11年的时候开始学习的Java&#xff0c;可以说那时候的企业要求低于现在&#xff0c;我当时学习由于没有钱&#xff0c;我是自学的&#xff0c;我大学学过C语言 我晚上下班的时候…