MySQL中如何优化索引

发布时间:2021-07-24 16:07:17 作者:Leah
来源:亿速云 阅读:144

MySQL中如何优化索引,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

文章的脑图如下:

MySQL中如何优化索引

索引优化规则

1、like语句的前导模糊查询不能使用索引

select * from doc where title like '%XX';   --不能使用索引 select * from doc where title like 'XX%';   --非前导模糊查询,可以使用索引

因为页面搜索严禁左模糊或者全模糊,如果需要可以使用搜索引擎来解决。

2、union、in、or 都能够命中索引,建议使用 in

union能够命中索引,并且MySQL 耗费的 CPU 最少。

select * from doc where status=1 union all select * from doc where status=2;

in能够命中索引,查询优化耗费的 CPU 比 union all 多,但可以忽略不计,一般情况下建议使用 in。

select * from doc where status in (1, 2);

or 新版的 MySQL 能够命中索引,查询优化耗费的 CPU 比 in多,不建议频繁用or。

select * from doc where status = 1 or status = 2

补充:有些地方说在where条件中使用or,索引会失效,造成全表扫描,这是个误区:

3、负向条件查询不能使用索引

select * from doc where status != 1 and status != 2;

可以优化为 in 查询:

select * from doc where status in (0,3,4);

4、联合索引最左前缀原则

select uid, login_time from user where login_name=? andpasswd=?
  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. 建立联合索引的时候,区分度最高的字段在最左边

  3. 存在非等号和等号混合判断条件时,在建立索引时,把等号条件的列前置。如 where a>? and b=?,那么即使a 的区分度更高,也必须把 b  放在索引的最前列。

  4. 最左前缀查询时,并不是指SQL语句的where顺序要和联合索引一致。

select uid, login_time from user where passwd=? andlogin_name=?

假如index(a,b,c), where a=3 and b like 'abc%' and c=4,a能用,b能用,c不能用。

5、不能使用索引中范围条件右边的列(范围列可以用到索引),范围列之后列的索引全失效

select * from employees.titles where emp_no < 10010' and title='Senior Engineer'and from_date between '1986-01-01' and '1986-12-31'

6、不要在索引列上面做任何操作(计算、函数),否则会导致索引失效而转向全表扫描

例如下面的 SQL 语句,即使 date 上建立了索引,也会全表扫描:

select * from doc where YEAR(create_time) <= '2016';

可优化为值计算,如下:

select * from doc where create_time <= '2016-01-01';

比如下面的 SQL 语句:

select * from order where date < = CURDATE();

可以优化为:

select * from order where date < = '2018-01-2412:00:00';

7、强制类型转换会全表扫描

字符串类型不加单引号会导致索引失效,因为mysql会自己做类型转换,相当于在索引列上进行了操作。

如果 phone 字段是 varchar 类型,则下面的 SQL 不能命中索引。

select * from user where phone=13800001234

可以优化为:

select * from user where phone='13800001234';

8、更新十分频繁、数据区分度不高的列不宜建立索引

9、利用覆盖索引来进行查询操作,避免回表,减少select * 的使用

Select uid, login_time from user where login_name=? and passwd=?

10、索引不会包含有NULL值的列

只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时,尽量使用not  null 约束以及默认值。

11、is null, is not null无法使用索引

12、如果有order by、group by的场景,请注意利用索引的有序性

order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现file_sort 的情况,影响查询性能。

如果索引中有范围查找,那么索引有序性无法利用,如 WHERE a>10 ORDER BY b;,索引(a,b)无法排序。

13、使用短索引(前缀索引)

14、利用延迟关联或者子查询优化超多分页场景

MySQL 并不是跳过 offset 行,而是取 offset+N 行,然后返回放弃前 offset 行,返回 N 行,那当 offset  特别大的时候,效率就非常的低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL 改写。

示例如下,先快速定位需要获取的id段,然后再关联:

selecta.* from 表1 a,(select id from 表1 where 条件 limit100000,20 ) b where a.id=b.id;

15、如果明确知道只有一条结果返回,limit 1 能够提高效率

select * from user where login_name=?;
select * from user where login_name=? limit 1

自己明确知道只有一条结果,但数据库并不知道,明确告诉它,让它主动停止游标移动。

16、超过三个表最好不要 join

17、单表索引建议控制在5个以内

18、SQL 性能优化 explain 中的 type:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好

19、业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引

不要以为唯一索引影响了 insert  速度,这个速度损耗可以忽略,但提高查找速度是明显的。另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。

20.创建索引时避免以下错误观念

索引越多越好,认为需要一个查询就建一个索引。

宁缺勿滥,认为索引会消耗空间、严重拖慢更新和新增速度。

抵制惟一索引,认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。

过早优化,在不了解系统的情况下就开始优化。

索引选择性与前缀索引

Index Selectivity = Cardinality / #T
SELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles; +-------------+ | Selectivity | +-------------+ |      0.0000 | +-------------+
EXPLAIN SELECT * FROM employees.employees WHERE first_name='Eric' AND last_name='Anido'; +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ | id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows   | Extra       | +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+ |  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 300024 | Using where | +----+-------------+-----------+------+---------------+------+---------+------+--------+-------------+
SELECT count(DISTINCT(first_name))/count(*) AS Selectivity FROM employees.employees; +-------------+ | Selectivity | +-------------+ |      0.0042 | +-------------+ SELECT count(DISTINCT(concat(first_name, last_name)))/count(*) AS Selectivity FROM employees.employees; +-------------+ | Selectivity | +-------------+ |      0.9313 | +-------------+
SELECT count(DISTINCT(concat(first_name, left(last_name, 3))))/count(*) AS Selectivity FROM employees.employees; +-------------+ | Selectivity | +-------------+ |      0.7879 | +-------------+
ALTER TABLE employees.employees ADD INDEX `first_name_last_name4` (first_name, last_name(4));
SHOW PROFILES; +----------+------------+---------------------------------------------------------------------------------+ | Query_ID | Duration   | Query                                                                           | +----------+------------+---------------------------------------------------------------------------------+ |       87 | 0.11941700 | SELECT * FROM employees.employees WHERE first_name='Eric' AND last_name='Anido' | |       90 | 0.00092400 | SELECT * FROM employees.employees WHERE first_name='Eric' AND last_name='Anido' | +----------+------------+---------------------------------------------------------------------------------+

关于MySQL中如何优化索引问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

推荐阅读:
  1. MySQL 索引及优化实战
  2. Mysql索引如何优化

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

mysql

上一篇:Python中如何操作数据库

下一篇:Scrapy中怎么利用Xpath选择器从网页中采集目标数据

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》