慢sql总结

前置条件背景:某项目线上环境有短信、邮件、站内信、APP消息推送服务,例如短信在线上环境发一次可能是60w的发送记录...等等,每种推送消息的渠道数据库中可能会记录上百万、千万的发送记录(开发也采用分库分表)。针对这些记录后端进行统计查询后前端展示报表数据。

 

 

解决办法:从查询方式由后端改为数仓查询

测试场景考虑:测试环境的可能因为测试数据较少,而我们需要考虑到生产环境的数据量,针对于发送记录较多的场景,判断查询方式是否合理,是否在时间久的情况下数据量过多而造成的慢sql

QA:

1、业务库采用分库分表,数仓需要怎样去统计

答:对于数仓来说没有影响

2、怎样验证慢sql优化效果

答:数仓查询前一天的数据,而且后端在查询的数仓ads结果表数据的时候,数仓已经把结果放在数据库中了,相当于后端单表查每天的数据量且按照纬度加和。之前后端自己去查询,查的是sql上万的数据,如果没有定时任务,或者每天通过sql去查询,数据量是很大的,sql就肯定会慢,影响cpu资源,响应时间等。相当于数仓有临时表缓存中间的结果,避免多次查询主表,也减少了阻塞,提高性能。以前走数据库的时候10W的数据量我们需要通过SQL去查询统计之后返回给前端显示,现在走数仓了之后我们相当于只是查我们已经统计好的某几条数据,这样对于我们来说不管是10W的数据量还是100W的数据量,都是走数仓了,而我们要查的只是统计表里面的其中某几条数据,对于我们服务器来说是没有多少压力的。

3、影响因素可能有哪些?

(1)数据量:数据量越大需要的I/O次数越多

(2)取数据的方式,数据在缓存中还是在磁盘上;是否可以通过索引快速寻址

(3)数据加工的方式,排序、子查询等,需要先把数据取到临时表中,再对数据进行加工;增加了I/O,且消耗大量CPU资源

(4)、没有索引或则无效索引导致的全表扫描

4、针对慢sql有没有好的解决思路?

(1)将数据存放在更快的地方。如果数据量不大,变化频率不高,但访问频率很高,此时应该考虑将数据放在应用端的缓存当中或者Redis这样的缓存当中,以提高存取速度。如果数据不做过滤、关联、排序等操作,仅按照key进行存取,且不考虑强一致性需求,也可考虑选用NoSQL数据库。

(2)适当合并I/O。分别执行select c1 from t1与select c2 from t1,与执行select c1,c2 from t1相比,后者开销更小。合并时也需要考虑执行时间的增加。

(3)利用分布式架构。在面对海量的数据时,通常的做法是将数据和I/O分散到多台主机上去执行。

(4)OLTP环境下通常使用innodb引擎。索引使用b+tree.

(5)通过explain sql获取的信息:第一个执行查询的表;索引的使用情况;每张表扫描到的数据条数;

(6)通过select count(distinct cl)/count(1) from table,来查询关键查询字段的选择性。越大说明选择性越高,这种字段就应该优先建立索引。

(7)analyze table 根据情况,分析table使其索引重建或则分布更加均衡。

(8)如果查询优化后,反应出来的数据仍然很多,查询很慢。这时就应该根据业务来调整查询条件。

索引无效:

1、表关联查询时,字段类型或长度不一致。如:varchar(10)和varchar(20)

2、查询参数的数据类型与索引字段类型不一致。如int = '1313'

3、in () 索引字段in查询时,通常是有效的。但是当in中指定的数据太多,优化器认为全表扫描更快时,也不会使用索引。

4、其他如:like、索引上使用函数等使索引失效。导致全表扫描

索引:向有索引的表当中插入、更新、删除数据时,都需要对索引进行相应操作, 因此索引越多,写表效率越低。索引列的选择需要注意列的离散度(唯一性)越高,越适合做索引。

复合索引:应考虑索引之间组合的顺序,将离散度最高的列放在前面

索引列长度:InnoDB单列索引长度不能超过767bytes,复合索引是3072。InnoDB一个page的默认大小是16k。由于是Btree组织,要求叶子节点上一个page至少要包含两条记录(否则就退化链表了)。所以一个记录最多不能超过8k。又由于InnoDB的聚簇索引结构,一个二级索引要包含主键索引,因此每个单个索引不能超过4k (极端情况,pk和某个二级索引都达到这个限制)。由于需要预留和辅助空间,扣掉后不能超过3500,取个“整数”就是(1024*3)。

sql的执行顺序:from>join>on>where>group by>avg/sum>having>select>distinct>order by > limit

sql 优化之8个尽量:

1、在表中建立索引,优先考虑where、group by使用到的字段。

2、尽量避免使用select *,返回无用的字段会降低查询效率。

3、尽量避免使用in 和not in,会导致数据库引擎放弃索引进行全表扫描。

4、尽量避免使用or,会导致数据库引擎放弃索引进行全表扫描。

6、尽量避免进行null值的判断,会导致数据库引擎放弃索引进行全表扫描。

5、尽量避免在字段开头模糊查询,会导致数据库引擎放弃索引进行全表扫描。

7、尽量避免在where条件中等号的左侧进行表达式、函数操作,会导致数据库引擎放弃索引进行全表扫描。

8、当数据量大时,避免使用where 1=1的条件。通常为了方便拼装查询条件,我们会默认使用该条件,数据库引擎会放弃索引进行全表扫描。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章