IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 索引和sql优化 -> 正文阅读

[大数据]索引和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)
? ? )
);

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

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

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 00:59:31  更:2022-09-30 01:01:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年4日历 -2025/4/28 23:11:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码