从如何优化SQL入手,提高数据仓库的ETL效率

1        引言
数据仓库建设中的ETL(Extract, Transform, Load)是数据抽取、转换和装载到模型的过程,整个过程基本是通过控制用SQL语句编写的存储过程和函数的方式来实现对数据的直接操作,SQL语句的效率将直接影响到数据仓库后台的性能。

目前,国内的大中型企业基本都具有四年以上计算机信息系统应用经验,积累了大量可分析的业务数据,这些信息系统中的数据需要通过搭建数据仓库平台才能得到科学的分析,这也是近几年数据仓库系统建设成为IT领域热门话题的原因。

2        优化的思路分析

    数据仓库ETL过程的主要特点是:面对海量的数据进行抽取;分时段对大批量数据进行删除、更新和插入操作;面对异常的数据进行规则化的清洗;大量的分析模型重算工作;有特定的过程处理时间规律性,一般整个ETL过程需要在每天的零点开始到6点之前完成。所以,针对ETL过程的优化主要是结合数据仓库自身的特点,抓住需要优化的主要方面,针对不同的情况从如何采用高效的SQL入手来进行。
        优化的实例分析

   目前数据仓库建设中的后台数据库大部分采用Oracle,以下的SQL采用Oracle的语法来说明,所有的测试在Oracle9i环境中通过,但其优化的方法和原理同样适合除Oracle之外的其他数据库。

3.1   索引的正确使用

在海量数据表中,基本每个表都有一个或多个的索引来保证高效的查询,在ETL过程中的索引需要遵循以下使用原则:

(1) 当插入的数据为数据表中的记录数量10%以上时, 首先需要删除该表的索引来提高数据的插入效率,当数据全部插入后再建立索引。

(2) 避免在索引列上使用函数或计算,在WHERE子句中,如果索引列是函数的一部分,优化器将不使用索引而使用全表扫描。举例:

低效: SELECT * ROM DEPT WHERE SAL * 12 > 25000;

高效: SELECT * FROM DEPT WHERE SAL > 25000/12;

(3) 避免在索引列上使用NOT和”!=” , 索引只能告诉什么存在于表中, 而不能告诉什么不存在于表中,当数据库遇到NOT和”!=”时,就会停止使用索引转而执行全表扫描。

(4) 索引列上用>=替代>

高效:   SELECT *    FROM EMP    WHERE DEPTNO >=4

低效:   SELECT *    FROM EMP    WHERE DEPTNO >3 

      两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录。

(5) 函数的列启用索引方法,如果一定要对使用函数的列启用索引,Oracle9i以上版本新的功能:基于函数的索引(Function-Based Index)是一个较好的方案,但该类型索引的缺点是只能针对某个函数来建立和使用该函数。
CREATE INDEX EMP_I ON EMP (UPPER( ENAME));         /*建立基于函数的索引*/

SELECT * FROM EMP WHERE UPPER(ENAME) = ‘BLACKSNAIL’; /*将使用索引*/

3.2 游标的正确使用

当在海量数据表中进行数据的删除、更新和插入操作时,用游标处理的效率是最慢的方式,但它在ETL过程中的使用又必不可少,而且使用有着及其重要的地位,所以游标的正确使用尤为重要。

对数据仓库维表的数据进行维护时,因为需要保证维表ID的一致性,所以采用游标的是数据维护完整性的最好方式。由于它的效率低,如果按照普通的方式将无法处理大数据量的维表数据维护(一般是指10万条记录以上的维表),以下是处理这种情况的有效方式:

(1) 在数据抽取的源表中使用时间戳,这样每天的维表数据维护只针对更新日期为最新时间的数据来进行,大大减少需要维护的数据记录数。

(2) 在INSERT和UPDATE维表时都加上一个条件来过滤维表中已经存在的记录,实例为:

INSERT INTO DIM_CUSTOMER SELECT * FROM ODS_CUSTOMER WHERE ODS_CUSTOMER.CODE  NOT EXISTS  (DIM_CUSTOMER.CODE)

        /* ODS_CUSTOMER为数据源表;DIM_CUSTOMER为维表*/
(3) 使用显式的游标(CURSORs) ,因为使用隐式的游标将会执行两次操作, 第一次检索记录,第二次检查TOO MANY ROWS 这个EXCEPTION,而显式游标不执行第二次操作。

3.3数据抽取和上载时的SQL优化

3.3.1 WHERE子句中的连接顺序

          ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其它WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾。

低效:SELECT * FROM EMP E  WHERE SAL > 50000  AND JOB = ‘MANAGER’ AND 25 < (SELECT COUNT(*) FROM EMP   WHERE MGR=E.EMPNO);

高效:SELECT * FROM EMP E WHERE 25 < (SELECT COUNT(*) FROM EMP              WHERE MGR=E.EMPNO) AND SAL > 50000 AND JOB = ‘MANAGER’;

3.3.2 删除全表时用TRUNCATE替代DELETE
当DELETE删除表中的记录时,有回滚段(rollback segments ) 用来存放可以被恢复的信息,而当运用TRUNCATE时,回滚段不再存放任何可被恢复的信息,所以执行时间也会很短。 同时需要注意TRUNCATE只在删除全表时适用,因为TRUNCATE是DDL而不是DML。

3.3.3 尽量多使用COMMIT

ETL中同一个过程的数据操作步骤很多,数据仓库采用的是数据抽取后分析模型重算的原理,所以对数据的COMMIT不像业务系统为保证数据的完整和一致性而需要某个操作过程全部完成才能进行,只要有可能就在程序中对每个DELETE、INSERT和UPDATE操作尽量多使用COMMIT, 这样系统性能会因为COMMIT所释放的资源而大大提高。

3.3.4 用EXISTS替代IN               

在许多基于基础表的查询中,为了满足一个条件往往需要对另一个表进行联接,例如在ETL过程写数据到模型时经常需要关联10个左右的维表,在这种情况下,使用EXISTS而不用IN将提高查询的效率。

3.3.5 用NOT EXISTS替代NOT IN

子查询中,NOT IN子句将执行一个内部的排序和合并,无论在哪种情况下,NOT IN都是最低效的,因为它对子查询中的表执行了一个全表遍历。用NOT EXISTS替代NOT IN将提高查询的效率。
3.3.6 优化GROUP BY

提高GROUP BY 语句的效率,可以通过将不需要的记录在GROUP BY 之前过滤掉。

低效: SELECT JOB , AVG(SAL)    FROM EMP    GROUP BY JOB    HAVING JOB = ‘PRESIDENT’    OR JOB = ‘MANAGER’

高效: SELECT JOB , AVG(SAL)    FROM EMP    WHERE JOB = ‘PRESIDENT’    OR JOB = ‘MANAGER’    GROUP BY JOB

3.3.7 有条件的使用UNION-ALL 替换UNION

ETL过程针对多表连接操作的情况很多,有条件的使用UNION-ALL 替换UNION的前提是:所连接的各个表中无主关键字相同的记录,因为UNION ALL 将重复输出两个结果集合中相同记录。

当SQL语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并,然后在输出最终结果前进行排序。如果用UNION ALL替代UNION, 这样排序就不是必要了,效率就会因此得到提高3-5倍

3.3.8 分离表和索引

总是将你的表和索引建立在不同的表空间内,决不要将不属于ORACLE内部系统的对象存放到SYSTEM表空间里。 同时确保数据表空间和索引表空间置与不同的硬盘控制卡控制的硬盘上。

4        结论

   随着数据仓库系统应用需求的急剧增长,参与和关注这方面的人员将越来越多。文章中主要依据本人4年多的数据仓库实施经验,同时结合ETL的过程原理和数据仓库建设的方法论,归纳总结了以上优化的方案,愿此文能在同行中起到抛砖引玉的作用。

出处:http://www.cnblogs.com/invinboy/archive/2008/01/10/1032824.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290206.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C和指针之动态内存分配(读取范围在1和标准输入读取的size之前每个数据出现的次数)

1、问题 读取范围在1和标准输入读取的size之前每个数据出现的次数 2、代码实现 #include <stdio.h> #include <stdlib.h> #include <string.h>//读取范围在1和标准输入读取的size之前每个数据出现的次数 int *count(int size) {if (size <= 0)return NUL…

测试眉形的有哪个软件_这五款自动化软件测试工具,你最喜欢用哪个?

对测试自动化的依赖性增加导致大量自动化软件测试工具的出现&#xff0c;使得很难确定哪些是最好的。为了帮助您完成自动化工作&#xff0c;我们根据自己和他人的经验创建了五大最佳自动化软件测试工具列表。1. SeleniumSelenium可以说是web开发人员和测试人员中最受欢迎的自动…

本科 8年经验,20k的Offer,接还是不接?

伴随着疫情的此起彼伏&#xff0c;今年的金三银四跳槽季比往年要低沉很多&#xff0c;近日一条朋友圈火遍社区&#xff0c;“坐标一线城市&#xff0c;本科毕业&#xff0c;8年经验&#xff0c;15天仅5场面试&#xff0c;最终接了20k的offer&#xff0c;今年真难&#xff01;”…

CAD中批量打印

同事在网上找各种软件来实现CAD图的批量打印&#xff0c;总是问题多多。于是&#xff0c;我想到一个更方便的解决方法&#xff0c;即只要我将一个打印出来&#xff0c;然后就可以用批量处理来实现。 1.在CAD中输入plot命令&#xff08;或快捷键CtrlP&#xff09;&#xff0c;即…

java里面的文件上传与下载

java里面的文件上传与下载 文件的上传与下载主要用到两种方法&#xff1a;1、方法一&#xff1a;commons-fileupload.jar commons-io.jarapache的commons-fileupload实现文件上传&#xff0c;下载 【upload】package com.handson.bbs.servlet; import java.io.File;import java…

Photoshop脚本 使用ExtendScript编写Ps脚本

源自&#xff1a;http://coolketang.com/tutorials/menu1lesson3.php本节课程将演示如何使用ExtendScript编写脚本&#xff0c;它是由Adobe公司开发的一款脚本语言工具包。以后的所有课程也将使用这款工具编写脚本。您可以在开始菜单(Windows电脑)或Application目录(Mac电脑)上…

C和指针之动态内存分配之(编写calloc函数,函数内部使用malloc函数来获取内存)

1、问题 编写calloc函数,函数内部使用malloc函数来获取内存 2、代码实现 #include <stdio.h> #include <stdlib.h>void *my_calloc(size_t nums, size_t element_size) {int i, all_size;all_size = nums * element_size;char *p = NULL;p = malloc…

CentOS6.4安装Vbox增强包

2019独角兽企业重金招聘Python工程师标准>>> 1、升级#yum update2、安装gcc #yum install gcc安装编译系统3、安装外置核心模块#yum install kernel-devel4、添加一个连接 ln -s /usr/src/kernels/2.6.18- 164.15.1.el5-i686(内核版本) /usr/src/linux 5、重启以…

eltree ref什么时候有_Vue3响应式系统源码解析-Ref篇

文章转载自&#xff1a;https://zhuanlan.zhihu.com/p/85978064我们阅读源码的原因是什么&#xff1f;无非是1&#xff1a;学习&#xff1b;2&#xff1a;更好的使用这个库。如果只是想大致的了解下原理&#xff0c;倒不必花时间阅读源码&#xff0c;几句话&#xff0c;几张图就…

揭秘.NET Core剪裁器背后的技术

十天前&#xff0c;我发布了对.NET Core程序进行瘦身的开源软件Zack.DotNetTrimmer&#xff0c;与.NET Core内置的剪裁器相比&#xff0c;Zack.DotNetTrimmer不仅对程序的剪裁效果更好&#xff0c;而且还支持WPF、WinForm程序。很多朋友对于这个开源项目的原理很感兴趣&#xf…

C和指针之动态内存分配之编程练习3

1、问题 编写一个函数,从标准输入读取一个字符串,把字符串复制到动态内存分配的内存中,并返回该字符串的拷贝,这个函数不应该对读入字符串的长度作任何限制! 2、代码实现 #include <stdio.h> #include <stdlib.h>#define OFFSET 5char *my_strcpy…

freetds 移植

移植freetds主要是为了能够在linux下&#xff0c;使用C语言访问微软的sqlserver数据库。 参考连接 http://blog.csdn.net/neighbor1000/article/details/8824084 http://blog.csdn.net/lovehere33/article/details/41118405 在ubuntu上安装 从官网下载最新的稳定版本。 http://…

优秀程序员的 18 大法则【转载】

DRY原则 不要重复&#xff08;Don’t repeat yourself&#xff09;——程序设计中一个最根本的原则就是要避免重复。许多编程结构&#xff08;比如循环、函数、类等&#xff09;的存在就是为了避免重复。一旦重复&#xff08;例如&#xff0c;一个长表达式&#xff0c;一系列语…

java邮件系统(java邮件收发系统源代码和下载地址)

2019独角兽企业重金招聘Python工程师标准>>> 本软件包包括源文件和可执行的jar文件 项目下载地址&#xff1a; 下载 1. 运行方式 A可以直接运行jar文件&#xff08;电脑上必须安装jdk1.6而且关联jar文件&#xff09; B可以用eclipse导入源文件然后运行 2功能简介…

两对光纤收发器用网线连接_为什么现在的人不喜欢用网线,反而更爱用光纤来传输呢?涨知识了...

随着通信技术的不断发展&#xff0c;信号传输介质已从原来的同轴电缆逐渐变为光纤。光纤传输完全满足大容量数据通信正确&#xff0c;可靠&#xff0c;高速传输和处理的要求&#xff0c;已成为世界上主要的通信方式。本文主要详细介绍光纤传输的基本知识&#xff0c;希望对您有…

openGauss学习笔记-170 openGauss 数据库运维-备份与恢复-导入数据-更新表中数据-使用合并方式更新和插入数据

文章目录 openGauss学习笔记-170 openGauss 数据库运维-备份与恢复-导入数据-更新表中数据-使用合并方式更新和插入数据170.1 前提条件170.2 操作步骤 openGauss学习笔记-170 openGauss 数据库运维-备份与恢复-导入数据-更新表中数据-使用合并方式更新和插入数据 在用户需要将…

C和指针之动态内存分配之编程练习4

1、问题 4.编写一个程序&#xff0c;按照下图中的样子创建数据结构&#xff0c;最后三个对象都是动态分配的结构。第一个对象则可能是一个静态的指向结构的指针。你不必使这个程序过于全面--我们将在下一章讨论这个结构。 2、代码实现 #include <stdio.h> #include <s…

.NET 6 攻略大全(四)

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;15分钟)接上篇内容&#xff0c;本篇文章将介绍&#xff1a;DependentHandle 现已公开、RyuJIT、即用型代码/Crossgen 2、.NET 诊断&#xff1a;EventPipe、SDK 的相关攻略。 DependentHandle 现已公开该 DependentHan…

[原创]同一个Tomcat,配置多个context、多个Host

需求前提&#xff1a; 系统结束后&#xff0c;需要部署到服务器上。 目前只可以映射到一个固定IP的非80端口。 而server端和web端都要暴露到外网。 所以配置两个context&#xff0c;使得client应用不需要添加服务名&#xff0c;直接使用IP即可访问&#xff1b;server可以通过ht…

[No000022]他们说:得诺贝尔奖到底有多难?

转载于:https://www.cnblogs.com/Chary/p/No000022.html