「每天一个知识点」数据库sql优化
mhr18 2024-10-07 10:10 31 浏览 0 评论
点击上方"java全栈技术"关注我们,每天学习一个java知识点
1 正确使用索引
数据库性能很关键的一点在于sql是否能正确使用索引,我们应该尽量避免无法使用索引的sql写法。
示例:表t的id和name数据类型分别为number和varchar2,且id为从1开始递增的主键,表记录数为10万
索引查询范围尽可能小,否则可能用不到索引
无法使用索引(查询范围太大):
select * from t where id>10;
正确使用索引(查询范围很小):
select * from t where id<10;
尽量避免对索引列进行函数计算,请尽可能将函数运算移到条件右边或者创建函数索引。
无法使用索引(左边条件使用了函数):
select * from t where id+5=10;
正确使用索引(将函数运算移到条件右边):
select * from t1 where id=10-5
或者创建函数索引
create index idx_t1 on t1(id+5)
两个字段直接进行比较无法使用索引(本例中id1为主键)
无法使用索引(条件两边含不同字段):
select * from t where id1=id2+10
正确使用索引(将两个字段移到条件左边并创建函数索引):
select * from t1 where id1-id2=10; create index idx_t1 on t1(id1-id2)
不同类型的数值比较可能无法使用索引
无法使用索引(条件两边含不同类型字段,db会做隐式函数转换,使得索引无法正常使用):
select * from t where name=123
正确使用索引(两边数据类型一致):
select * from t where name='123'
对于复合索引,sql语句一般情况下必须使用第一个索引字段,索引才会生效(本例中id,name为联合索引)
无法使用索引(id为索引列的第一个字段,单独查询name一般不会使用索引):
select * from t where name='123'
正确使用索引(条件中使用了索引列的第一个字段,where条件中的字段先后顺序没有关系):
select * from t where id=1select * from t where id=1 and name='abc'select * from t where name='abc' and id=1
查询条件中,尽量避免使用null作为条件,如果有查询需求,可以在null字段上创建默认值
无法使用索引(oracle不行,mysql可以):
select * from t where id is null;select * from t where id is not null;
正确使用索引:
alter table t modify id int default 0;select * from t where id is null
转换为
select * from t where id=0
对于索引的比较,尽量避免使用 <>(!=)
无法使用索引(无论任何情况都只能全表扫描):
select * from t where id !=0;
正确使用索引(如果非0值占少数,则两个条件都可能用到索引):
select * from t where id>0 or id<0
like查询时,%不能出现在条件最左边
无法使用索引(无论任何情况都只能全表扫描):
select * from t where name like '%abc;select * from t where name like '%abc%;
如果要高效实现如上查询,建议使用全文本索引或者第三方搜索引擎。
正确使用索引:
select * from t where name like 'abc%'
如果可以,尽可能只查询索引列
需求:只需要查询表t的id和name值,id和name上有联合索引
低效查询(先扫描索引,再回表):
select * from t1 where id=1 and name=>'abc'
高效查询(只需要扫描索引):
select id,name from t1 where id=1 and name>'abc'
2 尽量减少数据库的访问
使用乐观锁,避免大多数无效数据库访问
低效sql:
select count(1) from t1 where conditionif count(1)>0 then update t1 set ...
高效sql:
update t1 set ...if result=0 thenexception
高效存在性判断
低效sql:
select count(*) into t_count from t where condition;if t_count> 0 then select cols into t_cols from t where condition;elseotherstatement;end;
高效sql:
select 1 into t_count from t where condition and rownum<2;if exist(1) then select cols into t_cols from t where condition;elseotherstatement;end;
使用casewhen函数减少数据库访问次数
低效sql(需要访问3次数据库)
select sum(sum1) from( select sum(data_object_id)*0.001 sum1 from t1 where data_object_id<=10000union select sum(data_object_id)*0.002 sum1 from t1 where data_object_id>10000 and data_object_id<=50000union select sum(data_object_id)*0.003 sum1 from t1 where data_object_id>50000);
高效sql(访问一次数据库)
select sum(case when data_object_id<=10000 then data_object_id*0.001 when data_object_id>10000 and data_object_id<=50000 then data_object_id*0.002 when data_object_id>50000 then data_object_id*0.003 else 0end) from t1;
3 尽量减少排序
用unionall替代union
二者的区别是后者会合并后排序去重,前者不需要这个工作
减少排序结果集
示例1:
低效sql(全部记录进行排序后过滤):
select name,count(1) from t1 group by name having name>'abc'
高效sql(过滤数据后再排序):
select name,count(1) from t1 where name>'abc' group by name;
示例2:
低效分页查询(对所有满足条件的记录进行排序后分页):
select object_id,object_name,rn from (select a.*, rownum rn from (select * from t1 where object_id>0 order by object_id) a )where rn <= &last and rn >= &first;
高效分页查询(只对满足条件的记录排序前rn条):
select object_id,object_name,rn from (select a.*, rownum rn from (select * from t1 where object_id>0 order by object_id) a where rownum <= &last)where rn >= &first;
尽可能利用索引排序
低效sql(排序操作在表上):
select * from (select rownum no,t.* from (select * from t where lmodify> (sysdate - interval '60' day) order by lmodify desc) t where rownum < 24100 ) where no > 24000
高效sql(排序操作在索引上)
select * from t e,(select * from (select c.*,rownum rcount from (select rowid rn,lmodify from t where lmodify> (sysdate - interval '30' day)order by lmodify desc ) cwhere rownum<24100) where rcount>24000) dwhere e.rowid=d.rn
4 in/exists使用规范
示例:当有a、b 两个结果集,当结果集b 很大时,a 较小时,适用exists,如:
select * from a where exists(select 1 from b where a.column = b.column);
当结果集 a 很大时,b 很小时,适用in,如:
select *from awhere a.column in(select b.columnfrom b)
5 避免锁问题
事务尽可能小,尽量避免大事务,频繁提交的大事务会明显带来并发的降低。
批量处理的任务最好能较少执行频率,且最好放在访问量低的时候做。
避免死锁
死锁产生原因:session间由于对锁的获取产生了资源竞争,导致发生session的互相等待的僵持状态,即死锁。一般非事务锁(比如表锁)由于锁是一次性完全占有和释放,不会在同一资源上产生互相等待,因此不会产生死锁,比如mysql中的MyISAM存储引擎;而事务锁(比如页锁和行锁)由于在同一事务中锁是逐渐获取的,如果两个session获取锁的顺序相反,则可能产生死锁。Oracle和mysql中的InnoDB存储引擎都属于这一类。
死锁示例:
session1 | session2 |
---|---|
mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec) mysql> select * from table_1 where where id=1 for update; ... 做一些其他处理... | mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec) mysql> select * from table_2 where id=1 for update; ... |
select * from table_2 where id =1 for update; 因session_2已取得排他锁,等待 | 做一些其他处理... |
mysql> select * from table_1 where where id=1 for update; 死锁 |
死锁的处理:oracle和mysql对于死锁会自动探测并处理,一般是选择其中一个事务进行回滚。
死锁的危害:降低系统并发性和用户体验。
如何避免死锁:在不同的事务中对表的操作顺序保持一致。比如在两个方法中都对order和order_detail进行更新,那么要保证两个方法中两个表的更新顺序是一致的。
相关推荐
- 甲骨文签署多项大型云协议,其一未来可贡献超300亿美元年收入
-
IT之家7月1日消息,根据甲骨文Oracle当地时间6月30日向美国证券交易委员会(SEC)递交的FORM8-K文件,该企业在始于2025年6月1日的202...
- 甲骨文获TEMU巨额合同,后者大部分基础设施将迁移至Oracle云
-
IT之家6月23日消息,Oracle甲骨文创始人、董事长兼首席技术官LarryEllison(拉里埃里森)在本月早些时候的2025财年第四财季和全财年财报电话会议上表示,Oracle...
- Spring Boot 自定义数据源设置,这些坑你踩过吗?
-
你在使用SpringBoot进行后端开发的过程中,是不是也遇到过这样的问题:项目上线后,数据库连接总是不稳定,偶尔还会出现数据读取缓慢的情况,严重影响了用户体验。经过排查,发现很大一部分原因竟然...
- 一个开箱即用的代码生成器(一个开箱即用的代码生成器是什么)
-
今天给大家推荐一个好用的代码生成器,名为renren-generator,该项目附带前端页面,可以很方便的选择我们所需要生成代码的表。首先我们通过git工具克隆下来代码(地址见文末),导入idea。...
- 低代码建模平台-数据挖掘平台(低代码平台的实现方式)
-
现在来看一下数据连接。·这里是管理数据连接的空间,点击这里可以新增一个数据连接。·输入连接名称,然后输入url,是通过gdbc的方式去连接的数据库,目前是支持mysql、oracle以及国产数据库达梦...
- navicat 17.2.7连接oracle数据库提示加载oracle库失败
-
系统:macOS15.5navicat版本:navicatpremiumlite17.2.7连接oracle测试报错:加载oracle库失败【解决办法】:放达里面找到程序,显示简介里面勾选“使...
- 开源“Windows”ReactOS更新:支持全屏应用
-
IT之家6月17日消息,ReactOS团队昨日(6月16日)在X平台发布系列推文,公布了该系统的最新进展,包括升级Explorer组件,支持全屏应用,从Wine项目引入了...
- SSL 推出采用全模拟内置混音技术的模拟调音台Oracle
-
英国调音台传奇品牌SolidStateLogic宣布推出Oracle——一款采用全模拟内置混音技术的调音台,在紧凑的AWS尺寸机箱内集成了大型调音台的功能。该调音台提供24输入和...
- 47道网络工程师常见面试题,看看有没有你不会的!
-
你们好,我的网工朋友。网络工程师面试的时候,都会被问到什么?这个问题其实很泛,一般来说,你肯定要先看明白岗位需求写的是什么。基本上都是围绕公司需要的业务去问的。但不可否认的是,那些最基础的概念,多少也...
- 汉得信息:发布EBS系统安装启用JWS的高效解决方案
-
e公司讯,从汉得信息获悉,近日,微软官方宣布InternetExplorer桌面应用程序将于2022年6月15日正式停用。目前大部分客户都是使用IE浏览器打开EBS的Form界面,IE停用后,只能使...
- 36.9K star ! 推荐一个酷炫低代码开发平台!功能太强!
-
前言最近在逛github,看看能不能搜罗到一些对自己有帮助的开源软件。不经意间看到一个高star的java开源项目:jeecg-boot。进入在线演示版一看,感叹实在是太牛了!此开源项目不管是给来学习...
- Linux新手入门系列:Linux下jdk安装配置
-
本系列文章是把作者刚接触和学习Linux时候的实操记录分享出来,内容主要包括Linux入门的一些理论概念知识、Web程序、mysql数据库的简单安装部署,希望能够帮到一些初学者,少走一些弯路。注意:L...
- 手把手教你在嵌入式设备中使用SQLite3
-
摘要:数据库是用来存储和管理数据的专用软件,使得管理数据更加安全,方便和高效。数据库对数据的管理的基本单位是表(table),在嵌入式linux中有时候它也需要用到数据库,听起来好难,其实就是几个函数...
- JAVA语言基础(java语言基础知识)
-
一、计算机的基本概念什么是计算机?计算机(Computer)全称:电子计算机,俗称电脑。是一种能够按照程序运行、自动高速处理海量数据的现代化智能电子设备。由硬件和软件组成、没有安装过任何软件的计算机称...
- 再见 Navicat!一款开源的 Web 数据库管理工具!
-
大家好,我是Java陈序员。在日常的开发工作中,常常需要与各种数据库打交道。而为了提高工作效率,常常会使用一些可视化工具进行操作数据库。今天,给大家介绍一款开源的数据库管理工具,无需下载安装软件,基...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 甲骨文签署多项大型云协议,其一未来可贡献超300亿美元年收入
- 甲骨文获TEMU巨额合同,后者大部分基础设施将迁移至Oracle云
- Spring Boot 自定义数据源设置,这些坑你踩过吗?
- 一个开箱即用的代码生成器(一个开箱即用的代码生成器是什么)
- 低代码建模平台-数据挖掘平台(低代码平台的实现方式)
- navicat 17.2.7连接oracle数据库提示加载oracle库失败
- 开源“Windows”ReactOS更新:支持全屏应用
- SSL 推出采用全模拟内置混音技术的模拟调音台Oracle
- 47道网络工程师常见面试题,看看有没有你不会的!
- 汉得信息:发布EBS系统安装启用JWS的高效解决方案
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (55)
- oracle 乐观锁 (51)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)