相关文章推荐
绅士的酱牛肉  ·  面向开发人员的 PL/SQL | ...·  1 月前    · 
踏实的胡萝卜  ·  标量 UDF 内联 - SQL ...·  1 月前    · 
道上混的领结  ·  查询处理体系结构指南 - SQL ...·  1 月前    · 
有胆有识的小狗  ·  MongoDB笔记(六) ...·  1 年前    · 
帅呆的豌豆  ·  在matplotlib中动态更新绘图-腾讯云 ...·  1 年前    · 
谦虚好学的跑步机  ·  从零开始的Django论坛搭建(一)混沌中的 ...·  2 年前    · 
聪明伶俐的蛋挞  ·  如何看待高达SEED? - 知乎·  2 年前    · 
低调的核桃  ·  IOS swift实现密码的显示与隐藏切换 ...·  2 年前    · 
Code  ›  18 | 为啥SQL逻辑相同,性能差异大开发者社区
索引 select sql优化
https://cloud.tencent.com/developer/article/1767557
愉快的钱包
2 年前
作者头像
HaC
0 篇文章

18 | 为啥SQL逻辑相同,性能差异大

前往专栏
腾讯云
开发者社区
文档 意见反馈 控制台
首页
学习
活动
专区
工具
TVP
文章/答案/技术大牛
发布
首页
学习
活动
专区
工具
TVP
返回腾讯云官网
社区首页 > 专栏 > HaC的技术专栏 > 18 | 为啥SQL逻辑相同,性能差异大

18 | 为啥SQL逻辑相同,性能差异大

作者头像
HaC
发布 于 2020-12-30 17:48:06
545 0
发布 于 2020-12-30 17:48:06
举报

第一种:隐式类型转换

  1. 如果规则是“将字符串转成数字”,那么就是做数字比较,结果应该是 1;
  2. 如果规则是“将数字转成字符串”,那么就是做字符串比较,结果应该是 0。

情况一:

此时cg_bidid的类型是bigint 在 MySQL 中,字符串和数字做比较的话,是将字符串转换成数字。

EXPLAIN SELECT * FROM cg_bid WHERE id ="104";
EXPLAIN SELECT * FROM cg_bid WHERE id =104;

这两句都一样的性能,所以说where的值是整型,右侧的值无论是字符串还是整型,不会出现隐式类型转换。

情况二:

此时cg_bid的id 的类型为varchar

where条件的值是字符串类型,右侧的值是整型,会进行类型转换,会进行全盘扫描,无法使用索引。

EXPLAIN SELECT * FROM cg_bid WHERE id =104;

explain结果:

在这里插入图片描述
在这里插入图片描述

看到这里全盘扫描了(rows),而且key为NULL,证明没有走索引。

第一种:条件字段函数操作

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;

这种不会走索引

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

下面是这个 t_modified 索引的示意图。方框上面的数字就是 month() 函数对应的值。

在这里插入图片描述
在这里插入图片描述

果你的 SQL 语句条件用的是 where t_modified='2018-7-1’的话,引擎就会按照上面绿色箭头的路线,快速定位到 t_modified='2018-7-1’需要的结果。 为了能够用上索引的快速定位能力,我们就要把 SQL 语句改成基于字段本身的范围查询。按照下面这个写法,优化器就能按照我们预期的,用上 t_modified 索引的快速定位能力了。

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 操作并不会改变有序性,但是 MySQL 优化器还是不能用 id 索引快速定位到 9999 这一行。所以,需要你在写 SQL 语句的时候,手动改写成 where id = 10000 -1 才可以。

第三种:隐式字符编码转换

连表,字符集不一样也会不走索引。

像这种:

select * from trade_detail  
where CONVERT(traideid USING utf8mb4)=$L2.tradeid.value; 

CONVERT() 函数,在这里的意思是把输入的字符串转成 utf8mb4 字符集。 连接过程中要求在被驱动表的索引字段上加函数操作,是直接导致对被驱动表做全表扫描的原因。

假如表的数据较大,这种情况可以使用以下的方法优化:移到右侧

select operator from tradelog  
where traideid = CONVERT($R4.tradeid.value USING utf8mb4); 

课程后面看到有一个有意思的问答:

老师,有道面试题困扰了很久,求指教!题目是这样的,a表有100条记录,b表有10000条记录,两张表做关联查询时,是将a表放前面效率高,还是b表放前面效率高?网上各种答案,但感觉都没有十分的说服力,期待老师的指点!

 
推荐文章
绅士的酱牛肉  ·  面向开发人员的 PL/SQL | Oracle 中国
1 月前
踏实的胡萝卜  ·  标量 UDF 内联 - SQL Server | Microsoft Learn
1 月前
道上混的领结  ·  查询处理体系结构指南 - SQL Server | Microsoft Learn
1 月前
有胆有识的小狗  ·  MongoDB笔记(六) 删除操作(详细)_deletemany 通过objectid批量删除-CSDN博客
1 年前
帅呆的豌豆  ·  在matplotlib中动态更新绘图-腾讯云开发者社区-腾讯云
1 年前
谦虚好学的跑步机  ·  从零开始的Django论坛搭建(一)混沌中的独白+一切的开始_django 论坛_Dulow的博客-CSDN博客
2 年前
聪明伶俐的蛋挞  ·  如何看待高达SEED? - 知乎
2 年前
低调的核桃  ·  IOS swift实现密码的显示与隐藏切换 - 猿哥爱码 - 博客园
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号