06 05 2020

1 函数操作

对条件字段做函数操作走不了索引

c字段类型

`c` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,


SQL如下:

select * from t1 where date(c) ='2019-05-21';


因为 SQL 的目的是查询 2019-05-21 当天所有的记录,因此可以改成范围查询,如下:

select * from t1 where c>='2019-05-21 00:00:00' and c<='2019-05-21 23:59:59';


2 隐式转换

a字段类型

`a` varchar(20) DEFAULT NULL,


SQL如下:

select * from t1 where a=1000;


a 字段类型是 varchar(20),而语句中 a 字段条件值没加单引号,导致 MySQL 内部会先把a转换成int型,再去做判断,相当于实际执行的 SQL 语句如下:

select * from t1 where cast(a as signed int) =1000;


因此又回到上面说的:对索引字段做函数操作时,优化器会放弃使用索引


优化:

select * from t1 where a='1000';


3 范围查询

要取出b字段1到2000范围数据,SQL 如下 :

select * from t1 where b>=1 and b <=2000;


优化器会根据检索比例、表大小、I/O块大小等进行评估是否使用索引。比如单次查询的数据量过大,优化器将不走索引。


优化:

select * from t1 where b>=1 and b <=1000;
select * from t1 where b>=1001 and b <=2000;


实际这种范围查询而导致使用不了索引的场景经常出现,比如按照时间段抽取全量数据,每条SQL抽取一个月的;或者某张业务表历史数据的删除。遇到此类操作时,应该在执行之前对SQL做explain分析,确定能走索引,再进行操作,否则不但可能导致操作缓慢,在做更新或者删除时,甚至会导致表所有记录锁住,十分危险。



4 计算操作

对索引字段做运算将使用不了索引。


SQL 如下 :

select * from t1 where b-1 =1000;


优化:

select * from t1 where b =1000 + 1;


一般需要对条件字段做计算时,建议通过程序代码实现,而不是通过MySQL实现。如果在MySQL中计算的情况避免不了,那必须把计算放在等号后面。



总结

写 SQL 时应该注意这些点:


  • 应该避免隐式转换

  • like查询不能以%开头

  • 范围查询时,包含的数据比例不能太大

  • 不建议对条件字段做运算及函数操作


图片描述