一、使用索引
1)索引是数据库优化常用也是重要的手段之一, 通过索引通常可以帮助用户解决大多数的MySQL的性能优化问题。
2)创建单索引:create index idx_item_title on tb_item(title);
创建复合索引:create index idx_seller_name_sta_addr on tb_seller(name,status,address);
3)利用索引查找:select * from tb_item where title =‘'iphoneX’;
:select * from tb_seller where name='小米科技' and status='1' and address='北京市';
4)应该遵守的一些规则
• 如果索引了多列,要遵守左前缀法则。指的是查询从索引的左前列开始,并且不跳过索引中的列。
• 范围查询不能使用索引。
• 不要在索引列上进行运算操作,否则索引失效。(eg:where substring(name,3,2) = '科技')
• 字符串不加单引号会使索引失效。
• 尽量使用覆盖索引,避免select *,不然查找时使用了索引,但是需要回表查询数据,导致性能下降。
• 用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。
• 以%开头的Like模糊查询,索引失效。(解决:通过覆盖索引来解决。)
• 如果MySQL评估使用索引比全表更慢,则不使用索引。
• is NULL , is NOT NULL 有时索引失效。
• in 走索引, not in 索引失效。
• 尽量使用复合索引,而少使用单列索引 。
二、SQL优化
1)优化insert
优化前:
insert into tb_test values(1,'Tom');
insert into tb_test values(2,'Cat');
insert into tb_test values(3,'Jerry');
优化后:
insert into tb_test values(1,'Tom'),(2,'Cat'),(3,'Jerry');
除此之外,插入有序数据效率更快。
2)优化order by语句
减少额外的排序,通过索引直接返回有序数据。where 条件 和Order by 使用相同的索引,并且Order By 的顺序和索引顺序相同, 并且Order by 的字段都是升序,或者都是 降序。否则肯定需要额外的操作。
3)优化group by语句
由于GROUP BY 实际上也同样会进行排序操作,而且与ORDER BY 相比,GROUP BY 主要只是多了排序之后的分 组操作。当然,如果在分组的时候还使用了其他的一些聚合函数,那么还需要一些聚合函数的计算。所以,在 GROUP BY 的实现过程中,与 ORDER BY 一样也可以利用到索引。
如果查询包含 group by 但是用户想要避免排序结果的消耗, 则可以执行order by null 禁止排序。如:
优化前:explain select age,count(*) from emp group by age;
优化后:explain select age,count(*) from emp group by age order by null;
4)优化嵌套查询
Mysql4.1版本之后,开始支持SQL的子查询。这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把 这个结果作为过滤条件用在另一个查询中。使用子查询可以一次性的完成很多逻辑上需要多个步骤才能完成的SQL 操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询是可以被更高效的连接 (JOIN)替代。 连接(Join)查询之所以更有效率一些 ,是因为MySQL不需要在内存中创建临时表来完成这个逻辑上需要两个步骤的 查询工作。
优化前: explain select * from t_user where id in (select user_id from user_role );
优化后:explain select * from t_user u , user_role ur where u.id = ur.user_id;
5)优化OR条件
对于包含OR的查询子句,如果要利用索引,则OR之间的每个条件列都必须用到索引 , 而且不能使用到复合索 引; 如果没有索引,则应该考虑增加索引。
建议使用 union 替换 or ,如:
优化前:explain select * from emp where id = 1 or id = 10;
优化后:explain select * from emp where id = 1 union explain select * from emp where id = 10;
6)优化分页查询
优化前:explain select * from tb_item limit 2000000,10;(大约3秒)
一般分页查询时,通过创建覆盖索引能够比较好地提高性能。一个常见又非常头疼的问题就是 limit 2000000,10 , 此时需要MySQL排序前2000010 记录,仅仅返回2000000 - 2000010 的记录,其他记录丢弃,查询排序的代价非常大 。
优化一:explain select * from tb_item t, (select id from tb_item order by id limit 2000000,10) a where t.id = a.id;(大约1.5秒)
在索引上完成排序分页操作,后根据主键关联回原表查询所需要的其他列内容。
优化二: explain select * from tb_item where id > 2000000 limit 10;(接近0秒)
该方案适用于主键自增的表,可以把Limit 查询转换成某个位置的查询。