问题1:SQL执行慢的原因有哪些?如何进行SQL优化?
一、导致SQL执行慢的原因
1、硬件问题。如网络速度慢,内存不足,I/O吞吐量小,磁盘空间满了等。
2、没有索引或者索引失效。(一般在互联网公司,DBA会在半夜把表锁了,重新建立一遍索引,因为当你删除某个数据的时候,索引的树结构就不完整了。所以互联网公司的数据做的是假删除,一是为了做数据分析,二是为了不破坏索引 )
3、数据过多(分库分表)
4、服务器调优及各个参数设置(调整my.cnf)
二、分析原因时,一定要找切入点
1、先观察,开启慢查询日志,设置相应的阈值(比如超过3秒就是慢SQL),在生产环境跑上个一天过后,看看哪些SQL比较慢。
2、Explain和慢SQL分析。比如SQL语句写的烂,索引没有或失效,关联查询太多(有时候是设计缺陷或者不得以的需求)等等。
3、Show Profile是比Explain更近一步的执行细节,可以查询到执行每一个SQL都干了什么事,这些事分别花了多少秒。
4、找DBA或者运维对MySQL进行服务器的参数调优。 解析: (1)、explain出来的各种item的意义
id:每个被独立执行的操作的标志,表示对象被操作的顺序。一般来说, id 值大,先被执行;如果 id 值相同,则顺序从上到下。 select_type:查询中每个 select 子句的类型。 table:名字,被操作的对象名称,通常的表名(或者别名),但是也有其他格式。 partitions:匹配的分区信息。 type:join 类型。 possible_keys:列出可能会用到的索引。 key:实际用到的索引。 key_len:用到的索引键的平均长度,单位为字节。 ref:表示本行被操作的对象的参照对象,可能是一个常量用 const 表示,也可能是其他表的 key 指向的对象,比如说驱动表的连接列。 rows:估计每次需要扫描的行数。 filtered:rows*filtered/100 表示该步骤最后得到的行数(估计值)。 extra:重要的补充信息。
(2)、profile的意义以及使用场景
Profile 用来分析 sql 性能的消耗分布情况。当用 explain 无法解决慢 SQL 的时候,需要用profile 来对 sql 进行更细致的分析,找出 sql 所花的时间大部分消耗在哪个部分,确认 sql的性能瓶颈。
(3)、explain 中的索引问题
Explain 结果中,一般来说,要看到尽量用 index(type 为 const、 ref 等, key 列有值),避免使用全表扫描(type 显式为 ALL)。比如说有 where 条件且选择性不错的列,需要建立索引。 被驱动表的连接列,也需要建立索引。被驱动表的连接列也可能会跟 where 条件列一起建立联合索引。当有排序或者 group by 的需求时,也可以考虑建立索引来达到直接排序和汇总的需求。
问题二:SQL调优的几种方式:
一:创建索引
尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引
一个表的索引数最好不要超过6个
避免在索引上进行计算
二:使用预编译查询
程序中通常是根据用户的输入来动态执行SQL,这时应该尽量使用参数化SQL,这样不仅可以避免SQL注入漏洞攻击,最重要数据库会对这些参数化SQL进行预编译
三:调整where连接顺序
DBMS一般采用自下而上的顺序解析where字句,根据这个原理表连接最好写在其他where条件之前,那些可以过滤掉最大数量记录。
四:多条SQL压缩到一条SQL
五:用where替换having字段
因为HAVING只会在检索出所有记录之后才对结果集进行过滤,而where则是在聚合前刷选记录,如果能通过where字句限制记录的数目,那就能减少这方面的开销。HAVING中的条件一般用于聚合函数 的过滤,除此之外,应该将条件写在where字句中。
六:使用表的别名
当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这样就可以减少解析的时间并减 少哪些友列名歧义引起的语法错误。
七:用union all 替换union
八:使用临时表暂存中间结果
化SQL语句的重要方法就是采用临时表暂存中间结果,但是,临时表的好处远远不止这些,将临时结果暂存在临时表,后面的查询就在tempdb中了,这可以避免程序中多次扫描主表,也大大减少了程序执行中“共享锁”阻塞“更新锁”,减少了阻塞,提高了并发性能。 但是也得避免频繁创建和删除临时表,以减少系统表资源的消耗。
九:避免使用游标
尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
十:用varchar/nvarchar代替char/nchar
尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。 不要以为 NULL 不需要空间,比如:char(100) 型,在字段建立时,空间就固定了, 不管是否插入值(NULL也包含在内),都是占用 100个字符的空间的,如果是varchar这样的变长字段, null 不占用空间。