相关文章推荐
豪爽的啄木鸟  ·  Statement Summary ...·  4 月前    · 
讲道义的大海  ·  Laravel中如何将多SQL请求生成的二维 ...·  4 月前    · 
难过的打火机  ·  Filtering collections ...·  1 年前    · 
豁达的跑步鞋  ·  C#.Net Core控制台程序连接SQL ...·  1 年前    · 
苦恼的羊肉串  ·  VSTO用clickonce发布时如何自建数 ...·  2 年前    · 
低调的警车  ·  mysql递归查询所有子节点·  2 年前    · 
深情的山羊  ·  python等待10秒执行下一命令的方法_p ...·  3 年前    · 
Code  ›  18 | 为啥SQL逻辑相同,性能差异大开发者社区
索引 select sql优化
https://cloud.tencent.com/developer/article/1767557
愉快的钱包
3 年前
作者头像
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表放前面效率高?网上各种答案,但感觉都没有十分的说服力,期待老师的指点!

 
推荐文章
豪爽的啄木鸟  ·  Statement Summary Tables | TiDB 文档中心
4 月前
讲道义的大海  ·  Laravel中如何将多SQL请求生成的二维数组转换为Collection
4 月前
难过的打火机  ·  Filtering collections - Windows apps | Microsoft Learn
1 年前
豁达的跑步鞋  ·  C#.Net Core控制台程序连接SQL Server SqlConnection类报错_netcore sqlconnection-CSDN博客
1 年前
苦恼的羊肉串  ·  VSTO用clickonce发布时如何自建数字证书 - 简书
2 年前
低调的警车  ·  mysql递归查询所有子节点
2 年前
深情的山羊  ·  python等待10秒执行下一命令的方法_python_脚本之家
3 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号