关于数据库SQL调优

数据库优化

高效使用索引

尽可能避免全表扫描

减少无效数据的查询

索引创建规则

idx_表名_字段名(字段名可以是多个,eg. idx_table_name,idx_table_nameAge)

Mysql所认为的执行顺序

FROM <left_table>

ON  <join_condition>

<join_type>JOIN <right_table>

WHERE <where_condition>

GROUP BY <group_by_list>

HAVING <having_codition>

SELECT

DISTINCT <select_list>

ORDER BY <order_by_condition>

LIMIT <limit_number>

哪些情况需要建索引

1.主键自动建立唯一索引

2.频繁作为查询条件的字段应该创建索引

3.查询中与其他表关联的字段

4.where条件里用不到的字段不创建索引

5.统计分组排序字段

哪些情况不需要建索引

1.表记录太少(百万以下不用考虑建索引,一般数据够300万就要建索引)

2.频繁更新的字段不适合建索引 

3.数据重复且分布平均的字段不建索引,比如性别,不是男就是女。索引是区别越大,效率越高

SQL优化

1.生产上出现慢SQL,首先要做的就是复现

2.设置阈值,开启慢日志查询(慢日志影响性能,生产上一定要关闭。比如超过5秒就是慢查询要这么抓出来)

3.explain + 慢日志分析

4.show profile分析(本地Navicat就可以看到,生产上只能用命令)

5.专业人士进行SQL服务器参数调优

Explain

首先要知道explain有哪些信息。id,select_type,table,partitions,type,possible_keys,key,key_len,ref,rows,filtered,Extra这些是基本的,还有些后来加的

id

id是用来表示执行顺序的东西。id相同就按顺序执行,id不同值越大;优先级越高,越先执行

一般出现id不同就是有子查询

select_type

就是select查询的类型

SIMPLE 

最简单的查询语句,不包含子查询或union

PRIMARY

当查询语句中包含任何复杂的子部分,最外层查询则被标记为PRIMARY

SUBQUERY

当select或where列表中包含了子查询,该子查询被标记为SUBQUERY

DERIVED

表示包含在from子句中的子查询的select,在我们的from列表中的包含的子查询会被标记为DERIVED

UNION

如果union后边又出现的select语句,则会被标记为union;若union包含在from子句的子查询中。外层select被标记为DERIVED

UNION RESULT

代表从union的临时表中读取的数据,table列的<union1,3>表示用第一个结果和第三个select的结果进行union操作

table

并不一定是真实的表,有别名,也有临时表

partitions

查询时匹配到的分区信息,对于非分区表值为NULL,查询的是分区表时,partitions显示分区表命中的分区情况

type

system>const>eq_ref>ref>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>All

system就是表中只有一行记录,相当于系统表,不需要磁盘IO,速度非常快

const表示查询时命中primary key主键或unique唯一索引,或者被连接的部分是一个常量const值,查询速度非常快

eq_ref对于每一个索引,表中只有一条记录与之匹配

ref返回匹配某个单独值的所用行,也算是一种索引访问

ref_or_null类似于ref,会额外搜索null的行

index_merge使用了索引合并,查询使用了两个以上的方法

unique_subquery该类型替换了下面形式的IN子查询的ref:value IN (SELECT primary_key FROM single_table WHERE some_expr),返回不重复值

index_subquery和unique_subquery类似,返回重复值

range使用索引检索范围内的行betwee,>,<,in

index遍历索引树,也很慢但比All强

All全表扫描,性能最差但驱动表避免不了

possible_keys

可能使用到的索引,如果是覆盖索引,他可以为null

key

实际用到的索引,使用到则标记出索引,没有使用到则为NULL

key_len

越短当然越好,越长就越精准。需要注意的是key_len只计算where条件中用到的索引长度,而排序和分组即便用到了索引也不会计算到key_len中

ref

常见的有null,func,const,字段名

使用常量等值查询,显示const

当关联查询时,会显示相应关联表的关联字段

如果查询条件使用了表达式,函数或者内部隐式转换可能显示为func

其他情况为null

rows

rows以表的统计信息和索引使用情况,计算需要读取多少行,rows越小代表扫描的行数越少

filtered

代表表中符合条件的记录数

Extra

一些重要的额外信息

using filesort,部分使用到了索引,一般是order by的字段没有索引,需要优化

using temporary,使用中间表保存中间结果,一般和group by,order by没用到索引,需要优化

using index,使用到了覆盖索引,使用了覆盖索引,覆盖索引就是索引列和查询列一致,顺序不同无所谓。这样就不需要查询数据行直接查索引就好,推荐使用

using where,查询时未找到可用索引,进而通过where条件过滤获取

using join buffer,在我们连表查询如果连接条件没有用到索引,需要一个连接缓冲区来存储中间结果,join太多了,可以考虑加索引或调大join buffer的参数

impossible where ,where后面的条件不正确

No tables used ,没有表或者用了虚表

单表优化

1.最左前缀匹配法则

2.不在索引列上做任何操作(计算,函数,显式或者隐式转换)

3.范围条件in,>,<等索引会失效,考虑把范围放最后或者使用between

4.尽量使用覆盖索引,不使用select *

5.使用!=或<>无法使用索引,这个看版本高版本的都是range,低版本建议不要在相关字段上设置索引

6.is null,is not null不走索引

7.like只有用 xx%可以走索引,这个也看版本的,数据实在过大(过亿了这种)考虑走搜索引擎Es,Solr。如果数据量很少刚刚几千条别想了直接%xx%。如果数据量也不算小,建议使用内置函数INSTR(str,substr)

8.字符串不加单引号不走索引,MySQL会帮你隐式转换但是不走索引

9.or使索引失效,低版本会,高版本肯定不会失效

10.拼装where后的条件少用1=1,在mybatis用where标签,好多项目都用这个,不用的也有类似解决方案

11.极端情况下,可以考虑使用hint(ignore index,force index加在from后面)优化语句。所谓极端可以是某个语句他不走索引了,查询慢到开花,强制让他走索引,留时间出来分析语句。这个慎用,搞不好会影响到其他业务,数据库版本升级也会对他造成很大打击

12.别用select *,不可能一张表里所有字段都是索引的

13.能用where,不用having,因为where能提前筛选出来,就会少很多数据

多表优化

LEFT JOIN索引加在从(右)表的关联字段上,RIGHT JOIN索引加在主(左)表的关联字段上,为什么这么说呢?就比如说左连接会把主(左)表的所有关联数据都拿去做匹配。如果索引加在主(左)表就会导致要扫描一些没必要查的行,导致效率下降,右连接也是同理。但还是要以小表驱动大表,不然得出来的结果还是有很大差距的

阿里手册开发手册也提过join的次数最好不要超过三次,超过了非常影响效率(想起我以前写SQL,5表查询我写了5个left join我还很自豪.....),关于这个我有两种解决方案:1.根据业务在表中设计冗余字段,你想要的某个字段已经存好放在同一张表里了,那就不需要联表了 2.设计中间表,中间表只存其他表对应记录的id,做业务时顺便往中间表里插入其他表的id确保他的id不会为空,让需要多次JOIN的表跟中间表关联上,这样可以根据中间表id查出中间表上的其他表的id字段,再根据各个id字段查出所需要的对应信息,也就是说分两步走

索引生效图鉴

我们的索引长这样idx_abc(a,b,c),是个复合索引,一般实际使用都是用的复合索引

单用where


where及order

慢日志分析

使用慢日志的分析工具mysqldumpslow

以下是几条用的较多的命令

得到返回记录集最多的10条SQL

mysqldumpslow -s -r -t 10 慢日志地址具体到文件(/var/lib/mysql/slow.log)| more

得到访问次数最多的10条SQL

mysqldumpslow -s c -t 10 慢日志地址具体到文件 | more

得到按照时间排序的前10条里面包含有左连接的SQL

mysqldumpslow -s t -t 10 -g "left join" 慢日志地址具体到文件 | more

show profile

其实只要注意几个点就好了

converting to HEAP to MyISAM 查询结果太大,内存不够用往磁盘上搬

creating tmp table 创建临时表,拷贝数据到临时表用完了再删除,这个非常的影响效率

copying to tmp table on disk 把内存中临时表复制磁盘,这个就是必须要优化了

locked 锁表了,这个要看是为什么锁,众所周知DML加了各种锁,锁了正常那就不用管,不正常就看是不是常用的业务,不是常用的kill,常用的看看是kill好还是等到满足解锁条件自动解锁好

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容