我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Oracle学习(八) --- SQL优化

短信预约 信息系统项目管理师 报名、考试、查分时间动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Oracle学习(八) --- SQL优化

Oracle学习(八) --- SQL优化

1、前置工具:执行计划 Explain Plan

1.1、概念

一条查询语句在 ORACLE 中的执行过程或访问路径的描述。即就是对一个查询任务,做出一份怎样去完成任务的详细方案。

  • 执行计划:用于记录SQL执行每一个细节。
  • 执行计划目的:通过分析SQL执行每一个细节,从而确定优化方案。

1.2、Oracle执行计划

  • 方式1:使用SQL语句进行查询,结果更加详细。

    --运行“执行计划”: explain plan for SQL语句;
    explain plan for select * from dual;
    --查询“执行计划”结果(固定语句)
    select * from table(dbms_xplan.display());
    
  • 方式2:使用PL/SQL Dev 工具提供"执行计划窗口"进行查询,内容相对而言少一些。

1.3、执行原则

  • 执行计划原则:由上而下、从右向左。
    • 由上至下:在执行计划中一般含有多个节点,相同级别(或并列)的节点,靠上的优先执行,靠下的后执行
    • 从右向左:在某个节点下还存在多个子节点,先从最靠右的子节点开始执行
  • 一般按缩进长度来判断,缩进最大的最先执行,如果有2行缩进一样,那么就先执行上面的。
字段 解释
ID 一个序号,但不是执行的先后顺序。执行的先后根据缩进来判断。
Operation 当前操作的内容。
Rows 当前操作的Cardinality,Oracle估计当前操作的返回结果集。
Cost(CPU) Oracle 计算出来的一个数值(代价),用于说明SQL执行的代价。
Time Oracle 估计当前操作的时间。

2、准备数据

2.1、前置技术演示

  • 前置技术:
    • 随机数字、随机字符串
    • 重复执行次数
    • 系统时间处理
    • 根据查询结果创建表
-- 2 准备数据

--- 2.1 获得随机数据  dbms_random
-- dbms_random.value(a,b) 生产[a,b) 之间 一个随机数
-- dbms_random.string(符号,数量) 根据"符号"生产指定“长度”随机字符串
---- 符号:u 大写字母、l 小写字母、x 大写字母和数字、a 混合型(大小写) 、p 可打印
-- 1.1) 获得一个 1-10 随机浮点数
select dbms_random.value(1,10) from dual;

-- 1.2) 获得一个 1-10 随机整数
select round( dbms_random.value(1,10) ) from dual;
select trunc( dbms_random.value(1,10) ) from dual;

-- 2) 获得长度为6的随机字符串
select dbms_random.string("u",6) from dual;
select dbms_random.string("l",6) from dual;
select dbms_random.string("x",20) from dual;
select dbms_random.string("a",6) from dual;
select dbms_random.string("p",6) from dual;


-- 2.2 控制查询条件(重复执行次数)
select dbms_random.string("a",6) from dual 
 connect by level <= 10;

-- 2.3 系统时间
-- 1) 当前系统时间
select to_char(sysdate , "yyyy-mm-dd hh24:mi:ss") from dual;
select to_char(sysdate + 1000000/24/3600 , "yyyy-mm-dd hh24:mi:ss") from dual;

-- 2.4 根据查询结果创建表
-- 语法:  create table 表名 as  查询语句;
--- 1) 查询
select trunc( dbms_random.value(18,120) ) age , dbms_random.string("x",4) name from dual;
--- 2) 创建
create table t_person
as
select trunc( dbms_random.value(18,120) ) age , dbms_random.string("x",4) name from dual;


2.2、准备1千万条数据

  • 约耗时3-10分钟
--- 准备1千万条数据
create table t_user
as
select 
  rownum as id,
  to_char(sysdate + rownum / 24 / 3600 , "yyyy-mm-dd hh24:mi:ss") as birthday,
  trunc( dbms_random.value(18,140) ) as age,
  dbms_random.string("x",20) as username
from dual
connect by level <= 10000000;

  • 生成表之后,插入一百万条测试数据
insert into t_user(ID, birthday,age,username)
	select 1000000+rownum as id,
        to_char(sysdate + rownum/24/3600, "yyyy-mm-dd hh24:mi:ss") as birthday,
        trunc(dbms_random.value(0, 100)) as age,
        dbms_random.string("x", 20) username
    from dual
  		connect by level <= 1000000;

3、优化

3.1、使用索引(可以大大提高检索速度)

--优化1:使用索引
-- 未使用搜索 2.480
select * from t_user where id = 1;
-- 设置主键,自带唯一索引
alter table t_user add constraint user_pk primary key (id);
-- 创建索引后 0.046
select * from t_user where id = 1;

3.2、避免在WHERE字句中使用NULL

  • 使用null,讲放弃索引,进行全表扫描
--优化2:避免在where中使用null
-- 1) 给age添加普通索引
create index user_age_index on t_user(age);
-- 2) 查询age = 18所有信息  0.051
select * from t_user where age = 18;
-- 3) 更新id=1 age为null
update t_user set age = null where id = 1;
commit;
-- 4) 查询null数据
-- 查看age是否为null,0.058
select * from t_user where id = 1;
-- 根据null查询,1.396
select * from t_user where age is null;

3.3、尽量不使用不等于(<>或 !=)

  • 使用不等于,将进行全表扫描

3.4、应尽量避免在 where子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描

  • 避免部分条件放弃索引,进行全表扫描
-- 优化4 :
--- 查询所有
select * from t_user;
-- 0.031
select * from t_user where id = 15;
-- 1.282
select * from t_user where username = "NNH250Y9LN7JHA13G1T3";
-- or 操作 1.846
select * from t_user where id = 15 or username = "NNH250Y9LN7JHA13G1T3";

--- 优化方案:使用 union all 替换 or  -- 1.361
select * from t_user where id = 15
union all
select * from t_user where username = "NNH250Y9LN7JHA13G1T3";

3.5、避免使用 select *

-- 优化5:避免使用 select *
--- id 查询
select * from t_user where id = 6000000;
--- 通过username查询 -- 1.416
select * from t_user where username = "C2Q0Q9INJDTDZ9TLN8JG";
--- 字段替换*  -- 1.309
select id,username,age,birthday from t_user where username = "C2Q0Q9INJDTDZ9TLN8JG";

3.6、尽量不用 like 语句,如果必须使用,优先使用"xx%"

-- 优化6:尽量不用like语句,如果必须使用,优先使用"xx%"
----  "%xx" 和 "%xx%" 不能使用索引
-- 1) 给 t_user username 添加索引
create index user_username_index on t_user(username);
-- 2) 使用 %xx% 进行模糊查询 -- 3.825
select * from t_user where username like "%C2Q0Q9IN%";
-- 3) 使用 xx% 进行模糊查询 -- 0.053
select * from t_user where username like "C2Q0Q9IN%";

3.7、避免在 where 子句中对字段进行表达式

-- 优化7:避免在 where 子句中对字段进行表达式
-- 所有 60 岁人员
select * from t_user where age = 60;
-- 对 age 进行计算
select * from t_user where age / 2 = 30;

3.8、避免在 where 子句使用函数

-- 优化8:避免where子句使用函数
--- 使用substr(开始位置,长度)
select substr(username,2,3) from t_user where id = 6000000;
select length("C2Q0Q9IN") from dual;
--- 判断前缀 -- 2.959
select * from t_user where substr(username, 1, 8) = "C2Q0Q9IN";
select * from t_user where substr(username, 1, length("C2Q0Q9IN")) = "C2Q0Q9IN";
-- 使用like 替换函数
select * from t_user where username like "C2Q0Q9IN%";

3.9、复合索引中,必须使用索引中第一个字段,且尽量字段顺序与索引顺序一致

-- 优化10:复合索引中,必须使用索引中第一个字段,且尽量字段顺序与索引顺序一致
-- 1)创建表(复合主键)
create table t_user2(
  firstname varchar2(20),
  secondname varchar2(20),
  age int,
  constraint user2_fk primary key (firstname,secondname)
);
-- 2)初始化 100w条数据
-- 语法: insert into 表名 select语句;
-- 2.1) 查询结果
select dbms_random.string("x",20) as firstname,
    dbms_random.string("x",20) as secondname,
    trunc(dbms_random.value(0,100) ) as age
from dual
connect by level <= 10;

-- 2.2) insert 100w
insert into t_user2(firstname,secondname,age)
select dbms_random.string("x",20) as firstname,
    dbms_random.string("x",20) as secondname,
    trunc(dbms_random.value(0,100) ) as age
from dual
connect by level <= 1000000;
-- 提交事务
commit;

-- 3)测试:查询第一字段、查询第二字段、查询第一 + 二字段
--- 3.1) 查询id 700000
select * from (
  select rownum r ,t_user2.* from t_user2
) t where t.r = 700000;
--- 3.2) 查询firstname -- 0.023 (速度快一些)
select * from t_user2 where firstname = "PR9AVGGXEJL4SJ8OCZWF";
--- 3.3) 查询secondname  -- 0.068 (相对而言慢一些)
select * from t_user2 where secondname = "93A0SPRCXQBZ45V1S59A";
--- 3.4) 查询firstname + secondname (字段顺序无关,建议顺序一致)
select * from t_user2 where firstname = "PR9AVGGXEJL4SJ8OCZWF" and secondname = "93A0SPRCXQBZ45V1S59A";
select * from t_user2 where secondname = "93A0SPRCXQBZ45V1S59A" and firstname = "PR9AVGGXEJL4SJ8OCZWF";

3.10、构建空表

-- 优化11:创建空表结构
-- 1) select into 不能生成空表结构
-- select 字段1,字段2,... into 新表名 from 查询表 where 1=0;
-- 1.1) select into 在Oracle无法创建表结构
-- select id,birthday,age,username into t_user3 from t_user where id < 10;

-- 2) 创建表结构,但没有数据
create table t_user3
as
select 
  dbms_random.string("x",20) as firstname, dbms_random.string("x",20) as secondname
from dual where 1 = 0;

3.11、根据实际情况创建索引,而不是越多越好。

  • 添加索引提供查询速度,同时降低了insert 和 update效率。

3.12、使用 exists 和 in 对比

  • 两个表中数据一致的情况下,没有差异
  • 如果两个表中一个数据较小A,一个是数据较多B,则子查询B用exists,子查询A用in
--如果部门名称中含有字母A,则查询所有员工信息(使用exists)

-- 1) 查询 部门名称中含有字母A
select * from dept where dname like "%A%";

-- 2) 使用exists
select * from emp where exists ( select * from dept where dname like "%A%" and dept.deptno = emp.deptno )

-- 3) in
select * from emp where emp.deptno in ( select dept.deptno from dept where dname like "%A%" )

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Oracle学习(八) --- SQL优化

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Oracle学习(八) --- SQL优化

1、前置工具:执行计划 Explain Plan1.1、概念一条查询语句在 ORACLE 中的执行过程或访问路径的描述。即就是对一个查询任务,做出一份怎样去完成任务的详细方案。执行计划:用于记录SQL执行每一个细节。执行计划目的:通过分析SQL执行每一个细节,
Oracle学习(八) --- SQL优化
2019-07-03

MySQL学习笔记(18):SQL优化

本文更新于2019-08-18,使用MySQL 5.7,操作系统为Deepin 15.4。目录优化SQL语句的步骤通过SHOW STATUS了解SQL语句的执行情况定位执行效率低下的SQL语句通过EXPLAIN或DESC分析SQL的执行计划通过SHOW PRO
MySQL学习笔记(18):SQL优化
2016-01-24

Redis学习笔记(八) RDB持久化

Redis是内存数据库,它将自己的数据库状态存储在内存里面,所以如果不想办法将存储在内存中的数据库状态保存到磁盘,那么服务器 进程一旦退出,服务器中的数据库状态也会消失不见。为了解决这个问题,Redis提供了RDB持久化功能,这个功能可以将数据库状态保存到磁盘
Redis学习笔记(八) RDB持久化
2019-01-14

数据库学习之八:mysql 基础优化-索引管理

八、mysql 基础优化-索引管理1、课程大纲索引介绍索引管理2、执行计划获取及分析mysql数据库中索引的类型介绍BTREE:B+树索引 (主要)HASH:HASH索引FULLTEXT:全文索引RTREE:R树索引------索引管理:索引建立的在表的列上(
数据库学习之八:mysql 基础优化-索引管理
2016-09-20

Oracle(PLSQL)入门学习八(完结篇)

学习视频:https://www.bilibili.com/video/BV1tJ411r7EC?p=75游标cursor:用于存放多条数据的容器。需要开始open和关闭close。游标下移使用“fetch...into...”。declare cursor
Oracle(PLSQL)入门学习八(完结篇)
2022-04-06

如何用机器学习优化SQL拼接查询

使用机器学习优化SQL拼接查询可以通过以下步骤实现:数据准备:收集和准备用于训练的数据集,包括已有的SQL查询语句和其对应的性能数据,例如执行时间、资源消耗等。特征工程:为每个SQL查询语句提取特征,例如查询的长度、使用的表数量、使用的索引
如何用机器学习优化SQL拼接查询
2024-04-29

编程热搜

目录