SQL优化

插入数据

insert优化
  • 批量插入,每次批量插入1000条数据
  • 手动提交事务
  • 按主键顺序插入
大批量插入数据
  • 使用MySQL数据库提供的 load 指令进行插入
  • 顺序插入性能更好
#客户端连接服务器时,加上参数 --local-infile
mysql --local-infile -u root -p
#设置全局参数local_infile为1,开启从本地加载文件导入数据的开关
set global local_infile=1;
#执行load指令将准备好的数据,加载到表结构中
load data local infile '/root/xxx.sql' into table 'tb_user' 
fields terminated by ',' lines terminated by '\n';

主键优化

几个概念
  • 数据组织方式:在InnoDB存储引擎中,表数据都是根据主键顺序组织存放的,这种存储方式的表称为索引组织表
  • 页分裂:当不按主键顺序插入数据时,会新开辟一个页,用于维护主键的顺序性,并更改页之间指针的指向
  • 页合并:删除一条记录时,在页中做标记,并不会立刻删除,当一个页删除元素达到了阈值,InnoDB会查找相邻的页是否可以合并
  • MERGE_THRESHOLD:合并页的阈值,默认50%,可以在创建表或创建索引时指定
主键设计原则
  • 满足业务需求的情况下,尽量降低主键的长度。二级索引叶子结点存放主键,主键越长,二级索引所占空间越大。
  • 插入数据时,尽量选择顺序插入,选择使用AUTO_INCREMENT自增主键。避免页分裂现象。
  • 尽量不用使用UUID做主键或者其他自然主键,如身份证号。它们是无序的。
  • 在业务操作时,避免对主键的修改。修改主键会改变索引结构,代价比较大。

order by优化

  • 根据排序字段 建立合适的索引,多字段排序也遵循最左前缀法则
  • 尽量使用覆盖索引,避免回表查询
  • 多字段排序,一个升序一个降序,可以在创建索引时指定索引的排序规则
  • 如果不可避免的出现filesort,大数据排序时,可以适当增大排序缓冲区的大小 sort_buffer_size(默认256k),如果超过阈值,会在磁盘文件中进行排序,效率很低
MySQL的两种排序方式
  1. Using filesort:需要将返回的结果在排序缓冲区排序
  2. Using index:通过索引顺序扫描直接返回有序数据,不需要额外排序,效率高
#默认创建一个升序排序的联合索引
create index idx_user_age_phone_aa on tb_user(age,phone);
#使用了idx_user_age_phone_aa索引,Extra内容为 Using index
explain select id,age,phone from tb_user order by age,phone;
#使用了idx_user_age_phone_aa索引,Extra内容为 Backward index scan;Using index
explain select id,age,phone from tb_user order by age desc,phone desc;
#不满足最左前缀法则,Extra内容为 Using index;Using filesort
explain select id,age,phone from tb_user order by phone,age;
#age排序用到了联合索引,但倒序排序phone时需要额外的排序,Extra内容为Using index;Using filesort
explain select id,age,phone from tb_user order by age asc,phone desc;

#对特殊的排序规则,可以按不同的排序规则创建索引
create index idx_user_age_phone_ad on tb_user(age asc,phone desc);
#此时将使用idx_user_age_phone_ad索引,Extra内容为Using index
explain select id,age,phone from tb_user order by age asc,phone desc;

group by 优化

  • 建立索引提高性能,建立的索引也满足最左前缀法则
  • 尽量使用覆盖索引,避免回表查询
#创建一个联合索引
create index idx_user_pro_age_sta on tb_user(profession,age,status);

#使用了idx_user_pro_age_sta索引,Extra内容为 Using index
explain select profession,count(*) from tb_user group by profession;
#不满足最左前缀法则,用到了临时表,Extra内容为 Using index;Using temporary
explain select profession,count(*) from tb_user group by age;
#where和group by 连用,如果遵循最左前缀法则,也会用到索引,Extra内容为 Using index
explain select profession,count(*) from tb_user where profession='软件工程' group by age;

limit 优化

  • 官方给的优化方式是:覆盖索引+子查询
#原始SQL
select * from tb_sku order by id limit 9000000,10;
#覆盖查询后的SQL
select id from tb_sku order by id limit 9000000,10;
#覆盖查询+子查询后的SQL,但当前版本不支持在 in 后 用到 limit
select * from tb_sku where id in (select id from tb_sku order by id limit 9000000,10);
#另一种写法,表连接查询
select s.* from tb_sku s,(select id from tb_sku order by id limit 9000000,10) a where s.id=a.id;

count 优化

MyISAM 引擎把一个表的总行数存在了磁盘中,count(*)会直接返回总行数

InnoDB 引擎执行count(*),需要遍历所有行数据,然后进行累加计数

优化思路:借助Redis自行维护计数,插入数据时记录数+1,删除记录时记录数-1
count的几种用法
  • count(主键):InnoDB 引擎会遍历整张表,把每一行的主键id取出,返回给服务层。服务层拿到主键后进行累加

  • count(字段):

    • 有 not null 约束,InnoDB 引擎遍历整表取出每行字段值,返回给服务层。服务层直接累加
    • 没有 not null 约束,InnoDB 引擎遍历整表取出每行字段值,返回给服务层。服务层判断是否为空,不为空则计数累加
  • count(1):InnoDB 引擎会遍历整张表,但不取值。服务层对返回的每一行,放一个数字1进去,直接进行累加

  • count(*):InnoDB做过优化,不会取出全部字段,而是在服务层直接累加

  • 按照效率排序:count(*) > count(1) > count(主键) > count(字段)


Update 优化

InnoDB的行锁是针对索引加的锁,在更新数据时,根据索引去更新只会触发行锁,不根据索引更新 或 索引失效 会触发表锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dynamic_Pro

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值