索引和sql优化

oracle实例:


SGA,系统全局区,整个数据库只有一个
    数据缓冲区 :  缓存数据
    共享池:  存放执行过的sql
    重做日志缓冲区: 用于支持回滚
    
PGA ,程序全局区,每个用户连接数据库之后,都会拥有一个独立的PGA,多个PGA相互之间是隔离的; 

oracle数据库:
硬盘上的地址:D:\app\Administrator\oradata\orcl
物理上划分:
    控制文件:后缀为ctl的文件,用于存放用户信息,登录信息,权限信息;
    日志文件:后缀为log的文件,用户数据库的恢复
    数据文件:后缀为dbf的文件,用于存放表空间,表,数据
逻辑上划分:
    所有的表和数据,都是存放在表空间里面的;
    新建一张表的时候,默认都是存放在USERS表空间中
    
*************************************************************************************************
索引
用于提高查询性能;
前提:有大量数据的情况下

索引的分类:
唯一索引和非唯一索引
单列索引和组合索引
B树索引:通常保存的数据是没有重复的
反向键索引:通常配合B树一起使用
位图索引 : 通常用于有大量重复数据的


关于主键,在为表设定主键的时候,系统默认会为主键创建一个唯一索引;
创建主键约束和唯一约束的时候,都会自动创建索引;

create table student(
    stuid number(8) primary key,
    stu_no number(20),
    sex   varchar2(50),
    card_no varchar2(30)
);


B树索引:
create index stunoIndex on student(stu_no);  --where stu_no-5>0
反向键索引
create index stunoIndex on student(stu_no) reverse;
位图索引:
create bitmap index sexIndex on student(sex);
组合索引
create index xxxindex on student(stu_no,sex,card_no);
当组合索引的第一个字段用于条件时,组合索引才会生效;
select 字段,字段 from student where stu_no=1 and sex='男' ;
函数索引
create index yyyindex on student(avg(sal));
如果索引字段,在查询中,非函数索引的字段不会使用索引;
索引字段如果用于了计算,索引也会失效;


当索引失效以后,如果想要强制使用索引:
hint: 
本质上就是一段注释,对于查询结果没有任何影响
参考:https://www.cnblogs.com/emilyyoucan/p/7844795.html
    /*+  */ :   +必须跟在*后面,而且中间连空格都不能有
    hint内容,必须跟在select,update,insert,delete关键字后面
    index : 表示建议使用索引,小括号里面先写表名(如果表名有别名,这里要写别名)
select /*+ index(emp 索引的名字) */ empno,ename,job,sal from emp where empno>2000;


*****************************************************************************************************
sql优化
--WHERE ENAME='SMITH'
WHERE aziduan='xxx' and b='ccc' and c='ddd'

1.    sql语句全部使用大写
2.    不要使用*来查询
3.    当需要写多个条件的时候,过滤掉数据最多的条件,应该放在sql的最右端
4.    =,<=与<,>相比较,>=,<=的效率会更高
5.    between...and...的效率比>,<的写法效率要高
6.    尽量避免使用in,any,distinct..这些关键字
7.    尽量避免使用否定性的条件,包括not等关键字
8.    尽量避免使用函数
9.    尽量减少使用联表查询,子查询等

10.当数据量比较高的时候,使用索引来提高查询的效率

11.尽量避免对索引列做运算

12.当一张表中列太多,或者数据量太大时,可以通过表的横向,纵向切割来提高效率

*******************************************************************************************
数据库设计:

三大范式:
参考:https://www.cnblogs.com/sxkio/p/15955665.html
第一范式:列不可再分
第二范式:加主键
第三范式:非主键字段,如果与当前主键无直接关联,而是与表中其他某个字段有关联,此时应该把这些字段单独分离成新的表

---------------------------------------------------------------------------------------------------

oracle的远程访问
开始菜单->net manager
实例选项和监听选项中,都有主机名和端口号
端口号默认为1521;
主机名默认为localhost(允许的值有四个:localhost,127.0.0.1,ip地址,计算机名)

也可以在路径下:D:\app\Administrator\product\11.2.0\dbhome_1\NETWORK\ADMIN
记事本打开listener.ora和tnsnames.ora两个文件,修改其中的主机名

要想允许远程访问,需要把上述的主机名修改为ip地址或者是计算机名;修改之后,需要重新启动监听服务和实例服务;

oracle服务端准备ok之后,客户端开始访问:
客户端连接:
第一种方式:直接在database下,写IP地址/orcl方式,加上账号密码,完成连接;
第二种方式:建立远程连接服务
    a.开始菜单->net manager窗口:
        左上角,绿色的加号,创建远程服务;
    b.开始菜单->oracle安装目录->配置和移植工具->net configuration assistent
        本地网络服务名配置->...->下一步到完成;

**************************************************************************************************
oracle的优化:
1.sql优化
2.索引
3.分区

oracle服务端是如何执行一条sql的?
1.语句解析
    a.查询告诉缓存:检查缓存中,是否存在执行计划
    b.语句的合法性检查:检查sql语句的语法知否合规
    c.语义检查:检查表名,字段名是否正确
    d.获取对象解析锁:给表加锁,保证数据一致性;
    e.权限检查:检查是否拥有权限
    f.确定最优执行计划
2.语句执行
3.结果收集

************************************************************************************
执行计划
如何查看执行计划:
explain plan for sql语句;

select * from table(dbms_xplan.display);

operation中,原则上来说,缩进越多,越先执行(大部分时候,都是从下往上执行)

oracle在执行sql语句,选择执行计划的时候,有两种优化方式:
1.RBO:基于规则的优化方式
2.CBO: 基于代价的优化方式


全表扫描(table access full)
举例:查询所有的员工信息
explain plan for select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp;
select * from table(dbms_xplan.display);

通过ROWID的表存取(TABLE ACCESS BY USER ROWID)
explain plan for select * from emp where rowid='AAAR3sAAEAAAACXAAA';
select * from table(dbms_xplan.display);

索引扫描
索引扫描又分几种方式:
a.索引唯一扫描(INDEX UNIQUE SCAN)
explain plan for select empno,ename,job,sal from emp where empno=7369;
select * from table(dbms_xplan.display);

b.索引范围扫描(INDEX RANGE SCAN)
explain plan for select empno,ename,job,sal from emp where empno>2000;
select * from table(dbms_xplan.display);

empno本身是创建了索引的(PK_EMP),但是在查询中,把empno放到了函数里面,所以,此时查询的时候,索引会失效
explain plan for select empno,ename,job,sal from emp where substr(empno,1,4)>2000;
为了让索引生效,这里添加hint注释,再次运行的时候,这里的索引再次生效,不过这里已经是索引全扫描了
explain plan for select /*+ index(emp pk_emp)*/ empno,ename,job,sal from emp where substr(empno,1,4)>2000;

c.索引全扫描(INDEX FULL SCAN)

********************************************************************************************************************
上述举例都是单表的情况,如果是联表呢?


1.排序--合并连接(sort join--->merge join)
对于非等值连接,效率比较高
如果关联字段有索引,性能也会更好
explain plan for select e.empno,e.ename,e.job,e.sal,d.deptno,d.dname from emp e,dept d where e.deptno=d.deptno
select * from table(dbms_xplan.display);

2.嵌套循环(NESTED LOOPS)
适用于小表关联大表

需要先指明驱动表和被驱动表,一般以小表(数据量比较少的表)作为驱动表,以大表(数据量比较大的表)作为被驱动表;
驱动表,也叫外侧表;被驱动表,也叫内侧表;
先去查询驱动表中的数据,然后通过驱动表中每一行数据,去被驱动表中查找;

这里把d(dept)表作为驱动表
explain plan for select /*+ leading(d) use_nl(e) */ e.empno,e.ename,e.job,e.sal,d.deptno,d.dname from emp e,dept d where e.deptno=d.deptno
select * from table(dbms_xplan.display);

3.哈希连接(HASH JOIN OUTER)
用于等值连接
大表关联小表,效率更好;
大表关联大表,也能提高效率;
explain plan for select e.empno,e.ename,e.job,e.sal,d.deptno,d.dname from emp e left join dept d on e.deptno=d.deptno;
select * from table(dbms_xplan.display);

4.笛卡尔积

-----------------------------------------------------------------------------------------------------------------------------

表分区
分区必须在创建表的时候就分区;
表一旦创建完成,就不能进行分区了;

分区的方式:
1.范围分区
2.列表分区
3.散列分区
4.组合分区


1.范围分区
按照工资的范围,进行分区:
0-2000,第一分区
2001-4000,第二分区
4000以上,第三分区
create table emp(
    empno  number(8) primary key,
    ename  varchar2(50),
    job    varchar2(50),
    sal    number(8)
)
partition by range(sal)(
    partition firstpart values less than (2000),
    partition secondpart values less than (4000),
    partition threepart values less than (maxvalue)
);

查看表是否存在
select * from emp;

往表中添加数据
insert into emp values(1001,'zhangsan','助理',1500);
commit;
有了分区之后,增,删,改,查操作,与未分区之前,完全一致;

查询指定分区下的数据
select * from emp partition(firstpart);
此时可以查看到数据,确实存入了第一个分区

insert into emp values(1002,'lisi','程序员',3500);
commit;

数据存入了第二分区
select * from emp partition(firstpart);--没有1002的数据
select * from emp partition(secondpart);--有了1002的数据

insert into emp(empno,ename,job) values(1003,'wangwu','销售员');
commit;

select * from emp partition(firstpart);
select * from emp partition(secondpart);
当sal为空时,数据也分到了第三个分区中
select * from emp partition(threepart);


2.列表分区
创建用户表,表中有一个字段:岗位;
岗位的可能值有:程序员,销售员,助理,经理
存入数据的时候,按照岗位来进行分区

create table t_users(
    userid    number(8) primary key,
    username  varchar2(50),
    job       varchar2(50)
)
partition by list(job)
(
    partition pro_part values ('程序员'),
    partition sale_part values ('销售员'),
    partition help_part values ('助理'),
    partition manager_part values ('经理'),
    partition def_part values (default)
);

先检查表是否存在
select * from t_users;

添加数据
insert into t_users values(1001,'zhangsan','销售员');
commit;

查询指定分区下的数据:
select * from t_users partition(sale_part);

如果job为空呢?
insert into t_users(userid,username) values(1002,'lisi');
commit;

没有为空单独分区的时候,job为空的数据,会存入默认分区中
select * from t_users partition(def_part);

3.散列分区
create table dept(
    dno   number(8) primary key,
    dname varchar2(50)
)
partition by hash(dno)
(
    partition fp,
    partition sp,
    partition tp
);

insert into dept values(10,'销售部');
insert into dept values(20,'开发部');
insert into dept values(30,'人事部');

select * from dept partition(tp);

4.组合分区
创建订单表,有订单创建时间,订单状态
先按照订单创建时间,做父分区,范围分区;
再按照订单状态,做子分区
订单状态:0-未支付,1-已支付,2-已到货

create table t_order(
    orderid   number(8) primary key,
    userid    number(8),
    shopid    number(8),
    total_money  number(8,2),
    create_time date,
    order_status  varchar2(10)
)
partition by range(create_time)
subpartition by list(order_status)
(
    partition p1 values less than (to_date('2022-03-01','yyyy-mm-dd'))
    (
        subpartition p1_sub1 values ('0'),
        subpartition p1_sub2 values ('1'),
        subpartition p1_sub3 values ('2'),
        subpartition p1_sub4 values (default)
    ),
    partition p2 values less than (to_date('2022-06-01','yyyy-mm-dd'))
    (
        subpartition p2_sub1 values ('0'),
        subpartition p2_sub2 values ('1'),
        subpartition p2_sub3 values ('2'),
        subpartition p2_sub4 values (default)
    ),
    partition p3 values less than (maxvalue)
    (
        subpartition p3_sub1 values ('0'),
        subpartition p3_sub2 values ('1'),
        subpartition p3_sub3 values ('2'),
        subpartition p3_sub4 values (default)
    )
);

对于分区:
在现有分区的基础上,可以新增一个分区,也可以删除一个现有的分区;
如果现在只有一个分区了,那么这个分区不允许被删除;

可以针对表的全局(所有分区)创建索引,此时的索引针对所有分区都有效;
也可以只针对某一个分区来创建索引,此时索引只针对这一个分区有效,其他分区里面,该所以无效;这种情况下,如果删除该分区下的索引,其他分区不受影响;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
SQL优化中使用索引是一种常见的方法。索引可以加快数据库的查询速度和性能。下面是一些使用索引进行SQL优化的常见技巧: 1. 选择合适的列进行索引:通常情况下,需要在经常用于查询条件的列上创建索引。选择经常用于筛选、排序或连接操作的列可以提高查询性能。 2. 避免过多的索引:虽然索引可以提高查询速度,但过多的索引会增加数据库的维护成本并降低写入性能。只创建必要的索引,避免不必要的列进行索引。 3. 多列索引优化:对于经常一起使用的列,可以创建多列索引以提高查询性能。多列索引可以更好地满足复杂查询条件。 4. 聚簇索引优化:聚簇索引是一种特殊的索引类型,它可以将数据物理上组织在一起。通过合理地选择聚簇索引,可以减少磁盘IO和提高查询性能。 5. 使用覆盖索引:覆盖索引是指索引包含了查询所需的所有列。通过使用覆盖索引,可以减少数据库的访问次数,从而提高查询性能。 6. 定期更新统计信息:统计信息用于查询优化器选择合适的索引和执行计划。定期更新统计信息可以确保查询优化器能够做出更准确的选择,提高查询性能。 7. 避免索引过度优化:有时候过度使用索引可能会导致性能下降。当数据量较小或查询频率低时,可以考虑不使用索引或者使用覆盖索引来避免过度优化带来的性能问题。 需要注意的是,索引的创建和维护会增加额外的开销,因此在使用索引进行优化时需要综合考虑查询频率、数据量和维护成本等因素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好好羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值