SQL优化——插入数据、主键优化、order by 优化、group by 优化、limit 优化、count优化、update优化、

目录

1、SQL优化1——插入数据(Insert)

1.1、普通插入:

1.1.1、采用批量插入(一次插入的数据不建议超过1000条)

1.1.2、手动提交事务

1.1.3、主键顺序插入

1.2、大批量插入

1.2.1、在客户端连接服务器的时候,不用mysql -u root -p,加上参数--local-infile(这一行在bash/cmd界面输入)

1.2.2、设置全局函数local_infile=1,也就是开启从本地加载文件导入数据的开关

1.2.3、查看开关是否开启

1.2.4、执行load指令将准备好的数据,加载到表结构中

2、SQL优化2——主键优化

2.1、页分裂

2.1.1、主键顺序插入:会根据主键的ID顺序进行插入,第一页写完之后,开始第二页,之间会维护一个双向指针

2.1.2、主键乱序插入:主键ID不是排序好的, 当我们要插入ID=50的时候,因为叶子节点是有序的,所以50必须存放在47之后,也就是应该将50放在第一页。

2.2、页合并

2.3、主键索引设计原则

2.3.1、满足业务条件的情况下,尽量减小主键的长度,因为耳机索引的时候叶子节点挂的是主键

2.3.2、插入数据的时候,尽量选择顺序插入,可以选择自增主键

2.3.3、尽量不要使用无序,长度太长的作为主键,例如身份证

2.3.4、在实际操作的时候,尽量避免对主键的操作

3、SQL优化3——order by 优化

3.1、using filesort

3.2、using index

3.3、举个例子

3.3.1、创建表格

3.3.2、执行以下两个查询语句。

3.3.3、但是当name升序,phone降序,又会出现什么情况呢

4、SQL优化4——group by 优化

4.1、从表中查找gender,并对gender进行分组

4.2、此时可以给这个字段添加索引,提高效率

4.3、执行语句

4.4、总结:

4.4.1、在分组操作时,可以通过索引来提高效率

4.4.2、分组操作的时候,还是必须要满足最左前缀法则的 

5、SQL优化5——limit 优化

5.1、优化方案

5.1.1、通过创建覆盖索引能够比较好的提高性能

5.1.2、之后,通过覆盖索引加子查询形式进行优化

5.2、实施例子

5.2.1、查询9000000-9000010

5.2.2、使用覆盖索引加快速度,直接通过主键索引进行排序和查询,先执行order by再执行limit

5.2.3、通过id找数据

5.3、总结

6、SQL优化6——count优化

6.1、count的几种用法

6.1.1、如果count函数的参数(count里面写的字段)不是null(字段值不是null),累计就加一,最后返回累计值

6.1.2、用法:count(*)、count(主键)、count(字段)、count(1)

6.1.3、count(*)和count(主键)一样,因为主键不可以为空;count(字段)只计算字段值不是null的行;count(1)引擎会为每一行添加一个1,然后count这个1,返回结果也跟count(*)一样;count(null)返回0

6.2、count用法的性能

6.2.1、count(主键):InnoDB引擎会遍历整张表,把每行的主键id都取出来,返回给服务层,服务层拿到主键之后,直接按照行进行累加(主键不可能为空)

6.2.2、count(字段):没有not null约束的话,InnoDB引擎会遍历整张表,把每一行的字段值都取出来,返回给服务层,服务层会判断是否为null,不为null,计数累加。如果有not null约束的话,InnoDB引擎会遍历整张表,把每一行的字段值都取出来,返回给服务层,直接按行进行累加

6.2.3、count(1):InnoDB引擎会遍历整张表,但不取值,服务层对于返回的每一层,放一个数字1进去,直接按行进行累加

6.2.4、count(*):InnoDB引擎并不会把全部字段都取出来,而是专门做了优化,不取值,服务层直接按行进行累加;

6.3、总结效率

7、SQL优化7——update优化

7.1、这句sql语句id有主键索引,索引只会锁这一行

7.2、这句话name没有索引,所以会将整张表都锁住进行数据更新(当我们开了两个事务的时候,必须等这句话的事务完成之后,才能提交另一个事务)


1、SQL优化1——插入数据(Insert)

在SQL优化中,如何高效插入数据也是比较重要的一点,那么现有的插入数据类型主要分为普通插入和大批量插入。

1.1、普通插入:

1.1.1、采用批量插入(一次插入的数据不建议超过1000条)

语法:

Insert into tb_test values(1,'A'),(2,'B'),(3,'C')...;

1.1.2、手动提交事务

这比起1.1的优点就是1.1在没插入一次数据就要提交一次,而手动提交事务是所有的数据插入完成之后,一起进行提交,相比较于1.1更高效,更省时间

语法:

Start transaction;
Insert into tb_test values(1,'A'),(2,'B'),(3,'C')...;
Insert into tb_test values(4,'D'),(5,'E'),(6,'F')...;
Insert into tb_test values(7,'G'),(8,'H'),(9,'I')...;
......
commit;

1.1.3、主键顺序插入

举个例子:

乱序插入:4,7,2,5,78,9,1;

顺序插入:1,2,5,4,7,9,78;

顺序插入的性能会比乱序插入的性能更高

1.2、大批量插入

如果一次性需要插入大量的数据(上百万的数据100w-500w),使用insert插入的话就很低效,性能较低,此时可以使用MySQL数据库提供的load指令插入

语法:

1.2.1、在客户端连接服务器的时候,不用mysql -u root -p,加上参数--local-infile(这一行在bash/cmd界面输入)

mysql --local-infile -u root -p

1.2.2、设置全局函数local_infile=1,也就是开启从本地加载文件导入数据的开关

set global local_infile=1;

1.2.3、查看开关是否开启

select @@local_infile;

1.2.4、执行load指令将准备好的数据,加载到表结构中

load data local infile '/你的sql文件地址' into table 'tb_user' fields terminated by ',' lines terminated by '\n';

 在InnoDB存储引擎中,表数据都是根据主键顺序组织存放的(聚集索引,主键下面挂的是一行数据),这种存储方式的表称为索引组织表(index organized table, IOT )。

2、SQL优化2——主键优化

2.1、页分裂

主键索引的页可以为空,也可以为一半,也可以为100%,每个页都会包含2N行数据(如果一行的数据过大,超出了一定的阈值之后,会出现行溢出)

2.1.1、主键顺序插入:会根据主键的ID顺序进行插入,第一页写完之后,开始第二页,之间会维护一个双向指针

2.1.2、主键乱序插入:主键ID不是排序好的, 当我们要插入ID=50的时候,因为叶子节点是有序的,所以50必须存放在47之后,也就是应该将50放在第一页。

但是第一页现在剩下的空间不够ID=50,那么此时就会开辟新的数据页,找到第一个数据页50%的数据,将23和47这两个数据移动到第三页,再将50放在47后面

此时双向链表第一页就把不能接上第二页了,而是指向第三页。这种现象就叫页分裂

2.2、页合并

当删除一行记录的时候,实际上记录并没有被物理删除,只是标记一下(例如红色圆圈里面的13,14,15,16),并且这四个空间变得运行被其他记录声明使用。当页中删除的记(MERGE_THRESHOLD)页的50%的时候,InnoDB会寻找最靠近的前后页,看看是否可以将两个页合并,从而优化空间。

也就是说,当13,14,15,16被标记删除后,系统会找到第三页的17,18,19.将这三个数据放在第二页,那么第三页就空出来了,这样就可以达到优化空间的效果

 MERGE_THRESHOLD:可以自己设计

2.3、主键索引设计原则

2.3.1、满足业务条件的情况下,尽量减小主键的长度,因为耳机索引的时候叶子节点挂的是主键

2.3.2、插入数据的时候,尽量选择顺序插入,可以选择自增主键

2.3.3、尽量不要使用无序,长度太长的作为主键,例如身份证

2.3.4、在实际操作的时候,尽量避免对主键的操作

3、SQL优化3——order by 优化

 关于SQL优化,order by 在执行过程中会出现两种类型:using index 和 using filesort

3.1、using filesort

using filesort:通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区sort buffer中完成排序操作。所有不是通过索引直接返回排序结果的排序都叫做filesort排序

3.2、using index

using index:通过有序序列顺序扫描直接返回有序数据,这种情况即为using index,不需要额外排序,操作效率高。

3.3、举个例子

3.3.1、创建表格

索引为:

3.3.2、执行以下两个查询语句。

explain select id, age, phone from tb_user order by age;
explain select id, age, phone from tb_user order by age,phone;

发现Extra都是using filesort,查询效率不高,解决办法就是

create index index_age_phone on tb_user(age,phone);

 发现现在的都是using index,查询效率提高

3.3.3、但是当name升序,phone降序,又会出现什么情况呢

explain select id, age, phone from tb_user order by age asc,phone desc;

发现既有using index又有using filesort。因为age升序之后,phone需要反向排序

解决办法就是,建立索引

create index index_age_phone_ad on tb_user(age asc,phone desc);

4、SQL优化4——group by 优化

 在SQL优化的时候,group by分组操作的时候,可以通过索引来提高效率

举个例子

4.1、从表中查找gender,并对gender进行分组

 explain select gender, count(*) from tb_user group by gender;

发现Extra=using temporary,表示效率不高。

4.2、此时可以给这个字段添加索引,提高效率

 create index index_user_gender_age_phone on tb_user(gender,age,phone);

4.3、执行语句

explain select age, count(*) from tb_user group by age;

出现这个原因是因为,他违背了最左前缀法则

解决:

 explain select gender, age, count(*) from tb_user group by gender, age;

或者

explain select  age, count(*) from tb_user where gender='1' group by age;

4.4、总结:

4.4.1、在分组操作时,可以通过索引来提高效率

4.4.2、分组操作的时候,还是必须要满足最左前缀法则的 

5、SQL优化5——limit 优化

 如果数据量很小的时候,limit优化效果是很不明显的,当数据量很大的时候(上百万),需要分页查询数据的时候,例如limit 2000000,10,此时需要MySQL排序前2000000条记录,但是我们仅仅需要得到的数据量只有2000000-2000010,这10个记录,其他的记录丢弃,这样会造成排序的代价非常大。那么,该如何优化呢?

5.1、优化方案

5.1.1、通过创建覆盖索引能够比较好的提高性能

5.1.2、之后,通过覆盖索引加子查询形式进行优化

5.2、实施例子

5.2.1、查询9000000-9000010

select * from tb_user limit 9000000,10;

这个语句将会耗时很长,如何解决呢?

5.2.2、使用覆盖索引加快速度,直接通过主键索引进行排序和查询,先执行order by再执行limit

select id from tb_user order by id limit 9000000,10;

这个语句就得到了9000000-9000010这10个数据的id

5.2.3、通过id找数据

错误示范:MySQL不支持in里面使用limit

select * from tb_user where id in (select id from tb_user order by id limit 9000000,10);

正确动作:将select * from tb_user where id in (select id from tb_user order by id limit 9000000,10);的结果看成一张表

select t.* from tb_user as t, (select id from tb_user order by id limit 9000000,10) as a where t.id=a.id;

5.3、总结

limit优化包括两个步骤:先覆盖索引,再子查询。

6、SQL优化6——count优化

关于count优化,首先我们先来看一下引擎。

MyISAM引擎:把一个表的总行数存在了磁盘上,因此执行coount(*)的时候会直接返回这个数,效率很高(前提是不适用where);

InnoDB引擎:在执行count(*)的时候,需要把数据一行一行的从引擎中读出来,然后累计技术。那么InnoDB引擎是现有的最常用的引擎,该如何进行优化呢?可以自己去维护,自己计数,写入一个数据,就加一;

6.1、count的几种用法

6.1.1、如果count函数的参数(count里面写的字段)不是null(字段值不是null),累计就加一,最后返回累计值

6.1.2、用法:count(*)、count(主键)、count(字段)、count(1)

6.1.3、count(*)和count(主键)一样,因为主键不可以为空;count(字段)只计算字段值不是null的行;count(1)引擎会为每一行添加一个1,然后count这个1,返回结果也跟count(*)一样;count(null)返回0

6.2、count用法的性能

6.2.1、count(主键):InnoDB引擎会遍历整张表,把每行的主键id都取出来,返回给服务层,服务层拿到主键之后,直接按照行进行累加(主键不可能为空)

6.2.2、count(字段):没有not null约束的话,InnoDB引擎会遍历整张表,把每一行的字段值都取出来,返回给服务层,服务层会判断是否为null,不为null,计数累加。如果有not null约束的话,InnoDB引擎会遍历整张表,把每一行的字段值都取出来,返回给服务层,直接按行进行累加

6.2.3、count(1):InnoDB引擎会遍历整张表但不取值,服务层对于返回的每一层,放一个数字1进去,直接按行进行累加

6.2.4、count(*):InnoDB引擎并不会把全部字段都取出来,而是专门做了优化,不取值,服务层直接按行进行累加;

6.3、总结效率

count(字段)<count(主键)<count(1)<count(*),索引尽量使用count(*)。

7、SQL优化7——update优化

 在update优化的时候,尽量避免行锁升级为表锁

InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效,否则会从行锁升级为表锁

7.1、这句sql语句id有主键索引,索引只会锁这一行

update tb_user set number='123' where id=1;

7.2、这句话name没有索引,所以会将整张表都锁住进行数据更新(当我们开了两个事务的时候,必须等这句话的事务完成之后,才能提交另一个事务)

update tb_user set number='123' where name='test';

那么如果改进呢?就是给name字段创建索引

  • 76
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQL中,ORDER BY语句用于对查询结果进行排序。为了优化ORDER BY操作,可以考虑建立适当的索引和使用合适的排序方式。 一种常见的优化方式是建立适当的索引。索引可以提高查询的性能,特别是在排序操作中。通过在排序字段上创建索引,可以避免使用文件排序(Using filesort),从而提高查询性能。在给定的示例中,引用展示了一个排序SQL语句: "SELECT id, age, phone FROM tb_user ORDER BY age;"。为了优化这个排序操作,我们可以在age字段上创建索引。 另外,在排序操作中,使用合适的排序方式也是重要的优化因素。引用指出,使用索引(Using index)的性能更高,而使用文件排序(Using filesort)的性能较低。因此,我们应尽量优化为使用索引(Using index)进行排序操作。 对于降序排序,同样可以进行优化。引用给出了一个根据age和phone进行降序排序的示例SQL语句: "SELECT id, age, phone FROM tb_user ORDER BY age DESC, phone DESC;"。在这种情况下,我们可以在age和phone字段上创建降序的索引,以进一步提高性能。 综上所述,为了优化SQL中的ORDER BY操作,我们可以考虑建立适当的索引并使用合适的排序方式,以提高查询的性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [MySQL高级 SQL优化order by&group by优化】](https://blog.csdn.net/m0_64550837/article/details/128534787)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值