先对索引做个大概回顾,然后我们详细探讨SQL优化
主键索引
设定为主键后数据库会自动建立索引,innodb为聚簇索引
单值索引
即一个索引只包含单个列,一个表可以有多个单列索引【建议不要超过3】
唯一索引
索引列的值必须唯一,但允许有空值
复合索引
又称之为 组合索引、联合索引即一个索引包含多个列
(工号、名称、入职日期) 作为一个组合索引,将会生成的索引目录结构。由接口可以看出,工号是最先需要判断的字段,所以工号这个查询条件必须存在工号判断完,才会判断名称名称判断完才会判断入职日期
也就是说,组合索引查询条件必须得带有最左边的列:对于我们的索引:
索引的优点
索引的缺点
在应用开发的过程中,由于前期数据量少,开发人员编写的SQL语句或者数据库整体解决方案都更重视在功能上的实现, 但是当应用系统正式上线后,随着生成数据量的急剧增长,很多SQL语句和数据库整体方案开始逐渐显露出了性 能问题,对生成的影响也越来越大,此时Mysql数据库的性能问题成为系统应用的瓶颈,因此需要进行Mysql数据库的性能优化。
select * from order
select id,name.age from order
select id form ordero left join user u on o.user_id = u.id left join user_Info ui on ui.user_id = u.id where u.age >18 and ui.school ='人民大学'
SQL及索引优化
数据库表结构优化
系统配置优化
内核优化:linux 基础之-高并发内核优化_王道长的编程之路的博客-CSDN博客
硬件优化
如果我们需要一次性往数据库表中插入多条记录,可以从以下三个方面进行优化。
优化方案一
批量插入数据
Insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
优化方案二
手动控制事务
start transaction;
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
insert into tb_test values(4,'Tom'),(5,'Cat'),(6,'Jerry');
insert into tb_test values(7,'Tom'),(8,'Cat'),(9,'Jerry');
commit;
优化方案三
主键顺序插入,性能要高于乱序插入。
如果一次性需要插入大批量数据(比如: 几百万的记录),使用insert语句插入性能较低,此时可以使 用MySQL数据库提供的load指令进行插入。操作如下:
可以执行如下指令,将数据脚本文件中的数据加载到表结构中:
-- 客户端连接服务端时,加上参数 -–local-infile
mysql –-local-infile -u root -p
-- 设置全局参数local_infile为1,开启从本地加载文件导入数据的开关
set global local_infile = 1;
-- 执行load指令将准备好的数据,加载到表结构中
load data local infile '/root/sql1.log' into table tb_user fields terminated by ',' lines terminated by '\n' ;
主键顺序插入性能高于乱序插入
为什么主键顺序插入的性能是要高于乱序插入的 ?
在InnoDB存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表行数据,都是存储在聚集索引的叶子节点上的。而我们之前也讲解过InnoDB的逻辑结构图:
在InnoDB引擎中,数据行是记录在逻辑结构 page 页中的,而每一个页的大小是固定的,默认16K。 那也就意味着, 一个页中所存储的行也是有限的,如果插入的数据行row在该页存储不小,将会存储 到下一个页中,页与页之间会通过指针连接。
页可以为空,也可以填充一半,也可以填充100%。每个页包含了2-N行数据(如果一行数据过大,会行溢出),根据主键排列。
主键乱序插入可能会产生页分裂!
当页中删除的记录达到 MERGE_THRESHOLD(默认为页的50%),InnoDB会开始寻找最靠近的页(前 或后)看看是否可以将两个页合并以优化空间使用。
MySQL的排序,有两种方式:
Using filesort : 通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 FileSort 排序。
Using index : 通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index,不需要 额外排序,操作效率高。
对于以上的两种排序方式,Using index的性能高,而Using filesort的性能低,我们在优化排序操作时,尽量要优化为 Using index。
在分组操作中,我们需要通过以下两点进行优化,以提升性能:
A. 在分组操作时,可以通过索引来提高效率。
B. 分组操作时,索引的使用也是满足最左前缀法则的。
分页查询时,如果执行 limit 2000000,10 ,此时需要MySQL排序前2000010 记 录,仅仅返回 2000000 - 2000010 的记录,其他记录丢弃,查询排序的代价非常大 。
优化思路: 一般分页查询时,通过创建覆盖索引能够比较好地提高性能,可以通过覆盖索引加子查询形式进行优化。
select * from tb_sku t , (select id from tb_sku order by id
limit 2000000,10) a where t.id = a.id;
如果说要大幅度提升InnoDB表的count效率,主要的优化思路:自己计数(可以借助于redis这样的数 据库进行,但是如果是带条件的count又比较麻烦了)。
count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加,最后返回累计值。
用法:count(*)、count(主键)、count(字段)、count(数字)
按照效率排序的话,count(字段) < count(主键 id) < count(1) ≈ count(*),所以尽量使用 count(*)。
我们主要需要注意一下update语句执行时的注意事项。
update course set name = 'javaEE' where id = 1 ;
当我们在执行删除的SQL语句时,会锁定id为1这一行的数据,然后事务提交之后,行锁释放。
但是当我们在执行如下SQL时。
update course set name = 'SpringBoot' where name = 'PHP' ;
当我们开启多个事务,在执行上述的SQL时,我们发现行锁升级为了表锁。 导致该update语句的性能 大大降低。
InnoDB的行锁是针对索引加的锁,不是针对记录加的锁 ,并且该索引不能失效,否则会从行锁升级为表锁 。
插入数据
insert:批量插入/手动控制事务/主键顺序插入
大批量插入:load data local infile
主键优化
主键长度尽量短/顺序插入
order by优化
using index:直接通过索引返回数据,性能高
using filesort:需要将返回的结果在排序缓冲区排序
group by优化
最好走索引,多字段分组满足最左前缀法则
limit优化
覆盖索引+子查询
count优化
性能:count(字段) < count(主键 id) < count(1) ≈ count(*)
uodate优化
尽量根据主键/索引字段进行数据更新