互联网技术社区|福缘小草|程序员技术博客
🏠首页
  • 开发必备
  • Java
  • Spring Boot
  • MyBatis
  • C#
  • 架构
  • 算法
  • Vue
  • JavaScript
  • HTML
  • MySQL
  • Oracle
  • SQL Server
  • PostgreSQL
  • Redis
  • MongoDB
  • ElasticSearch
  • influxDB
  • ClickHouse
  • Linux
  • Docker
  • K8s
  • 消息队列
  • Shell
  • Git
  • Nginx
  • IDEA
  • Windows
  • 安卓
  • 在线工具
  • 实用技巧
  • 开源项目
  • 好文
  • 资源
  • 网站
  • 导航
💖关于
  • 分类
  • 标签
  • 归档

baohua.yin

不会填坑的程序员不是一个好程序猿!
🏠首页
  • 开发必备
  • Java
  • Spring Boot
  • MyBatis
  • C#
  • 架构
  • 算法
  • Vue
  • JavaScript
  • HTML
  • MySQL
  • Oracle
  • SQL Server
  • PostgreSQL
  • Redis
  • MongoDB
  • ElasticSearch
  • influxDB
  • ClickHouse
  • Linux
  • Docker
  • K8s
  • 消息队列
  • Shell
  • Git
  • Nginx
  • IDEA
  • Windows
  • 安卓
  • 在线工具
  • 实用技巧
  • 开源项目
  • 好文
  • 资源
  • 网站
  • 导航
💖关于
  • 分类
  • 标签
  • 归档
  • MySQL中延时或定时操作
  • select count查找是否存在效率问题
  • 批量清空数据库所有表数据
  • 字段类型date, datetime设置0000-00-00默认值报错
  • MySQL查询语句优化方法
  • MySQL查询 count(1) 比 count(*) 效率对比
  • Mysql中的COALESCE函数
  • MySQL字符串连接函数 ,分组连接函数
  • MySQL
baohua.yin
2023-03-03

select count查找是否存在效率问题

根据某一条件从数据库表中查询 『有』与『没有』,只有两种状态,那为什么在写SQL的时候,还要SELECT count(*) 呢?

目前多数人的写法

多次REVIEW代码时,发现如下现象:

业务代码中,需要根据一个或多个条件,查询是否存在记录,不关心有多少条记录。普遍的SQL及代码写法如下。

SQL写法:

SELECT count(*) FROM table WHERE a = 1 AND b = 2

Java写法:

int nums = xxDao.countXxxxByXxx(params);
if ( nums > 0 ) {
  //当存在时,执行这里的代码
} else {
  //当不存在时,执行这里的代码
}

是不是感觉很OK,没有什么问题

优化方案

SQL写法:

SELECT 1 FROM table WHERE a = 1 AND b = 2 LIMIT 1

Java写法:

Integer exist = xxDao.existXxxxByXxx(params);
if ( exist != NULL ) {
  //当存在时,执行这里的代码
} else {
  //当不存在时,执行这里的代码
}

SQL不再使用count,而是改用LIMIT 1,让数据库查询时遇到一条就返回,不要再继续查找还有多少条了。

业务代码中直接判断是否非空即可。

总结

根据查询条件查出来的条数越多,性能提升的越明显,在某些情况下,还可以减少联合索引的创建。

为什么都说SELECT * 效率低

不需要的列会增加数据传输时间和网络开销

用“SELECT ”数据库需要解析更多的对象、字段、权限、属性等相关内容,在 SQL 语句复杂,硬解析较多的情况下,会对数据库造成沉重的负担。
增大网络开销;
有时会误带上如log、IconMD5之类的无用且大文本字段,数据传输size会几何增涨。如果DB和应用程序不在同一台机器,这种开销非常明显
即使 mysql 服务器和客户端是在同一台机器上,使用的协议还是 tcp,通信也是需要额外的时间。

对于无用的大字段,如 varchar、blob、text,会增加 io 操作

准确来说,长度超过 728 字节的时候,会先把超出的数据序列化到另外一个地方,因此读取这条记录会增加一次 io 操作。(MySQL InnoDB)

失去MySQL优化器“覆盖索引”策略优化的可能性

SELECT * 杜绝了覆盖索引的可能性,而基于MySQL优化器的“覆盖索引”策略又是速度极快,效率极高,业界极为推荐的查询优化方式。
例如,有一个表为t(a,b,c,d,e,f),其中,a为主键,b列有索引。

那么,在磁盘上有两棵 B+ 树,即聚集索引和辅助索引(包括单列索引、联合索引),分别保存(a,b,c,d,e,f)和(a,b),如果查询条件中where条件可以通过b列的索引过滤掉一部分记录,查询就会先走辅助索引,如果用户只需要a列和b列的数据,直接通过辅助索引就可以知道用户查询的数据。
如果用户使用select *,获取了不需要的数据,则首先通过辅助索引过滤数据,然后再通过聚集索引获取所有的列,这就多了一次b+树查询,速度必然会慢很多。

由于辅助索引的数据比聚集索引少很多,很多情况下,通过辅助索引进行覆盖索引(通过索引就能获取用户需要的所有列),都不需要读磁盘,直接从内存取,而聚集索引很可能数据在磁盘(外存)中(取决于buffer pool的大小和命中率),这种情况下,一个是内存读,一个是磁盘读,速度差异就很显著了,几乎是数量级的差异。

上次更新: 2023/03/03, 13:18:42
MySQL中延时或定时操作
批量清空数据库所有表数据

← MySQL中延时或定时操作 批量清空数据库所有表数据→

最近更新
01
如何进行科学上网
05-31
02
分享(一个外地女孩,死在了我出租的公寓)
08-18
03
温家宝总理—《我的母亲》
06-13
更多文章>
Copyright © 2019-2025 1024fuli.com | 本站所有资源收集整理于网络,如有侵权请发邮件联系删除。| 粤ICP备18082936号-1 | 由又拍云提供CDN支持
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式