请你谈谈SQL的优化机制?

1设计数据库之初,表字段的设计要遵循范式标准:

一范式1NF:字段原子性,字段不可再分割。

第二范式:消除对主键(可以唯一标识记录的字段或者字段集合)的部分函数依赖。在这里插入图片描述
课程——>老师
(周几,课程)——>老师【对主键的部分依赖:某个字段依赖复合主键中的一部分】 && (周几,课程)——>教室
解决方案:新增一个独立字段作为主键。增加一个id作为主键,而消除对主键的部分依赖:主键id(替代【(周几,课程)】)——>教室。

第三范式:消除对主键的传递依赖
传递依赖:A——>B && B——>C == A——>C。
主键id——>课程 && 课程——>老师
因此需要将此表拆分为两张表日程表和课程表(独立数据独立建表):
在这里插入图片描述

2如何定位及优化SQL语句的性能问题?创建的索引有没有被使用到?或者说怎么才可以知道这条语句运行很慢的原因?

对于低性能的SQL语句的定位,最重要也是最有效的方法就是使用执行计划,MySQL提供了explain命令来查看语句的执行计划。 可以显示数据库引擎对于SQL语句的执行的详细情况,其中包含了是否使用索引,使用什么索引,使用的索引的相关信息等。

3对于查询,加索引

4大表数据查询,还可以

1 加缓存,redis;
2 主从复制,读写分离;

3 分库分表

分库 指的是将一个数据库拆分为多个数据库,分表指的是将一个表拆分为多个表。随着业务快速发展,数据库中的数据量猛增,访问性能也变慢了,关系型数据库本身比较容易成为系统瓶颈,单机存储容量、连接数、处理能力都有限。当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库、优化索引,做很多操作时性能仍下降严重。此时需要把数据分散在不同的数据库中,使得单一数据库的数据量变小来缓解单一数据库的性能问题,从而达到提升数据库性能的目的。

使用分库分表时,主要有垂直拆分和水平拆分两种拆分模式,都属于物理空间的拆分。
垂直分库: 按照业务将表进行分类,分布到不同的数据库上面; 垂直分表: 将一张表中不常用的字段拆分到另一张表中,从而保证一张表中的字段较少,避免出现数据库跨页存储的问题,从而提升查询效率。

1 拆分后业务清晰,拆分规则明确;
2 易于数据的维护和扩展;
3 可以使得行数据变小,一个数据块(BIock) 就能存放更多的数据,在查询时就会减少I/0 次数(每次查询时读取的Block就少) ;
4 可以达到最大化利用Cache的目的,具体在垂直拆分的时候可以将不常变的字段放一起,将经常改变的放一起;

1 主键出现冗余,需要管理冗余列。
2 会引起表连接JOIN 操作(增加CPU开销)
3 依然存在单表数据量过大的问题(需要水平拆分)。
4 事务处理复杂。

水平拆分: 通过某个字段(或某几个字段),根据某种规则将数据分散至多个库或表中,每个表仅包含数据的一部分。

1 不存在单库大数据,高并发的性能瓶颈
2 切分的表的结构相同,应用层改造较少,只需要增加路由规则即可
3 提高了系统的稳定性和负载能力

1 分规则难以抽象
2 跨库Join性能较差
3 分片事务的一致性难以解决
4 数据扩容的难度和维护量极大

分库分表后会产生的问题有: 分布式事务问题、分布式主键问题和跨库join问题。
分布式事务问题可以采用XA、TCC、SAGA、 Seata等方式。
分布式主键问题可以采用UUID、SnowFlake、数据库ID表以及Redis生成主键等方式。
跨库join问题可以采用全局表、E- R分片(绑定表)等方式解决。

分布式主键: 在分库分表的环境中,数据分布在不同的数据表中,不能再借助数据库自增长特性直接生成,否则会造成不同数据表主键重复。常见的分布式主键生成策略有:
➢UUID:使用UUID做主键,可以在本地生成,没有网络消耗,所以性能非常高。但是UUID比较长,没有规律性,耗费存储空间,而且不能排序。
➢SNOWFLAKE: SnowFlake生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID重复,并且效率较高。经测试SnowFlake每秒能够产生26万个ID。缺点是强依赖机器时钟,如果多台机器环境时钟没同步,或时钟回拨,会导致发号重复或者服务会处于不可用状态。
➢Redis生成ID:Redis是单线程的,所以也可以用生成全局唯一的ID。 可以用Redis的原子操作INCR和 INCRBY来实现。使用Redis生成主键性能较高,缺点是需要程序连接,如果Redis主机宕机,则不能使用。

跨库join问题: 使用分库分表后,数据分散在不同的数据库中,这样会形成跨越多个数据库的关联查询,造成性能的急剧下降。解决跨库Join的方法有:建立全局表和使用E- R分片(绑定表)的方式。

全局表就是在多个数据库中建立同一个表的备份,这样在使用关联查询时,只要关联自己的库就可以了。使用全局表的时候,要注意:
➢表的数据量不能过大,一般为代码表或字典表
➢各个数据库全局表数据的同步

E-R:将有ER关系的记录都存储到一个库中,这样在关联查询时,就只需要在一个库就可以了。我们可以查询多个库后将数据归并返回。

5超大分页怎么处理?

第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目
为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1N: limit (pageNo-1)*pageSzie,pageSzie
   [pageNo:页码,pageSize:单页面显示条数]

超大的分页一般从两个方向上来解决.

1 数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于select * from table where age > 20 limit 1000000,10这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为select * from table where id in (select id from table where age > 20 limit 1000000,10).这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快. 同时如果ID连续的好,我们还可以select * from table where id > 1000000 limit 10,效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据。

2 从需求的角度减少这种请求…主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击。解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可。

6规范化SQL的书写

1、查询SQL尽量不要使用select,而是select具体字段。只取需要的字段,节省资源、减少网络开销。select * 进行查询时,很可能就不会使用到覆盖索引了,就会造成回表查询。

2、如果知道查询结果只有一条或者只要最大/最小一条记录,建议用limit 1。加上limit 1后,只要找到了对应的一条记录,就不会继续向下扫描了,效率将会大大提高。

3、应尽量避免在where子句中使用or来连接条件。使用or可能会使索引失效,从而全表扫描。

4、优化limit分页。

5、使用where条件限定要查询的数据,避免返回多余的行。

6、尽量避免在索引列上使用mysql的内置函数。

7、应尽量避免在 where 子句中对字段进行表达式操作,这将导致系统放弃使用索引而进行全表扫。

8、Inner join 、left join、right join,优先使用Inner join,如果是left join,左边表结果尽量小

9、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

10、使用联合索引时,注意索引列的顺序,一般遵循最左匹配原则。

11、对查询进行优化,应考虑在 where 及 order by 涉及的列上建立索引,尽量避免全表扫描。

12、如果插入数据过多,考虑批量插入。

13、在适当的时候,使用覆盖索引。

14、where子句中考虑使用默认值代替null。如果mysql优化器发现,走索引比不走索引成本还要高,肯定会放弃索引,这些条件=,>,is null,is not null经常被认为让索引失效,其实是因为一般情况下,查询的成本高,优化器自动放弃的。如果把null值,换成默认值,很多时候让走索引成为可能,表达意思会相对清晰一点。

15、不要有超过5个以上的表连接。

16、当在SQL语句中连接多个表时,请使用表的别名,并把别名前缀于每一列上,这样语义更加清晰。

17、使用explain 分析你SQL的计划

7为什么要尽量设定一个主键?

主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键。设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全。

8主键使用自增ID还是UUID?

推荐使用自增ID,不要使用UUID。
因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值