太太太长了,不行,我受不鸟了
作者:编码砖家 来源:博客园
地址:cnblogs.com/xiaoyangjia/p/11267191.html
前言
MySQL性能
最大数据量
select field_1,field_2 from table where id < #{prePageMinId} order by id desc limit 20
,prePageMinId是上一页数据记录的最小ID。虽然当时查询速度还凑合,随着数据不断增长,有朝一日必定不堪重负。分库分表是个周期长而风险高的大活儿,应该尽可能在当前结构上优化,比如升级硬件、迁移历史数据等等,实在没辙了再分。对分库分表感兴趣的同学可以阅读分库分表的基本思想。最大并发数
max_used_connections / max_connections * 100% = 3/100 *100% ≈ 3%
show variables like '%max_connections%';
show variables like '%max_user_connections%';
[mysqld]
max_connections = 100
max_used_connections = 20
查询耗时0.5秒
实施原则
充分利用但不滥用索引,须知索引也消耗磁盘和CPU。
不推荐使用数据库函数格式化数据,交给应用程序处理。
不推荐使用外键约束,用应用程序保证数据准确性。
写多读少的场景,不推荐使用唯一索引,用应用程序保证唯一性。
适当冗余字段,尝试创建中间表,用应用程序计算中间结果,用空间换时间。
不允许执行极度耗时的事务,配合应用程序拆分成更小的事务。
预估重要数据表(比如订单表)的负载和数据增长态势,提前优化。
数据表设计
数据类型
如果长度能够满足,整型尽量使用tinyint、smallint、medium_int而非int。
如果字符串长度确定,采用char类型。
如果varchar能够满足,不采用text类型。
精度要求较高的使用decimal类型,也可以使用BIGINT,比如精确两位小数就乘以100后保存。
尽量采用timestamp而非datetime。
避免空值
is not null
的判断。text类型优化
索引优化
索引分类
普通索引:最基本的索引。
组合索引:多个字段上建立的索引,能够加速复合查询条件的检索。
唯一索引:与普通索引类似,但索引列的值必须唯一,允许有空值。
组合唯一索引:列值的组合必须唯一。
主键索引:特殊的唯一索引,用于唯一标识数据表中的某一条记录,不允许有空值,一般用primary key约束。
全文索引:用于海量文本的查询,MySQL5.6之后的InnoDB和MyISAM均支持全文索引。由于查询精度以及扩展性不佳,更多的企业选择Elasticsearch。
索引优化
分页查询很重要,如果查询数据量超过30%,MYSQL不会使用索引。
单表索引数不超过5个、单个索引字段数不超过5个。
字符串可使用前缀索引,前缀长度控制在5-8个字符。
字段唯一性太低,增加索引没有意义,如:是否删除、性别。
合理使用覆盖索引,如下所示:
select loginname, nickname from member where login_name = ?
SQL优化
分批处理
业务描述:更新用户所有已过期的优惠券为不可用状态。
SQL语句:
update status=0 FROM
coupon WHERE expire_date <= #{currentDate} and status=1;
如果大量优惠券需要更新为不可用状态,执行这条SQL可能会堵死其他SQL,分批处理伪代码如下:
int pageNo = 1;
int PAGE_SIZE = 100;
while(true) {
List<Integer> batchIdList = queryList('select id FROM `coupon` WHERE expire_date <= #{currentDate} and status = 1 limit #{(pageNo-1) * PAGE_SIZE},#{PAGE_SIZE}');
if (CollectionUtils.isEmpty(batchIdList)) {
return;
}
update('update status = 0 FROM `coupon` where status = 1 and id in #{batchIdList}')
pageNo ++;
}
操作符<>优化
select id from orders where amount != 100;
如果金额为100的订单极少,这种数据分布严重不均的情况下,有可能使用索引。鉴于这种不确定性,采用union聚合搜索结果,改写方法如下:
(select id from orders where amount > 100)
union all
(select id from orders where amount < 100 and amount > 0)
OR优化
select id,product_name from orders where mobile_no = '13421800407' or user_id = 100;
(select id,product_name from orders where mobile_no = '13421800407')
union
(select id,product_name from orders where user_id = 100);
IN优化
IN适合主表大子表小,EXIST适合主表小子表大。由于查询优化器的不断升级,很多场景这两者性能差不多一样了。
尝试改为join查询,举例如下:
select id from orders where user_id in (select id from user where level = 'VIP');
select o.id from orders o left join user u on o.user_id = u.id where u.level = 'VIP';
不做列运算
查询当日订单
select id from order where date_format(create_time,'%Y-%m-%d') = '2019-07-01';
select id from order where create_time between '2019-07-01 00:00:00' and '2019-07-01 23:59:59';
避免Select all
SELECT *
,它会进行全表扫描,不能有效利用索引。Like优化
SELECT column FROM table WHERE field like '%keyword%';
SELECT column FROM table WHERE field like 'keyword%';
Join优化
驱动表和被驱动表尽可能增加查询条件,满足ON的条件而少用Where,用小结果集驱动大结果集。
被驱动表的join字段上加上索引,无法建立索引的时候,设置足够的Join Buffer Size。
禁止join连接三个以上的表,尝试增加冗余字段。
Limit优化
select * from orders order by id desc limit 100000,10
耗时0.4秒
select * from orders order by id desc limit 1000000,10
耗时5.2秒
select * from orders where id > (select id from orders order by id desc limit 1000000, 1) order by id desc limit 0,10
耗时0.5秒
select id from orders where id between 1000000 and 1000010 order by id desc
耗时0.3秒
其他数据库
-End-
加小编微信:xiaobaito,可以邀请加入咱们的「菜鸟架构」技术群一起讨论技术,禁止发广告及垃圾信息哦。
热门阅读
实现分布式锁都有哪些方式?面试官的灵魂 50 问,问到你怀疑人生!如何抗住百亿流量,厉害了!
更多请关注“菜鸟架构”公众号,将不断呈现更多架构干货!
给个在看,谢谢老板!