MySQL进阶:SQL优化

SQL优化

插入数据

  1. 插入多条数据,可以采用批量操作(不建议超过1000条, 500到1000是比较合适的)。超过的话,分成多条批量插入语句。

    INSERT INTO tabel_name VALUES(1, 'Tom'),(2, 'Jack'),(3, 'Bob');
    
  2. 手动提交事物, MySQL默认自动提交事物,会频繁开启事物并提交。

  3. 主键顺序插入。顺序插入的性能高于乱序插入。(主键优化)

大批量插入数据,不建议使用insert了,可以采用MySQL提供的load指令。
load: 本地文件---->数据库

# 客户端连接时,加上参数--local-infile
mysql --local-infile -u root -p
# 设置全局参数local_infile为1,开启从本地文件导入数据的开关
set local_infile=1;
# 执行load指令,将准备好的数据加载到表结构中
load data local infile '/data_path' into table table_name fields terminated by ',' lines terminated by '\n';

load指令插入100万条数据16s,而用insert十多分钟。

主键优化

  • InnoDB引擎按照主键顺序存放数据(聚集索引:主键索引)。插入数据可以用AUTO_INCREMENT自增主键。

顺序插入,构建B+树代价小,而乱序插入,会发生很多额外的页分裂操作。

页分裂: 数据乱序插入的话,当前插入数据所应插入的位置空间不足,则需开辟一个新的空页,找到前一个数据页50%的位置,将后半的数据移到新的空数据页,然后插入新数据到新的数据页,然后调整指针,把新页放到正确的位置。
页合并: 删除数据行时,不会真正的从磁盘删除,而是标志位标志为删除,并且它空间可被其他记录使用。当页中删除的记录数达到MERGE_THRESHOLD(默认页的50%)时,InnoDB会从邻近的页查找是否可以合并的页,从而优化空间的使用。

  • 满足业务需求情况下,尽量减小主键长度。(节省磁盘空间,提高磁盘IO效率)

  • 尽量不使用UUID做主键或其他自然主键,如身份证号等(它们往往是无序的)。

  • 业务操作时,尽量避免对主键的修改。

order by优化

using filesort: 需要通过遍历索引或全表扫描获取符合条件的数据,然后将数据放入sort buffer中进行排序,凡是没有通过索引获取排序结果的排序都叫filesort排序。
using index:直接读取有序索引,获取排序结果。

  • 根据排序字段建立合适的索引,多字段排序时也遵循最左前缀法则。

  • 尽量使用覆盖索引。如果不是覆盖索引,会回表查询数据,然后在排序缓冲区对数据进行排序。

  • 多字段排序,一个升序一个降序,此时需注意创建联合索引时的规则。

    create index idx_name on tb_name(col1 asc, col2 desc);
    
  • 如果不可避免的出现filesort,大数据量排序时,可以适当增大排序缓冲区大小sort_buffer_size(默认256k)。

group by优化

  • 通过建立适当的索引来提升分组效率。
  • 分组使用索引也满足最左前缀法则。

limit优化

当limit起始位置很大时是比较耗时的,例如:

select * from table limit(2000000, 10);

这条语句需要对前2000010条数据先进行排序,然后再返回倒数十行。

优化:
采用覆盖索引+子查询,比如先查id,然后将查询结果作为一个临时表,联结查询。(limit在子查询里不支持)。

count优化

select count(*) from table;

MyISAM引擎会存放一个表的总行数,所以执行count(*)时可以直接返回这个值,前提是没有where条件。
而InnoDB则必须一行一行地把数据读取出来,然后累计行数返回。

优化: 目前没有直接的优化策略,但是可以自行进行计数,比如利用哈希表进行记录。

count的几种用法:
count(*), count(主键), count(字段),count(某一个数)。

count不计数NULL值。

count(主键):InnoDB引擎会把每一行的主键id取出来,然后交给服务层进行累加计数,此时不用判断NULL值,主键不可能为NULL。
count(字段):
取出相应字段值,交给服务层进行计数,如果该字段没有not NULL约束,则要判断是否为NULL,有not NULL约束,则不用判断。
count(1):遍历每一行,但不取值,把得到的行交给服务层,服务层往每一行里添加数字‘1’,然后进行计数。
count(*): InnoDB对count(*)进行了优化,它不会取出所有字段值,而是服务层直接按行进行累加。

因此效率排序
count(字段) < count(主键) < count(1) ≈ count(*)

update优化

InnoDB的行锁是针对索引加的锁,而不是对记录加锁,因此如果索引失效,则行锁升级为表锁。

优化:更新操作时,尽量根据索引字段来锁定要更新的行,这样InnoDB加的就是行级锁,如果不用索引字段,则会加表锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值