【数据库基础干货】MySQL基础及慢查询优化实践

知识储备

内存数据库:速度快,成本高,索引:Map、平衡树、T树 ,应用Redis、Memchached
磁盘数据库:速度较快,成本适中(虚拟机,物理机),索引哈希,B+ ,应用:MySQL、Oracle
分布式数据库:速度较慢,容量大,存储:竖表、HDFS

SQL执行阶段

  1. 客户端发送一个查询给服务器,到达连接器
  2. 服务器先检查缓存,如果命中了缓存,立即返回结果。
  3. 到达分析器服务器端进行SQL的解析,生成解析树。
  4. 再由优化器生成对应的执行计划。
  5. 根据执行计划,调用具体存储引擎(InnoDB)将结果返回给客户端。

InnoDB引擎为什么要使用B+数据
1、每个节点(数据页)为16K,叶子节点存储数据。
2、多叉树,减少层高,减少IO,一般只需要3~4次IO即可。
3、叶子节点间存在顺序指针。
4、B+主索引存所有数据,B树辅助索引只存主键ID。

利用索引的好处是什么?
1、减少服务器扫描的数据量,提高查询效率
2、服务器避免排序和临时表

分析原因及解决套路

Explain用法

  • table : 查询哪个表
  • rows : 预估扫描的行数
  • ref : 哪个字段和key一起使用
  • key : 使用的索引
  • possible_keys :可用的索引,不止一个
  • key_len :索引中使用的字节数,长度越短越好
  • type : ALL(扫描全表)、index(扫描全索引)、range(范围索引)、ref(索引,匹配单值)、const(主键或唯一键,只匹配一行)
  • filtered :此查询条件所过滤数据百分比
  • extra:额外信息eg: Using filesort(外部的索引排序而不是按照表内的索引顺序进行读取)、Using index(使用覆盖索引)、Using index condition (先条件过滤,再查数据)、Using where(使用where语句来处理结果) 、Using Temporary(临时表,常见于order by 和group by)

慢查询治理思路

索引层面

1、 没有建立索引
2、索引失效

select * from ShopTable where shopid > 10000000 VS where shopid > 50000000

虽然给shopid 加了一般索引,但执行where shopid > 10000000 没有使用到索引,回表(即从索引查出是哪一行,再回到表中取出所有字段返回)导致全表扫描当需要回表的数据量大于20%,MySQL会认为全表扫描会更快,故不走索引。
建议:

  • 减少使用select * ,索引覆盖所需要返回的字段,即索引列和查询列一致
  • 减少数据量,数据量过大时考虑分页

3 、使用索引不全面
where shopid > 234512 and update_days > -1 and buy_time > 300
只用到shopid的索引,索引效率低,查询到后还需要回表再过滤,导致效率严重下降
建议:
增加update_days 和 buy_time字段的索引

4、Order By /Group By /Distinct 避免临时表

5、建议使用自增列作为主键
create table test(idint(11) NOT NULL PRIMARY KEY (id))

6、主键设置为int unsigned或bigInt unsigned

7、表建的索引过多

8、唯一索引注意检查数据唯一性,如果数据不唯一在线表结构调整时将有可能自动将重复列删除,这有可能导致数据丢失

9、

SQL层面

避免不正确或低效的写法、避免复杂的SQL

1、limit 6000000 , 10
limit过大 ,limit A,B 会扫描 X+Y条数据,即当X过大时,扫描行数多导致慢查询
建议:
尽量使用id > xx LIMIT 10,建议分页遍历使用ID

2、
一般索引 KEY shopid
一般索引 KEY poiid
组合索引 KEY combined(shopid,poiid)
使用时只触发了索引merge i2 && KEY combined
建议:
删除Key shopid索引,减少索引占用空间
3、一个复杂SQL 还是多个简单SQL

4、不建议使用前项通配符查找
select c1,c2,c3 from tbl where name like '%foo';

5、没有通配符的LIKE查询
select c1,c2,c3 from tbl where name like 'foo';

6、参数比较包含隐式转换,无法使用索引
SELECT * FROM sakila.film WHERE length >= '60';

7、IN 要慎用,元素过多会导致全表扫描,建议使用between X and Y 代替

8、避免在WHERE条件中使用函数或其他运算符

表库层

1、查看表状况 show table status like ‘table_shop’
Rows : 180000000
Data_length : 30G
单表数据量过大,建议单表不超过1千万行

2、是否必须走主库
Master-Slave架构,主库单节点,容易成为资源瓶颈

3、范式:确保每列的原子性(不可分解)、唯一性
反范式:通过冗余字段,提高查询效率

应用层

换存储引擎、缓存
业务逻辑优化

基础规范
  1. 使用InnoDB存储引擎:支持事务、行级锁、并发性更好
  2. 数据表、数据字段必须加入中文注释,时间长了会忘记字段精确含义
  3. 禁止使用存储过程,视图,触发器,Event,数据库目的是存储和索引,计算逻辑应该放到服务层
  4. 禁止存储大文件和大照片,存储在文件系统中,数据库里存URI即可
建表规范
  1. 字段设计为NOT NULL,NULL的列使索引/索引统计/值比较都更加复杂,存储空间大,处理时需要用is null 、is not null
  2. 必须有主键,主键递增提高数据行写入效率,且主键选择较短数据类型,可以减少索引磁盘空间,建议增加xxx_create ,xxx_update字段
  3. 不要使用外键,外键会导致表与表之间耦合,更新、删除操作都会涉及到关联的表,不仅影响性能还可能造成死锁
  4. 使用varchar(20)存储手机号,因为涉及到国家会有符号(±),varchar支持模糊查询 ‘like 173’
  5. 单表大小不要超过1千万行
索引规范
  1. 单表索引数量控制,一般在5个以内
  2. 联合索引和覆盖索引是两个方面,联合索引是一种索引类型,覆盖索引是一种最优情况,不用回表
  3. 联合索引需要前导列,覆盖索引就是索引既数据即可,可能只用了一个字段的索引

联合索引

对(a,b,c)进行联合索引,判断是否走索引问题

a = 1            //true
a = 1 and b = 2  //true
b = 2 and a = 1  //true,Mysql有优化器会自动调整a,b的顺序与索引顺序一致,注意把区分度高的字段放在前面
b = 1            //false,
a = 1 and b = 2 and c > 3 and d = 4 //a,b,c三个字段能用到索引,而d就匹配不到,最左匹配原则遇到范围查询就停止匹配


如何建联合检索问题

SELECT * FROM table WHERE a = 1 and b = 2 and c = 3;     // (a,b,c) (b,a,c) (c,a,b)都可以,将区分度高的字段放在前列
SELECT * FROM table WHERE a > 1 and b = 2;               // (b,a)建立索引,优化器会帮我们调整where后a,b的顺序
SELECT * FROM `table` WHERE a > 1 and b = 2 and c > 3;   // (b,a) 或(b,c)都可以的
SELECT * FROM `table` WHERE a = 1 ORDER BY b;            // 对(a,b)建索引
SELECT * FROM `table` WHERE a IN (1,2,3) and b > 1;      //对(a,b)建立索引,因为IN在这里可以视为等值引用,不会中止索引匹配


哪些情况不适合建索引

  1. 禁止在更新频繁、区分度不高的属性字段上建立索引,更新会改变B+树结构
  2. “性别”这种区分度不高的属性建立索引没有意义
  3. Where 条件用不到的字段不创建索引
  4. 表记录太少
  5. 经常增删的表
SQL注意事项
  • 禁止在where条件的列名上使用函数、计算、类型转换
  • 禁止使用左模糊或全模糊查询,如like ‘%abc’ ,like ‘%abc%’
  • 少用or
  • is null ,is not null 也会无法使用索引
  • 禁止使用大偏移量的limit分页
  • 禁止3张表以上做join

推荐学习:
https://ipu.sankuai.com/app/course/detail/1927
高性能SQL 和 MySQL官方文档(https://www.mysql.com)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值