为什么这些sql逻辑相同,性能差异巨大

一:条件字段函数操作:

mysql> 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;

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

如果是where t_modified='2018-7-1';就会像上图执行的逻辑。

实际上,b+数提供的这个快速定位能力,来源于同一层兄弟节点的有序性。

如果传入7树的第一层就不知道怎么办了。

对索引字段做函数操作,可能会破坏函数索引值的有序性,所以放弃走搜索树。

使用了t_modified这个索引,扫描了整个索引的所有值。

优化:mysql> 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');

 二:隐式类型转换

mysql> select * from tradelog where tradeid=110717;
tradeid是varchar(32),这里是把字符串转化为了整数。

相当于

mysql> select * from tradelog where  CAST(tradid AS signed int) = 110717;

 三:隐式字符编码转换

mysql> CREATE TABLE `trade_detail` (
  `id` int(11) NOT NULL,
  `tradeid` varchar(32) DEFAULT NULL,
  `trade_step` int(11) DEFAULT NULL, /* 操作步骤 */
  `step_info` varchar(32) DEFAULT NULL, /* 步骤信息 */
  PRIMARY KEY (`id`),
  KEY `tradeid` (`tradeid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into tradelog values(1, 'aaaaaaaa', 1000, now());
insert into tradelog values(2, 'aaaaaaab', 1000, now());
insert into tradelog values(3, 'aaaaaaac', 1000, now());

insert into trade_detail values(1, 'aaaaaaaa', 1, 'add');
insert into trade_detail values(2, 'aaaaaaaa', 2, 'update');
insert into trade_detail values(3, 'aaaaaaaa', 3, 'commit');
insert into trade_detail values(4, 'aaaaaaab', 1, 'add');
insert into trade_detail values(5, 'aaaaaaab', 2, 'update');
insert into trade_detail values(6, 'aaaaaaab', 3, 'update again');
insert into trade_detail values(7, 'aaaaaaab', 4, 'commit');
insert into trade_detail values(8, 'aaaaaaac', 1, 'add');
insert into trade_detail values(9, 'aaaaaaac', 2, 'update');
insert into trade_detail values(10, 'aaaaaaac', 3, 'update again');
insert into trade_detail values(11, 'aaaaaaac', 4, 'commit');

mysql> select d.* from tradelog l, trade_detail d where d.tradeid=l.tradeid and l.id=2; /* 语句 Q1*/

 1.在tradelog上使用了主键索引。

2.key=null 表示没有在详情表上使用索引。全表扫面

 

 第三步的可以看做如下sql:

mysql> select * from trade_detail where tradeid=$L2.tradeid.value;
其中$L2.tradeid.value的字符集是utf8mb4;

等同于select * from trade_detail  where CONVERT(traideid USING utf8mb4)=$L2.tradeid.value;
连接过程中要求在被动驱动表的索引字段上加函数操作。

看下面这个:

mysql>select l.operator from tradelog l , trade_detail d where d.tradeid=l.tradeid and d.id=4;

 select operator from tradelog  where traideid =$R4.tradeid.value;
select operator from tradelog  where traideid =CONVERT($R4.tradeid.value USING utf8mb4);
这里的convert函数是加在输入参数上的。这样就可以用上被驱动表的traidid索引。

如果要优化

(1)alter table trade_detail modify tradeid varchar(32) CHARACTER SET utf8mb4 default null;
(2)mysql> select d.* from tradelog l , trade_detail d where d.tradeid=CONVERT(l.tradeid USING utf8) and l.id=2;


猜你喜欢

转载自www.cnblogs.com/hanguocai/p/10170473.html