《MySQL tips:查询时,尽量不要对字段进行操作》

维护一个交易系统,交易记录表tradelog包含交易流水号(tradeid)、交易员id(operator)、交易时间(t_modified)等字段。
建表语句如下:

create table 'tradelog' (
	'id' int(11) not null,
	'tradeid' varchar(32) default null,
	'operator' int(11) default null,
	't_modified' datetime default null,
	primary key ('id'),
	key 'tradeid' ('tradeid'),
	key 't_modified' ('t_modified')
) engine = InnoDB default charset = utf8mb4;

假设已经记录了从2016年初到2018年底的所有数据,运营部门有一个需求:统计发生在所有年份中7月份的交易记录总数。
我们可以这样写:

select count(*) from tradelog where month(t_modified) = 7;

t_modified字段上有索引,但是会发现这条语句执行时间特别久,才返回结果。
但是MySQL规定:如果对字段做了函数计算,就不能使用索引。
也就是说:
条件为where t_modified = '2018-7-1'时,可以用上索引,而改成where month(t_modified) = 7的时候就不行了。
B+树同一层的兄弟节点是有序的,所以可以快速定位。
而当使用了month()函数,传入7时,其实B+树不知道接下来是取子节点还是兄弟节点。
所以说对索引字段做函数操作,优化器无法判断最终的结果是不是有序的,所以就会放弃使用搜索树,只能全部扫描该索引树。所以建议在查询时,尽量不要对字段进行操作

为了能够用上索引的快速定位能力,我们就要把SQL语句改成基于字段本身的范围查询:

select count(*) from tradelog where
	-> (t_modified >= '2016-7-1' and t_modified < '2016-8-1') or
	-> (t_modified >= '2017-7-1' and t_modified < '2017-8-1') or
	-> (t_modified >= '2018-7-1' and t_modified < '2018-8-1');
	

优化器在对于不改变有序性的函数上,也不会考虑使用索引。比如:对于select * from tradelog where id + 1 = 10000这个SQL语句,
这个+1不会改变有序性,但是优化器还是不能用id索引快速定位到9999这一行。所以需要我们在写SQL语句时,手动改写成where id = 10000 - 1才行。

猜你喜欢

转载自blog.csdn.net/qq_42604176/article/details/115419312