一: MySQL知识点
1. MySQL 基础架构
MySQL 基础架构 |
从上图可以看出, MySQL 主要由下面几部分构成:
- 连接器: 身份认证和权限相关(登录 MySQL 的时候)。
- 查询缓存: 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。
- 分析器: 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。
- 优化器: 按照 MySQL 认为最优的方案去执行。
- 执行器: 执行语句,然后从存储引擎返回数据。 执行语句之前会先判断是否有权限,如果没有权限的话,就会报错。
- 插件式存储引擎 : 主要负责数据的存储和读取,采用的是插件式架构,支持 InnoDB、MyISAM、Memory 等多种存储引擎。
2.MyISAM 和 InnoDB 的区别是什么?
- MySQL 5.5.5 之前,MyISAM 是 MySQL 的默认存储引擎。5.5.5 版本之后,InnoDB 是 MySQL 的默认存储引擎。
InnoDB | MyISAM | |
是否支持行级锁 | InnoDB 支持行级锁(row-level locking)和表级锁,默认为行级锁 | MyISAM 只有表级锁(table-level locking) |
是否支持事务 | InnoDB 提供事务支持,实现了 SQL 标准定义了四个隔离级别,具有提交(commit)和回滚(rollback)事务的能力。并且,InnoDB 默认使用的 REPEATABLE-READ(可重读)隔离级别是可以解决幻读问题发生的(基于 MVCC 和 Next-Key Lock)。 | MyISAM 不提供事务支持。 |
是否支持外键 | InnoDB 支持 | MyISAM 不支持 |
是否支持数据库异常崩溃后的安全恢复 | InnoDB 支持; 使用 InnoDB 的数据库在异常崩溃后,数据库重新启动的时候会保证数据库恢复到崩溃前的状态。这个恢复的过程依赖于 | MyISAM 不支持 |
是否支持 MVCC | InnoDB 支持 | MyISAM 不支持; 毕竟 MyISAM 连行级锁都不支持。MVCC 可以看作是行级锁的一个升级,可以有效减少加锁操作,提高性能 |
索引实现 | InnoDB 引擎中,其数据文件本身就是索引文件 | MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按 B+Tree 组织的一个索引结构,树的叶节点 data 域保存了完整的数据记录。 |
3. MYSQL事务
- 原子性(
Atomicity
) : 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用; - 一致性(
Consistency
): 执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的; - 隔离性(
Isolation
): 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的; - 持久性(
Durabilily
): 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
ACID(AID是手段,C是目的) |
4. 并发事务带来了哪些问题?
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
- 脏读(Dirty read): 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
- 丢失修改(Lost to modify): 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 修改 A=A-1,事务 2 也修改 A=A-1,最终结果 A=19,事务 1 的修改被丢失。
121
问题 - 不可重复读(Unrepeatable read): 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
- 幻读(Phantom read): 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复读和幻读区别 :不可重复读的重点是修改比如多次读取一条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除比如多次查询同一条查询语句(DQL)时,记录发现记录增多或减少了。
5. SQL 标准定义的事务隔离级别
SQL 标准定义了四个隔离级别:
- READ-UNCOMMITTED(读取未提交) : 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交) : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读) : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
(MYSQL INNODB默认)
- SERIALIZABLE(可串行化) : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
READ-UNCOMMITTED(读未提交) | √ | √ | √ |
READ-COMMITTED(读已提交) | × | √ | √ |
REPEATABLE-READ(可重复读) | × | × | √ |
SERIALIZABLE(序列化) | × | × | × |
6. MySQL 锁
6.1 表级锁和行级锁
MyISAM 仅仅支持表级锁(table-level locking),一锁就锁整张表,这在并发写的情况下性非常差。
InnoDB 不光支持表级锁(table-level locking),还支持行级锁(row-level locking),默认为行级锁。行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说, InnoDB 的性能更高。
表级锁和行级锁对比 :
- 表级锁: MySQL 中锁定粒度最大的一种锁,是针对索引字段加的锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM 和 InnoDB 引擎都支持表级锁。
- 行级锁: MySQL 中锁定粒度最小的一种锁,是针对非索引字段加的锁,只针对当前操作的记录进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。
6.2 行级锁的使用有什么注意事项?
InnoDB 的行锁是针对索引字段加的锁,表级锁是针对非索引字段加的锁。当我们执行 UPDATE
、DELETE
语句时,如果 WHERE
条件中字段没有命中索引或者索引失效的话,就会导致扫描全表对表中的所有记录进行加锁。这个在我们日常工作开发中经常会遇到,一定要多多注意!!!
不过,很多时候即使用了索引也有可能会走全表扫描,这是因为 MySQL 优化器的原因。
6.3 共享锁和排他锁
不论是表级锁还是行级锁,都存在共享锁(Share Lock,S 锁)和排他锁(Exclusive Lock,X 锁)这两类:
- 共享锁(S 锁) :又称读锁,事务在读取记录的时候获取共享锁,允许多个事务同时获取(锁兼容)。
- 排他锁(X 锁) :又称写锁/独占锁,事务在修改记录的时候获取排他锁,不允许多个事务同时获取。如果一个记录已经被加了排他锁,那其他事务不能再对这条事务加任何类型的锁(锁不兼容)。
排他锁与任何的锁都不兼容,共享锁仅和共享锁兼容。
S 锁 | X 锁 | |
S 锁 | 不冲突 | 冲突 |
X 锁 | 冲突 | 冲突 |
由于 MVCC 的存在,对于一般的 SELECT
语句,InnoDB 不会加任何锁。不过, 你可以通过以下语句显式加共享锁或排他锁。
# 共享锁
SELECT ... LOCK IN SHARE MODE;
# 排他锁
SELECT ... FOR UPDATE;
二:MySQL高性能优化规范
1. 数据库命名规范
- 所有数据库对象名称必须使用小写字母并用下划线分割
- 所有数据库对象名称禁止使用 MySQL 保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来)
- 数据库对象的命名要能做到见名识意,并且最后不要超过 32 个字符
- 临时库表必须以 tmp_为前缀并以日期为后缀,备份表必须以 bak_为前缀并以日期 (时间戳) 为后缀
- 所有存储相同数据的列名和列类型必须一致(一般作为关联列,如果查询时关联列类型不一致会自动进行数据类型隐式转换,会造成列上的索引失效,导致查询效率降低)
2. 数据库基本设计规范
1. 所有表必须使用 Innodb 存储引擎
没有特殊要求(即 Innodb 无法满足的功能如:列存储,存储空间数据等)的情况下,所有表必须使用 Innodb 存储引擎(MySQL5.5 之前默认使用 Myisam,5.6 以后默认的为 Innodb)。
Innodb 支持事务,支持行级锁,更好的恢复性,高并发下性能更好。
2. 数据库和表的字符集统一使用 UTF8
兼容性更好,统一字符集可以避免由于字符集转换产生的乱码,不同的字符集进行比较前需要进行转换会造成索引失效,如果数据库中有存储 emoji 表情的需要,字符集需要采用 utf8mb4 字符集。
参考文章:MySQL 字符集不一致导致索引失效的一个真实案例
3. 所有表和字段都需要添加注释
使用 comment 从句添加表和列的备注,从一开始就进行数据字典的维护
4. 尽量控制单表数据量的大小,建议控制在 500 万以内。
500 万并不是 MySQL 数据库的限制,过大会造成修改表结构,备份,恢复都会有很大的问题。
可以用历史数据归档(应用于日志数据),分库分表(应用于业务数据)等手段来控制数据量大小
5. 谨慎使用 MySQL 分区表
分区表在物理上表现为多个文件,在逻辑上表现为一个表;
谨慎选择分区键,跨分区查询效率可能更低;
建议采用物理分表的方式管理大数据。
6.尽量做到冷热数据分离,减小表的宽度
MySQL 限制每个表最多存储 4096 列,并且每一行数据的大小不能超过 65535 字节。
减少磁盘 IO,保证热数据的内存缓存命中率(表越宽,把表装载进内存缓冲池时所占用的内存也就越大,也会消耗更多的 IO);
更有效的利用缓存,避免读入无用的冷数据;
经常一起使用的列放到一个表中(避免更多的关联操作)。
7. 禁止在表中建立预留字段
预留字段的命名很难做到见名识义。
预留字段无法确认存储的数据类型,所以无法选择合适的类型。
对预留字段类型的修改,会对表进行锁定。
8. 禁止在数据库中存储图片,文件等大的二进制数据
通常文件很大,会短时间内造成数据量快速增长,数据库进行数据库读取时,通常会进行大量的随机 IO 操作,文件很大时,IO 操作很耗时。
通常存储于文件服务器,数据库只存储文件地址信息
9. 禁止在线上做数据库压力测试
10. 禁止从开发环境,测试环境直接连接生产环境数据库
3. 数据库字段设计规范
1. 优先选择符合存储需要的最小的数据类型
原因:
列的字段越大,建立索引时所需要的空间也就越大,这样一页中所能存储的索引节点的数量也就越少也越少,在遍历时所需要的 IO 次数也就越多,索引的性能也就越差。
2. 避免使用 TEXT,BLOB 数据类型
a. 建议把 BLOB 或是 TEXT 列分离到单独的扩展表中
最常见的 TEXT 类型可以存储 64k 的数据,如果一定要使用,建议把 BLOB 或是 TEXT 列分离到单独的扩展表中,查询时一定不要使用 select * 而只需要取出必要的列,不需要 TEXT 列的数据时不要对该列进行查询。
b.TEXT 或 BLOB 类型只能使用前缀索引
3. 避免使用 ENUM 类型
修改 ENUM 值需要使用 ALTER 语句
ENUM 类型的 ORDER BY 操作效率低,需要额外操作
禁止使用数值作为 ENUM 的枚举值
4. 尽可能把所有列定义为 NOT NULL
原因:
索引 NULL 列需要额外的空间来保存,所以要占用更多的空间
进行比较和计算时要对 NULL 值做特别的处理
5. 使用 TIMESTAMP(4 个字节) 或 DATETIME 类型 (8 个字节) 存储时间
经常会有人用字符串存储日期型的数据(不正确的做法)
- 缺点 1:无法用日期函数进行计算和比较
- 缺点 2:用字符串存储日期要占用更多的空间
6. 同财务相关的金额类数据必须使用 decimal 类型
4. 索引设计规范
1. 限制每张表上的索引数量,建议单张表索引不超过 5 个
索引可以增加查询效率,但同样也会降低插入和更新的效率,甚至有些情况下会降低查询效率。
因为 MySQL 优化器在选择如何优化查询时,会根据统一信息,对每一个可以用到的索引来进行评估,以生成出一个最好的执行计划,如果同时有很多个索引都可以用于查询,就会增加 MySQL 优化器生成执行计划的时间,同样会降低查询性能。
2. 禁止给表中的每一列都建立单独的索引
3. 每个 Innodb 表必须有个主键
Innodb 是按照主键索引的顺序来组织表的
- 不要使用更新频繁的列作为主键,不适用多列主键(相当于联合索引)
- 不要使用 UUID,MD5,HASH,字符串列作为主键(无法保证数据的顺序增长)
- 主键建议使用自增 ID 值
4. 常见索引列建议
- 出现在 SELECT、UPDATE、DELETE 语句的 WHERE 从句中的列
- 包含在 ORDER BY、GROUP BY、DISTINCT 中的字段
- 并不要将符合 1 和 2 中的字段的列都建立一个索引, 通常将 1、2 中的字段建立联合索引效果更好
- 多表 join 的关联列
5.如何选择索引列的顺序
建立索引的目的是:希望通过索引进行数据查找,减少随机 IO,增加查询性能 ,索引能过滤出越少的数据,则从磁盘中读入的数据也就越少。
- 区分度最高的放在联合索引的最左侧(区分度=列中不同值的数量/列的总行数)
- 尽量把字段长度小的列放在联合索引的最左侧(因为字段长度越小,一页能存储的数据量越大,IO 性能也就越好)
- 使用最频繁的列放到联合索引的左侧(这样可以比较少的建立一些索引)
6. 避免建立冗余索引和重复索引(增加了查询优化器生成执行计划的时间)
- 重复索引示例:primary key(id)、index(id)、unique index(id)
- 冗余索引示例:index(a,b,c)、index(a,b)、index(a
7. 对于频繁的查询优先考虑使用覆盖索引
覆盖索引:就是包含了所有查询字段 (where,select,order by,group by 包含的字段) 的索引
覆盖索引的好处:
- 避免 Innodb 表进行索引的二次查询: Innodb 是以聚集索引的顺序来存储的,对于 Innodb 来说,二级索引在叶子节点中所保存的是行的主键信息,如果是用二级索引查询数据的话,在查找到相应的键值后,还要通过主键进行二次查询才能获取我们真实所需要的数据。而在覆盖索引中,二级索引的键值中可以获取所有的数据,避免了对主键的二次查询 ,减少了 IO 操作,提升了查询效率。
- 可以把随机 IO 变成顺序 IO 加快查询效率: 由于覆盖索引是按键值的顺序存储的,对于 IO 密集型的范围查找来说,对比随机从磁盘读取每一行的数据 IO 要少的多,因此利用覆盖索引在访问时也可以把磁盘的随机读取的 IO 转变成索引查找的顺序 IO。
8. 外键约束
- 不建议使用外键约束(foreign key),但一定要在表与表之间的关联键上建立索引
- 外键可用于保证数据的参照完整性,但建议在业务端实现
- 外键会影响父表和子表的写操作从而降低性能
5. 数据库 SQL 开发规范
1. 建议使用预编译语句进行数据库操作
预编译语句: SQL语句条件以参数的形式代入,SQL模板预编译
预编译语句可以重复使用这些计划,减少 SQL 编译所需要的时间,还可以解决动态 SQL 所带来的 SQL 注入的问题。
只传参数,比传递 SQL 语句更高效。
相同语句可以一次解析,多次使用,提高处理效率
2. 避免数据类型的隐式转换
类型的隐形转换会导致索引失效
-- int数据库结构是int类型 ,检索时由string隐形转换成int
select * from id = '1'
3. 充分利用表上已经存在的索引
充分利用表上已经存在的索引,避免索引失效
- 避免使用双%号的查询条件。如:
a like '%123%'
会导致索引失效,(如果无前置%,只有后置%,是可以用到列上的索引的) - 一个 SQL 只能利用到复合索引中的一列进行范围查询。如:有 a,b,c 列的联合索引,在查询条件中有 a 列的范围查询,则在 b,c 列上的索引将不会被用到。
- left join 或 not exists 来优化 not in 操作,因为not in 也通常会使用索引失效。
4. 数据库设计时,应该要对以后扩展进行考虑
5. 程序连接不同的数据库使用不同的账号,禁止跨库查询
- 为数据库迁移和分库分表留出余地
- 降低业务耦合度
- 避免权限过大而产生的安全风险
6. 禁止使用 SELECT * 必须使用 SELECT <字段列表> 查询
原因:
- 消耗更多的 CPU 和 IO 以网络带宽资源
- 无法使用覆盖索引
- 可减少表结构变更带来的影响
7. 禁止使用不含字段列表的 INSERT 语句
如:
insert into t values ('a','b','c');
应使用:
insert into t(c1,c2,c3) values ('a','b','c');
8. 避免使用子查询,可以把子查询优化为 join 操作
通常**子查询在 in 子句中,且子查询中为简单 SQL(不包含 union、group by、order by、limit 从句) **时,才可以把子查询转化为关联查询进行优化。
select name,age from tb_employee where city in (select city-id fron tb_city where provice-id=1)
-- 转换为
select name,age from tb_employee a left join tb_city b on a.city = b.city-id where b.provice-id=1
子查询性能差的原因:
子查询的结果集无法使用索引,通常子查询的结果集会被存储到临时表中,不论是内存临时表还是磁盘临时表都不会存在索引,所以查询性能会受到一定的影响。特别是对于返回结果集比较大的子查询,其对查询性能的影响也就越大。
由于子查询会产生大量的临时表也没有索引,所以会消耗过多的 CPU 和 IO 资源,产生大量的慢查询。
9. 避免使用 JOIN 关联太多的表
对于 MySQL 来说,是存在关联缓存的,缓存的大小可以由 join_buffer_size 参数进行设置。
在 MySQL 中,对于同一个 SQL 多关联(join)一个表,就会多分配一个关联缓存,如果在一个 SQL 中关联的表越多,所占用的内存也就越大。
如果程序中大量的使用了多表关联的操作,同时 join_buffer_size 设置的也不合理的情况下,就容易造成服务器内存溢出的情况,就会影响到服务器数据库性能的稳定性。
同时对于关联操作来说,会产生临时表操作,影响查询效率,MySQL 最多允许关联 61 个表,建议不超过 5 个
10. 减少同数据库的交互次数
数据库更适合处理批量操作,合并多个相同的操作到一起,可以提高处理效率。
11. 对应同一列进行 or 判断时,使用 in 代替 or
in 的值不要超过 500 个,in 操作可以更有效的利用索引,or 大多数情况下很少能利用到索引。
12. 禁止使用 order by rand() 进行随机排序
order by rand() 会把表中所有符合条件的数据装载到内存中,然后在内存中对所有数据根据随机生成的值进行排序,并且可能会对每一行都生成一个随机值,如果满足条件的数据集非常大,就会消耗大量的 CPU 和 IO 及内存资源。
推荐在程序中获取一个随机值,然后从数据库中获取数据的方式。
13. WHERE 从句中禁止对列进行函数转换和计算
对列进行函数转换或计算时会导致无法使用索引
不推荐:
where date(create_time)='20190101'
推荐:
where create_time >= '20190101' and create_time < '20190102'
14. 在明显不会有重复值时使用 UNION ALL 而不是 UNION
- UNION 会把两个结果集的所有数据放到临时表中后再进行去重操作
- UNION ALL 不会再对结果集进行去重操作
15. 拆分复杂的大 SQL 为多个小 SQL
- 大 SQL 逻辑上比较复杂,需要占用大量 CPU 进行计算的 SQL
- MySQL 中,一个 SQL 只能使用一个 CPU 进行计算
- SQL 拆分后可以通过并行执行来提高处理效率
6. 数据库操作行为规范
1. 超 100 万行的批量写 (UPDATE,DELETE,INSERT) 操作,要分批多次进行操作
- 大批量操作可能会造成严重的主从延迟
主从环境中,大批量操作可能会造成严重的主从延迟,大批量的写操作一般都需要执行一定长的时间, 而只有当主库上执行完成后,才会在其他从库上执行,所以会造成主库与从库长时间的延迟情况
- binlog 日志为 row 格式时会产生大量的日志
大批量写操作会产生大量日志,特别是对于 row 格式二进制数据而言,由于在 row 格式中会记录每一行数据的修改,我们一次修改的数据越多,产生的日志量也就会越多,日志的传输和恢复所需要的时间也就越长,这也是造成主从延迟的一个原因
- 避免产生大事务操作
大批量修改数据,一定是在一个事务中进行的,这就会造成表中大批量数据进行锁定,从而导致大量的阻塞,阻塞会对 MySQL 的性能产生非常大的影响。
特别是长时间的阻塞会占满所有数据库的可用连接,这会使生产环境中的其他应用无法连接到数据库,因此一定要注意大批量写操作要进行分批
2. 对于大表使用 pt-online-schema-change 修改表结构
- 避免大表修改产生的主从延迟
- 避免在对表字段进行修改时进行锁表
对大表数据结构的修改一定要谨慎,会造成严重的锁表操作,尤其是生产环境,是不能容忍的。
pt-online-schema-change 它会首先建立一个与原表结构相同的新表,并且在新表上进行表结构的修改,然后再把原表中的数据复制到新表中,并在原表中增加一些触发器。把原表中新增的数据也复制到新表中,在行所有数据复制完成之后,把新表命名成原表,并把原来的表删除掉。把原来一个 DDL 操作,分解成多个小的批次进行。
3. 禁止为程序使用的账号赋予 super 权限
- 当达到最大连接数限制时,还运行 1 个有 super 权限的用户连接
- super 权限只能留给 DBA 处理问题的账号使用
4. 对于程序连接数据库账号,遵循权限最小原则
- 程序使用数据库账号只能在一个 DB 下使用,不准跨库
- 程序使用的账号原则上不准有 drop 权限
3. MYSQL索引失效
1. 最佳左前缀原则
最佳左前缀原则——如果索引了多列,要遵守最左前缀原则。指的是查询要从索引的最左前列开始并且不跳过索引中的列。
前提条件:表中已添加复合索引(username,password,age)
SQL | 是否使用索引 | 原因 |
select * from table where password = ‘xxx’ and age = 3 | 不使用索引 | 该查询缺少username,查询条件复合索引最左侧username缺少,违反了最佳左前缀原则,导致索引失效,变为ALL,全表扫描 |
select * from table where password = age = 3 | 不使用索引 | 查询条件缺少username,password,查询条件复合索引最左侧username,password缺少,违反了最佳左前缀原则,导致索引失效,变为ALL,全表扫描 |
select * from table where name = ‘tom’ | 使用索引 | 该查询只有一个username条件,根据最佳左前缀原则索引能够被使用到,但是是部分使用 |
2. 不在索引列上做任何操作
不在索引列上做任何操作(计算,函数,(自动或者手动)类型装换),会导致索引失效而导致全表扫描
SQL | 是否使用索引 | 原因 |
select * from table where left(name,2) = ‘tom’ | 不使用索引 | 虽然符合最佳左前缀原则但是对索引列使用了函数,导致索引失效,变为ALL,全表扫描 |
3. 范围条件右边的列失效(> 、< 、 >= 、 <=)
存储引擎不能使用索引中范围条件右边的列,范围之后索引失效。(< ,> between and)
SQL | 是否使用索引 | 原因 |
select * from table where name = ‘tom’ and age>12 and password = ‘xxx’ | 使用部分索引 | 索引使用到username和age,但是username是使用索引检索,而age着重索引排序,这时age为范围查找,password索引将失效 |
4. mysql使用不等于(!= 或者<>)
mysql使用不等于(!= 或者<>)的时候,无法使用索引,会导致索引失效
SQL | 是否使用索引 | 原因 |
select * from table where name != ‘tom’ | 不使用索引 | 索引使用了 != 条件 |
select * from table where name <> ‘tom’ | 不使用索引 | 索引使用了 <> 条件 |
5. mysql中使用is not null 或者 is null
SQL | 是否使用索引 | 原因 |
select * from table where name is not null | 不使用索引 | 索引使用了 is not null 条件 |
select * from table where name is null | 不使用索引 | 索引使用了 is null 条件 |
6. mysql中like查询是以%开头
mysql中like查询是以%开头,索引会失效变成全表扫描,覆盖索引。
SQL | 是否使用索引 | 原因 |
select * from where name like ‘%tom’ select * from where name like ‘%tom%’ | 不使用索引 | like查询是以%开头 |
7. 字符串不加单引号索引会失效
SQL | 是否使用索引 | 原因 |
select * from table where name = tom | 不使用索引 | 字符串不加单引号索引失效 |
8. 条件中有or
SQL | 是否使用索引 | 原因 |
select * from table where name = tom or age=12 | 不使用索引 | 条件中有or |
9. 使用全表扫描要比使用索引快
使用全表扫描要比使用索引快,则不会使用到索引