版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
SQL编写规范和优化
SQL编写规范和优化SQL编写规范--1原则定义
1、要求代码行清晰、整齐,具有一定的可观赏性;
2、代码编写要充分考虑执行速度最优的原则;
3、代码行整体层次分明、结构化强;
4、代码中应有必要的注释以增强代码的可读性;
5、规范要求非强制性约束代码开发人员的代码编写行为,在实际应用中在不违反常规要求的前提下允许存在可理解的偏差。SQL编写规范--1原则定义SQL编写规范--2大小写规则
1、所有的SQL语句中的保留字均采用全部大写,不要使用缩写;表别名也要大写;如ALLASCASECREATEDATABASEDELETEFROMININSERTJOINLEFTNONOTNULLOUTSELECTTABLETITLEUPDATEVIEWWHERE等。
2、表名、视图名、宏和存储过程名:全部小写;SQL编写规范--2大小写规则SQL编写规范--2大小写规则
3、字段名:每个单词的首字母大写,其余部分小写,如party_id,loc_id,prod_inst_id,Acct_Id,Type_Id等;使用如下语句获得字段列表:SQL编写规范--2大小写规则SQL编写规范--3缩进和换行
整个的SQL语句最好按照子句进行分行编写,SELECT/FROM/WHERE/UPDATE/INSERT等每个关键字都要另起一行。如:SQL编写规范--3缩进和换行SQL编写规范--3缩进和换行SQL编写规范--3缩进和换行SQL编写规范--3缩进和换行
1、同一级别的子句间要对齐
2、逗号放在每行的开头
3、分号放在SQL语句的最后,单独占一行
4、每行宽度不超过120字符(每个字符为8个点阵宽),超过行宽的代码可折行与上行对齐编排;
5、每个字段后面使用字段标题作为注释
6、使用给出的语句获得字段列表和字段标题(借助UltraEdit列模式快速编辑)SQL编写规范--3缩进和换行SQL编写规范--3缩进和换行下面的编写方式不是好的形式:在所有需要缩进的地方,每次缩进4格;在以下情况下需要缩进:
1、不同层次的SQL语句之间
2、SELECTINSERT等关键字之后的字段列表和关键字之间SQL编写规范--3缩进和换行SQL编写规范--4别名
SQL语句别名的命名,分层命名,从第一层次至第四层次,分别用P、S、U、D(都是大写字母)表示,取意为Part,Segment,Unit,Detail。对于同一层次的多个子句,在字母后加1、2、3、4……区分。SQL编写规范--4别名SQL编写规范--4别名
如下图所示:SQL编写规范--4别名SQL编写规范--5运算符前后间隔要求算术运算符、逻辑运算符的前后至少要保留一个空格,如下图所示:SQL编写规范--5运算符前后间隔要求SQL编写规范--6变量引用
1、在SQL语句中引用变量时,要在变量名两端加花括号
2、对日期变量的引用要在单引号内,如'${MYDATE}'SQL编写规范--6变量引用SQL编写规范--7注释针对复杂的SQL语句,请尽量增加相应的注释说明,以便自己和其它同事事后可以比较容易的读懂和修改。注释中应包含以下内容:
1、编写人/编写日期
2、修改人/修改日期
3、该脚本的编写目的与主要内容
4、如果有特殊处理、特别的技巧等内容,一定要在注释中详细说明SQL编写规范--7注释SQL编写规范--7注释
5、每一段SQL的前面必须要有注释,重点说明该SQL的技术含义和应用含义、选择理由。技术含义指这段SQL在技术上这么写的原因、好处,应用含义指这段SQL从应用的角度将,是为了达到一个什么样的目的。如果有可能,还需要说明为什么这么选择,而不选择别的方式的理由。如果发现了不足,还可记录不足的原因和建议的解决办法等。SQL编写规范--7注释SQL编写规范--8连接的使用对于内连接和外连接的使用,要求该使用外连接的地方都已经使用了外连接,不需要外连接的地方一定不使用外连接。表中的字段若是从其它表引用的,要确保该字段在被引用的表中存在。SQL编写规范--8连接的使用SQL编写规范--8连接的使用要求所有的连接都写成JOIN的形式,如:SQL编写规范--8连接的使用SQL编写规范--8连接的使用而不要写成:SQL编写规范--8连接的使用SQL编写规范--8连接的使用另外,为了保证多表连接的连接条件穿透性,要求在多表连接的SQL书写时将连接条件有机的闭环起来,尤其是多表PI相同,并用PI连接时。SQL编写规范--8连接的使用SQL编写规范--8连接的使用
例如:SQL编写规范--8连接的使用SQL编写规范--8连接的使用即连接条件如下所示:SQL编写规范--8连接的使用SQL优化(teradata)SQL脚本优化原则
要优化脚本,在深刻理解业务逻辑的基础上,一个重要的方式是一段一段的查看SQL的执行计划,然后针对执行计划中不合理、不优化的地方对SQL进行优化编写,这项工作需要实践经验,经常看执行计划会有所帮助。SQL优化(teradata)SQL脚本优化原则SQL优化(teradata)SQL脚本优化原则表级优化可以参照以下以下优化原则:
(1)如果过滤性不很强,又不需要重分布,对大表尽可能不要只做一下过滤就进一次SPOOL,最好是直接与别的表JOIN,边JOIN边过滤了;
(2)如果过滤性非常强,可以只做一下过滤就进一次SPOOL;SQL优化(teradata)SQL脚本优化原则SQL优化(teradata)SQL脚本优化原则
(3)SPOOL空间尽量小原则,即尽可能使中间过程中的SPOOL空间小一些,这样可以减小I/O以及继续关联的代价;在此原则下可以引申出下面几个具体原则:
(3.1)在几个表大小差不多时,过滤性条件较强的先JOIN;
(3.2)在大/大/小三个表内联时,避免先把两个大表JOIN,除非过滤条件非常强;
(3.3)在大/小/小三个表内联时,尽量先把两个小表JOIN;
(3.4)有时将看似没必要的过滤条件加上,在关联表较多时可能有效的减小SPOOL;如表A、B、C、D的关联字段均为k,即A.k=B.kANDA.k=C.kANDA.k=D.k,而同时还有条件substr(A.k,1,2)='01',有时加上substr(B.k,1,2)='01'、substr(C.k,1,2)='01'、substr(D.k,1,2)='01‘会有好处;SQL优化(teradata)SQL脚本优化原则SQL优化(teradata)SQL脚本优化原则
(4)尽量避免大表重分布;
(5)当大表与很小的表(记录数量级在5位数以内)JOIN时,尽量让小表Duplicate;
(6)如果必须有重分布时,尽量使之靠后;
(7)尽量减少较大的中间过程中的SPOOL空间重分布的次数;SQL优化(teradata)SQL脚本优化原则SQL优化(teradata)SQL脚本优化原则
(8)遇到productjoin时要小心一些;
(9)尽量减少对大表的扫描次数;
(10)在拆SQL时也应注意,合起来虽然可能大些,但只扫描一次大表,而拆成多句后就要多次扫描大表,可能效率反降;SQL优化(teradata)SQL脚本优化原则SQL优化(oracle)基于索引的SQL语句优化数据库的优化方法有很多种,在应用层来说,主要是基于索引的优化。难就难在如何判断哪些索引是必要的,哪些又是不必要的。判断的最终标准是看这些索引是否对我们的数据库性能有所帮助。具体到方法上,就必须熟悉数据库应用程序中的所有SQL语句,从中统计出常用的可能对性能有影响的部分SQL,分析、归纳出作为Where条件子句的字段及其组合方式;在这一基础上可以初步判断出哪些表的哪些字段应该建立索引。SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化其次,必须熟悉应用程序。必须了解哪些表是数据操作频繁的表;哪些表经常与其他表进行连接;哪些表中的数据量可能很大;对于数据量大的表,其中各个字段的数据分布情况如何;等等。对于满足以上条件的这些表,必须重点关注,因为在这些表上的索引,将对SQL语句的性能产生举足轻重的影响SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化建立索引常用的规则如下:
1、表的主键、外键必须有索引;
2、数据量超过300的表应该有索引;
3、经常与其他表进行连接的表,在连接字段上应该建立索引;
4、经常出现在Where子句中的字段,特别是大表的字段,应该建立索引;
5、索引应该建在选择性高的字段上;
SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化
6、索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;
7、复合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替:
A、正确选择复合索引中的主列字段,一般是选择性较好的字段;
B、复合索引的几个字段是否经常同时以AND方式出现在Where子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引;SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化
C、如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引;
D、如果复合索引所包含的字段超过3个,那么仔细考虑其必要性,考虑减少复合的字段;
E、如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引;SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化
8、频繁进行数据操作的表,不要建立太多的索引;
9、删除无用的索引,避免对执行计划造成负面影响;以上是一些普遍的建立索引时的判断依据。一言以蔽之,索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。
SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化太多的索引与不充分、不正确的索引对性能都毫无益处:在表上建立的每个索引都会增加存储开销,索引对于插入、删除、更新操作也会增加处理上的开销。另外,过多的复合索引,在有单字段索引的情况下,一般都是没有存在价值的;相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负面影响更大。SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)避免对列的操作任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等式的右边,甚至去掉函数。例1:下列SQL条件语句中的列都建有恰当的索引,但30万行数据情况下执行速度却非常慢:
select*fromrecordwheresubstrb(CardNo,1,4)='5378'(13秒)select*fromrecordwhereamount/30<1000(11秒)
select*fromrecordwhereto_char(ActionTime,'yyyymmdd')='19991201'(10秒)
SQL优化(oracle)避免对列的操作SQL优化(oracle)避免对列的操作由于where子句中对列的任何操作结果都是在SQL运行时逐行计算得到的,因此它不得不进行表扫描,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表扫描,因此将SQL重写如下:
select*fromrecordwhereCardNolike'5378%'(<1秒)
select*fromrecordwhereamount<1000*30(<1秒)
select*fromrecordwhereActionTime=to_date('19991201','yyyymmdd')(<1秒)差别是很明显的!SQL优化(oracle)避免对列的操作SQL优化(oracle)避免不必要的类型转换需要注意的是,尽量避免潜在的数据类型转换。如将字符型数据与数值型数据比较,ORACLE会自动将字符型用to_number()函数进行转换,从而导致全表扫描。例2:表tab1中的列col1是字符型(char),则以下语句存在类型转换:
selectcol1,col2fromtab1wherecol1>10,应该写为:selectcol1,col2fromtab1wherecol1>'10'。SQL优化(oracle)避免不必要的类型转换SQL优化(oracle)增加查询的范围限制增加查询的范围限制,避免全范围的搜索。例3:以下查询表record中时间ActionTime小于2001年3月1日的数据:
select*fromrecordwhereActionTime<to_date('20010301','yyyymm')
查询计划表明,上面的查询对表进行全表扫描,如果我们知道表中的最早的数据为2001年1月1日,那么,可以增加一个最小时间,使查询在一个完整的范围之内。修改如下:
SQL优化(oracle)增加查询的范围限制SQL优化(oracle)增加查询的范围限制
select*fromrecordwhereActionTime<to_date('20010301','yyyymm')andActionTime>to_date('20010101','yyyymm')
后一种SQL语句将利用上ActionTime字段上的索引,从而提高查询效率。把'20010301'换成一个变量,根据取值的机率,可以有一半以上的机会提高效率。同理,对于大于某个值的查询,如果知道当前可能的最大值,也可以在Where子句中加上“AND列名<MAX(最大值)”。SQL优化(oracle)增加查询的范围限制SQL优化(oracle)尽量去掉"IN"、"OR“
含有"IN"、"OR"的Where子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。例4:selectcount(*)fromstuffwhereid_noin('0','1')(23秒)可以考虑将or子句分开:
selectcount(*)fromstuffwhereid_no='0'selectcount(*)fromstuffwhereid_no='1'
然后再做一个简单的加法,与原来的SQL语句相比,查询速度更快。SQL优化(oracle)尽量去掉"IN"、"OR“SQL优化(oracle)尽量去掉"<>“
尽量去掉"<>",避免全表扫描,如果数据是枚举值,且取值范围固定,则修改为"OR"方式。例5:UPDATESERVICEINFOSETSTATE=0WHERESTATE<>0;
以上语句由于其中包含了"<>",执行计划中用了全表扫描(TABLEACCESSFULL),没有用到state字段上的索引。实际应用中,由于业务逻辑的限制,字段state为枚举值,只能等于0,1或2,而且,值等于=1,2的很少,因此可以去掉"<>",利用索引来提高效率。修改为:UPDATESERVICEINFOSETSTATE=0WHERESTATE=1ORSTATE=2。进一步的修改可以参考第4种方法。SQL优化(oracle)尽量去掉"<>“SQL优化(oracle)去掉Where子句中的ISNULL和ISNOTNULL
Where字句中的ISNULL和ISNOTNULL将不会使用索引而是进行全表搜索,因此需要通过改变查询方式,分情况讨论等方法,去掉Where子句中的ISNULL和ISNOTNULL。SQL优化(oracle)去掉Where子句中的ISNULSQL优化(oracle)索引提高数据分布不均匀时查询效率索引的选择性低,但数据的值分布差异很大时,仍然可以利用索引提高效率。A、数据分布不均匀的特殊情况下,选择性不高的索引也要创建。表ServiceInfo中数据量很大,假设有一百万行,其中有一个字段DisposalCourseFlag,取值范围为枚举值:[0,1,2,3,4,5,6,7]。按照前面说的索引建立的规则,“选择性不高的字段不应该建立索引,该字段只有8种取值,索引值的重复率很高,索引选择性明显很低,因此不建索引。然而,由于该字段上数据值的分布情况非常特殊,具体如下表:SQL优化(oracle)索引提高数据分布不均匀时查询效率SQL优化(oracle)索引提高数据分布不均匀时查询效率而且,常用的查询中,查询DisposalCourseFlag<6的情况既多又频繁,毫无疑问,如果能够建立索引,并且被应用,那么将大大提高这种情况的查询效率。因此,我们需要在该字段上建立索引。SQL优化(oracle)索引提高数据分布不均匀时查询效率SQL优化(oracle)利用HINT强制指定索引在ORACLE优化器无法用上合理索引的情况下,利用HINT强制指定索引。继续上面7的例子,ORACLE缺省认定,表中列的值是在所有数据行中均匀分布的,也就是说,在一百万数据量下,每种DisposalCourseFlag值各有12.5万数据行与之对应。假设SQL搜索条件DisposalCourseFlag=2,利用DisposalCourseFlag列上的索引进行数据搜索效率,往往不比全表扫描的高,ORACLE因此对索引“视而不见”,从而在查询路径的选择中,用其他字段上的索引甚至全表扫描。根据我们上面的分析,数据值的分布很特殊,严重的不均匀。SQL优化(oracle)利用HINT强制指定索引SQL优化(oracle)利用HINT强制指定索引为了利用索引提高效率,此时,一方面可以单独对该字段或该表用analyze语句进行分析,对该列搜集足够的统计数据,使ORACLE在查询选择性较高的值时能用上索引;另一方面,可以利用HINT提示,在SELECT关键字后面,加上“/*+INDEX(表名称,索引名称)*/”的方式,强制ORACLE优化器用上该索引。比如:select*fromserviceinfowhereDisposalCourseFlag=1;SQL优化(oracle)利用HINT强制指定索引SQL优化(oracle)利用HINT强制指定索引上面的语句,实际执行中ORACLE用了全表扫描,加上蓝色提示部分后,用到索引查询。如下:
select/*+INDEX(SERVICEINFO,IX_S_DISPOSALCOURSEFLAG)*/*fromserviceinfowhereDisposalCourseFlag=1;
请注意,这种方法会加大代码维护的难度,而且该字段上索引的名称被改变之后,必须要同步所有指定索引的HINT代码,否则HINT提示将被ORACLE忽略掉。SQL优化(oracle)利用HINT强制指定索引SQL优化(oracle)屏蔽无用索引继续上面8的例子,由于实际查询中,还有涉及到DisposalCourseFlag=6的查询,而此时如果用上该字段上的索引,将是非常不明智的,效率也极低。因此这种情况下,我们需要用特殊的方法屏蔽该索引,以便ORACLE选择其他字段上的索引。比如,如果字段为数值型的就在表达式的字段名后,添加“+0”,为字符型的就并上空串:“||""”
如:select*fromserviceinfowhereDisposalCourseFlag+0=6andworkNo='36'。不过,不要把该用的索引屏蔽掉了,否则同样会产生低效率的全表扫描。SQL优化(oracle)屏蔽无用索引SQL优化(oracle)分解复杂查询,用常量代替变量对于复杂的Where条件组合,Where中含有多个带索引的字段,考虑用IF语句分情况进行讨论;同时,去掉不必要的外来参数条件,减低复杂度,以便在不同情况下用不同字段上的索引。SQL优化(oracle)分解复杂查询,用常量代替变量SQL优化(oracle)分解复杂查询,用常量代替变量继续上面9的例子,对于包含
Where(DisposalCourseFlag<v_DisPosalCourseFlag)or(v_DisPosalCourseFlagisnull)and....的查询,(这里v_DisPosalCourseFlag为一个输入变量,取值范围可能为[NULL,0,1,2,3,4,5,6,7]),可以考虑分情况用IF语句进行讨论,类似:
IFv_DisPosalCourseFlag=1THENWhereDisposalCourseFlag=1and....ELSIFv_DisPosalCourseFlag=2THENWhereDisposalCourseFlag=2and....
。。。。。。SQL优化(oracle)分解复杂查询,用常量代替变量SQL优化(oracle)like子句尽量前端匹配因为like参数使用的非常频繁,因此如果能够对like子句使用索引,将很高的提高查询的效率。例6:select*fromcitywherenamelike‘%S%’
以上查询的执行计划用了全表扫描(TABLEACCESSFULL),如果能够修改为:
select*fromcitywherenamelike‘S%’
那么查询的执行计划将会变成(INDEXRANGESCAN),成功的利用了name字段的索引。这意味着OracleSQL优化器会识别出用于索引的like子句,只要该查询的匹配端是具体值。因此我们在做like查询时,应该尽量使查询的匹配端是具体值,即使用like‘S%’。SQL优化(oracle)like子句尽量前端匹配SQL优化(oracle)用Case语句合并多重扫描我们常常必须基于多组数据表计算不同的聚集。例如下例通过三个独立查询:例8:1)selectcount(*)fromempwheresal<1000;2)selectcount(*)fromempwheresalbetween1000and5000;3)selectcount(*)fromempwheresal>5000;
这样我们需要进行三次全表查询,但是如果我们使用case语句:SQL优化(oracle)用Case语句合并多重扫描SQL优化(oracle)用Case语句合并多重扫描
selectcount(salewhensal<1000then1elsenullend)count_poor,count(salewhenbetween1000and5000then1elsenullend)count_blue_collar,count(salewhensal>5000then1elsenullend)count_poorfromemp;
这样查询的结果一样,但是执行计划只进行了一次全表查询SQL优化(oracle)用Case语句合并多重扫描SQL优化(oracle)使用nls_date_format
例9:
select*fromrecordwhereto_char(ActionTime,'mm')='12'
这个查询的执行计划将是全表查询,如果我们改变nls_date_format,
SQL>alertsessionsetnls_date_formate=’MM’;
现在重新修改上面的查询:
select*fromrecordwhereActionTime='12'
这样就能使用actiontime上的索引了,它的执行计划将是(INDEXRANGESCAN)SQL优化(oracle)使用nls_date_formatSQL优化(oracle)使用基于函数的索引前面谈到任何对列的操作都可能导致全表扫描,例如:
select*fromempwheresubstr(ename,1,2)=’SM’;
但是这种查询在客服系统又经常使用,我们可以创建一个带有substr函数的基于函数的索引,
createindexemp_ename_substroneemp(substr(ename,1,2));
这样在执行上面的查询语句时,这个基于函数的索引将排上用场,执行计划将是(INDEXRANGESCAN)。SQL优化(oracle)使用基于函数的索引SQL优化(oracle)基于函数的索引要求等式匹配上面的例子中,我们创建了基于函数的索引,但是如果执行下面的查询:
select*fromempwheresubstr(ename,1,1)=’S’
得到的执行计划将还是(TABLEACCESSFULL),因为只有当数据列能够等式匹配时,基于函数的索引才能生效,这样对于这种索引的计划和维护的要求都很高。请注意,向表中添加索引是非常危险的操作,因为这将导致许多查询执行计划的变更。然而,如果我们使用基于函数的索引就不会产生这样的问题,因为Oracle只有在查询使用了匹配的内置函数时才会使用这种类型的索引。SQL优化(oracle)基于函数的索引要求等式匹配SQL优化(oracle)使用分区索引在用分析命令对分区索引进行分析时,每一个分区的数据值的范围信息会放入Oracle的数据字典中。Oracle可以利用这个信息来提取出那些只与SQL查询相关的数据分区。例如,假设你已经定义了一个分区索引,并且某个SQL语句需要在一个索引分区中进行一次索引扫描。Oracle会仅仅访问这个索引分区,而且会在这个分区上调用一个此索引范围的快速全扫描。因为不需要访问整个索引,所以提高了查询的速度。SQL优化(oracle)使用分区索引SQL优化(oracle)使用位图索引位图索引可以从本质上提高使用了小于1000个唯一数据值的数据列的查询速度,因为在位图索引中进行的检索是在RAM中完成的,而且也总是比传统的B树索引的速度要快。对于那些少于1000个唯一数据值的数据列建立位图索引,可以使执行效率更快。SQL优化(oracle)使用位图索引SQL优化(oracle)决定使用全表扫描还是使用索引和所有的秘笈一样,最后一招都会又回到起点,最后我们来讨论一下是否需要建立索引,也许进行全表扫描更快。在大多数情况下,全表扫描可能会导致更多的物理磁盘输入输出,但是全表扫描有时又可能会因为高度并行化的存在而执行的更快。如果查询的表完全没有顺序,那么一个要返回记录数小于10%的查询可能会读取表中大部分的数据块,这样使用索引会使查询效率提高很多。但是如果表非常有顺序,那么如果查询的记录数大于40%时,可能使用全表扫描更快。SQL优化(oracle)决定使用全表扫描还是使用索引SQL优化(oracle)决定使用全表扫描还是使用索引因此,有一个索引范围扫描的总体原则是:
1)对于原始排序的表仅读取少于表记录数40%的查询应该使用索引范围扫描。反之,读取记录数目多于表记录数的40%的查询应该使用全表扫描。
2)对于未排序的表仅读取少于表记录数7%的查询应该使用索引范围扫描。反之,读取记录数目多于表记录数的7%的查询应该使用全表扫描。SQL优化(oracle)决定使用全表扫描还是使用索引SQL优化(oracle)以上的十八招式,是完全可以相互结合同时运用的。而且各种方法之间相互影响,紧密联系。这种联系既存在一致性,也可能带来冲突,当冲突发生时,需要根据实际情况进行选择,没有固定的模式。最后决定SQL优化功力的因素就是对ORACLE内功的掌握程度了。另外,值得注意的是:随着时间的推移和数据的累计与变化,ORACLE对SQL语句的执行计划也会改变,比如:基于代价的优化方法,随着数据量的增大,优化器可能错误的不选择索引而采用全表扫描。这种情况可能是因为统计信息已经过时,在数据量变化很大后没有及时分析表;但如果对表进行分析之后,仍然没有用上合理的索引,那么就有必要对SQL语句用HINT提示,强制用合理的索引。SQL优化(oracle)以上的十八招式,是完全可以相互结合SQL优化(oracle)但这种HINT提示也不能滥用,因为这种方法过于复杂,缺乏通用性和应变能力,同时也增加了维护上的代价;相对来说,基于函数右移、去掉“IN,OR,<>,ISNOTNULL”、分解复杂的SQL语句等等方法,却是“放之四海皆准”的,可以放心大胆的使用。同时,优化也不是“一劳永逸”的,必须随着情况的改变进行相应的调整。当数据库设计发生变化,包括更改表结构:字段和索引的增加、删除或改名等;业务逻辑发生变化:如查询方式、取值范围发生改变等等。在这种情况下,也必须对原有的优化进行调整,以适应效率上的需求。SQL优化(oracle)但这种HINT提示也不能滥用,因为演讲完毕,谢谢观看!演讲完毕,谢谢观看!SQL编写规范和优化
SQL编写规范和优化SQL编写规范--1原则定义
1、要求代码行清晰、整齐,具有一定的可观赏性;
2、代码编写要充分考虑执行速度最优的原则;
3、代码行整体层次分明、结构化强;
4、代码中应有必要的注释以增强代码的可读性;
5、规范要求非强制性约束代码开发人员的代码编写行为,在实际应用中在不违反常规要求的前提下允许存在可理解的偏差。SQL编写规范--1原则定义SQL编写规范--2大小写规则
1、所有的SQL语句中的保留字均采用全部大写,不要使用缩写;表别名也要大写;如ALLASCASECREATEDATABASEDELETEFROMININSERTJOINLEFTNONOTNULLOUTSELECTTABLETITLEUPDATEVIEWWHERE等。
2、表名、视图名、宏和存储过程名:全部小写;SQL编写规范--2大小写规则SQL编写规范--2大小写规则
3、字段名:每个单词的首字母大写,其余部分小写,如party_id,loc_id,prod_inst_id,Acct_Id,Type_Id等;使用如下语句获得字段列表:SQL编写规范--2大小写规则SQL编写规范--3缩进和换行
整个的SQL语句最好按照子句进行分行编写,SELECT/FROM/WHERE/UPDATE/INSERT等每个关键字都要另起一行。如:SQL编写规范--3缩进和换行SQL编写规范--3缩进和换行SQL编写规范--3缩进和换行SQL编写规范--3缩进和换行
1、同一级别的子句间要对齐
2、逗号放在每行的开头
3、分号放在SQL语句的最后,单独占一行
4、每行宽度不超过120字符(每个字符为8个点阵宽),超过行宽的代码可折行与上行对齐编排;
5、每个字段后面使用字段标题作为注释
6、使用给出的语句获得字段列表和字段标题(借助UltraEdit列模式快速编辑)SQL编写规范--3缩进和换行SQL编写规范--3缩进和换行下面的编写方式不是好的形式:在所有需要缩进的地方,每次缩进4格;在以下情况下需要缩进:
1、不同层次的SQL语句之间
2、SELECTINSERT等关键字之后的字段列表和关键字之间SQL编写规范--3缩进和换行SQL编写规范--4别名
SQL语句别名的命名,分层命名,从第一层次至第四层次,分别用P、S、U、D(都是大写字母)表示,取意为Part,Segment,Unit,Detail。对于同一层次的多个子句,在字母后加1、2、3、4……区分。SQL编写规范--4别名SQL编写规范--4别名
如下图所示:SQL编写规范--4别名SQL编写规范--5运算符前后间隔要求算术运算符、逻辑运算符的前后至少要保留一个空格,如下图所示:SQL编写规范--5运算符前后间隔要求SQL编写规范--6变量引用
1、在SQL语句中引用变量时,要在变量名两端加花括号
2、对日期变量的引用要在单引号内,如'${MYDATE}'SQL编写规范--6变量引用SQL编写规范--7注释针对复杂的SQL语句,请尽量增加相应的注释说明,以便自己和其它同事事后可以比较容易的读懂和修改。注释中应包含以下内容:
1、编写人/编写日期
2、修改人/修改日期
3、该脚本的编写目的与主要内容
4、如果有特殊处理、特别的技巧等内容,一定要在注释中详细说明SQL编写规范--7注释SQL编写规范--7注释
5、每一段SQL的前面必须要有注释,重点说明该SQL的技术含义和应用含义、选择理由。技术含义指这段SQL在技术上这么写的原因、好处,应用含义指这段SQL从应用的角度将,是为了达到一个什么样的目的。如果有可能,还需要说明为什么这么选择,而不选择别的方式的理由。如果发现了不足,还可记录不足的原因和建议的解决办法等。SQL编写规范--7注释SQL编写规范--8连接的使用对于内连接和外连接的使用,要求该使用外连接的地方都已经使用了外连接,不需要外连接的地方一定不使用外连接。表中的字段若是从其它表引用的,要确保该字段在被引用的表中存在。SQL编写规范--8连接的使用SQL编写规范--8连接的使用要求所有的连接都写成JOIN的形式,如:SQL编写规范--8连接的使用SQL编写规范--8连接的使用而不要写成:SQL编写规范--8连接的使用SQL编写规范--8连接的使用另外,为了保证多表连接的连接条件穿透性,要求在多表连接的SQL书写时将连接条件有机的闭环起来,尤其是多表PI相同,并用PI连接时。SQL编写规范--8连接的使用SQL编写规范--8连接的使用
例如:SQL编写规范--8连接的使用SQL编写规范--8连接的使用即连接条件如下所示:SQL编写规范--8连接的使用SQL优化(teradata)SQL脚本优化原则
要优化脚本,在深刻理解业务逻辑的基础上,一个重要的方式是一段一段的查看SQL的执行计划,然后针对执行计划中不合理、不优化的地方对SQL进行优化编写,这项工作需要实践经验,经常看执行计划会有所帮助。SQL优化(teradata)SQL脚本优化原则SQL优化(teradata)SQL脚本优化原则表级优化可以参照以下以下优化原则:
(1)如果过滤性不很强,又不需要重分布,对大表尽可能不要只做一下过滤就进一次SPOOL,最好是直接与别的表JOIN,边JOIN边过滤了;
(2)如果过滤性非常强,可以只做一下过滤就进一次SPOOL;SQL优化(teradata)SQL脚本优化原则SQL优化(teradata)SQL脚本优化原则
(3)SPOOL空间尽量小原则,即尽可能使中间过程中的SPOOL空间小一些,这样可以减小I/O以及继续关联的代价;在此原则下可以引申出下面几个具体原则:
(3.1)在几个表大小差不多时,过滤性条件较强的先JOIN;
(3.2)在大/大/小三个表内联时,避免先把两个大表JOIN,除非过滤条件非常强;
(3.3)在大/小/小三个表内联时,尽量先把两个小表JOIN;
(3.4)有时将看似没必要的过滤条件加上,在关联表较多时可能有效的减小SPOOL;如表A、B、C、D的关联字段均为k,即A.k=B.kANDA.k=C.kANDA.k=D.k,而同时还有条件substr(A.k,1,2)='01',有时加上substr(B.k,1,2)='01'、substr(C.k,1,2)='01'、substr(D.k,1,2)='01‘会有好处;SQL优化(teradata)SQL脚本优化原则SQL优化(teradata)SQL脚本优化原则
(4)尽量避免大表重分布;
(5)当大表与很小的表(记录数量级在5位数以内)JOIN时,尽量让小表Duplicate;
(6)如果必须有重分布时,尽量使之靠后;
(7)尽量减少较大的中间过程中的SPOOL空间重分布的次数;SQL优化(teradata)SQL脚本优化原则SQL优化(teradata)SQL脚本优化原则
(8)遇到productjoin时要小心一些;
(9)尽量减少对大表的扫描次数;
(10)在拆SQL时也应注意,合起来虽然可能大些,但只扫描一次大表,而拆成多句后就要多次扫描大表,可能效率反降;SQL优化(teradata)SQL脚本优化原则SQL优化(oracle)基于索引的SQL语句优化数据库的优化方法有很多种,在应用层来说,主要是基于索引的优化。难就难在如何判断哪些索引是必要的,哪些又是不必要的。判断的最终标准是看这些索引是否对我们的数据库性能有所帮助。具体到方法上,就必须熟悉数据库应用程序中的所有SQL语句,从中统计出常用的可能对性能有影响的部分SQL,分析、归纳出作为Where条件子句的字段及其组合方式;在这一基础上可以初步判断出哪些表的哪些字段应该建立索引。SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化其次,必须熟悉应用程序。必须了解哪些表是数据操作频繁的表;哪些表经常与其他表进行连接;哪些表中的数据量可能很大;对于数据量大的表,其中各个字段的数据分布情况如何;等等。对于满足以上条件的这些表,必须重点关注,因为在这些表上的索引,将对SQL语句的性能产生举足轻重的影响SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化建立索引常用的规则如下:
1、表的主键、外键必须有索引;
2、数据量超过300的表应该有索引;
3、经常与其他表进行连接的表,在连接字段上应该建立索引;
4、经常出现在Where子句中的字段,特别是大表的字段,应该建立索引;
5、索引应该建在选择性高的字段上;
SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化
6、索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引;
7、复合索引的建立需要进行仔细分析;尽量考虑用单字段索引代替:
A、正确选择复合索引中的主列字段,一般是选择性较好的字段;
B、复合索引的几个字段是否经常同时以AND方式出现在Where子句中?单字段查询是否极少甚至没有?如果是,则可以建立复合索引;否则考虑单字段索引;SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化
C、如果复合索引中包含的字段经常单独出现在Where子句中,则分解为多个单字段索引;
D、如果复合索引所包含的字段超过3个,那么仔细考虑其必要性,考虑减少复合的字段;
E、如果既有单字段索引,又有这几个字段上的复合索引,一般可以删除复合索引;SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化
8、频繁进行数据操作的表,不要建立太多的索引;
9、删除无用的索引,避免对执行计划造成负面影响;以上是一些普遍的建立索引时的判断依据。一言以蔽之,索引的建立必须慎重,对每个索引的必要性都应该经过仔细分析,要有建立的依据。
SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)基于索引的SQL语句优化太多的索引与不充分、不正确的索引对性能都毫无益处:在表上建立的每个索引都会增加存储开销,索引对于插入、删除、更新操作也会增加处理上的开销。另外,过多的复合索引,在有单字段索引的情况下,一般都是没有存在价值的;相反,还会降低数据增加删除时的性能,特别是对频繁更新的表来说,负面影响更大。SQL优化(oracle)基于索引的SQL语句优化SQL优化(oracle)避免对列的操作任何对列的操作都可能导致全表扫描,这里所谓的操作包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等式的右边,甚至去掉函数。例1:下列SQL条件语句中的列都建有恰当的索引,但30万行数据情况下执行速度却非常慢:
select*fromrecordwheresubstrb(CardNo,1,4)='5378'(13秒)select*fromrecordwhereamount/30<1000(11秒)
select*fromrecordwhereto_char(ActionTime,'yyyymmdd')='19991201'(10秒)
SQL优化(oracle)避免对列的操作SQL优化(oracle)避免对列的操作由于where子句中对列的任何操作结果都是在SQL运行时逐行计算得到的,因此它不得不进行表扫描,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表扫描,因此将SQL重写如下:
select*fromrecordwhereCardNolike'5378%'(<1秒)
select*fromrecordwhereamount<1000*30(<1秒)
select*fromrecordwhereActionTime=to_date('19991201','yyyymmdd')(<1秒)差别是很明显的!SQL优化(oracle)避免对列的操作SQL优化(oracle)避免不必要的类型转换需要注意的是,尽量避免潜在的数据类型转换。如将字符型数据与数值型数据比较,ORACLE会自动将字符型用to_number()函数进行转换,从而导致全表扫描。例2:表tab1中的列col1是字符型(char),则以下语句存在类型转换:
selectcol1,col2fromtab1wherecol1>10,应该写为:selectcol1,col2fromtab1wherecol1>'10'。SQL优化(oracle)避免不必要的类型转换SQL优化(oracle)增加查询的范围限制增加查询的范围限制,避免全范围的搜索。例3:以下查询表record中时间ActionTime小于2001年3月1日的数据:
select*fromrecordwhereActionTime<to_date('20010301','yyyymm')
查询计划表明,上面的查询对表进行全表扫描,如果我们知道表中的最早的数据为2001年1月1日,那么,可以增加一个最小时间,使查询在一个完整的范围之内。修改如下:
SQL优化(oracle)增加查询的范围限制SQL优化(oracle)增加查询的范围限制
select*fromrecordwhereActionTime<to_date('20010301','yyyymm')andActionTime>to_date('20010101','yyyymm')
后一种SQL语句将利用上ActionTime字段上的索引,从而提高查询效率。把'20010301'换成一个变量,根据取值的机率,可以有一半以上的机会提高效率。同理,对于大于某个值的查询,如果知道当前可能的最大值,也可以在Where子句中加上“AND列名<MAX(最大值)”。SQL优化(oracle)增加查询的范围限制SQL优化(oracle)尽量去掉"IN"、"OR“
含有"IN"、"OR"的Where子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。例4:selectcount(*)fromstuffwhereid_noin('0','1')(23秒)可以考虑将or子句分开:
selectcount(*)fromstuffwhereid_no='0'selectcount(*)fromstuffwhereid_no='1'
然后再做一个简单的加法,与原来的SQL语句相比,查询速度更快。SQL优化(oracle)尽量去掉"IN"、"OR“SQL优化(oracle)尽量去掉"<>“
尽量去掉"<>",避免全表扫描,如果数据是枚举值,且取值范围固定,则修改为"OR"方式。例5:UPDATESERVICEINFOSETSTATE=0WHERESTATE<>0;
以上语句由于其中包含了"<>",执行计划中用了全表扫描(TABLEACCESSFULL),没有用到state字段上的索引。实际应用中,由于业务逻辑的限制,字段state为枚举值,只能等于0,1或2,而且,值等于=1,2的很少,因此可以去掉"<>",利用索引来提高效率。修改为:UPDATESERVICEINFOSETSTATE=0WHERESTATE=1ORSTATE=2。进一步的修改可以参考第4种方法。SQL优化(oracle)尽量去掉"<>“SQL优化(oracle)去掉Where子句中的ISNULL和ISNOTNULL
Where字句中的ISNULL和ISNOTNULL将不会使用索引而是进行全表搜索,因此需要通过改变查询方式,分情况讨论等方法,去掉Where子句中的ISNULL和ISNOTNULL。SQL优化(oracle)去掉Where子句中的ISNULSQL优化(oracle)索引提高数据分布不均匀时查询效率索引的选择性低,但数据的值分布差异很大时,仍然可以利用索引提高效率。A、数据分布不均匀的特殊情况下,选择性不高的索引也要创建。表ServiceInfo中数据量很大,假设有一百万行,其中有一个字段DisposalCourseFlag,取值范围为枚举值:[0,1,2,3,4,5,6,7]。按照前面说的索引建立的规则,“选择性不高的字段不应该建立索引,该字段只有8种取值,索引值的重复率很高,索引选择性明显很低,因此不建索引。然而,由于该字段上数据值的分布情况非常特殊,具体如下表:SQL优化(oracle)索引提高数据分布不均匀时查询效率SQL优化(oracle)索引提高数据分布不均匀时查询效率而且,常用的查询中,查询DisposalCourseFlag<6的情况既多又频繁,毫无疑问,如果能够建立索引,并且被应用,那么将大大提高这种情况的查询效率。因此,我们需要在该字段上建立索引。SQL优化(oracle)索引提高数据分布不均匀时查询效率SQL优化(oracle)利用HINT强制指定索引在ORACLE优化器无法用上合理索引的情况下,利用HINT强制指定索引。继续上面7的例子,ORACLE缺省认定,表中列的值是在所有数据行中均匀分布的,也就是说,在一百万数据量下,每种DisposalCourseFlag值各有12.5万数据行与之对应。假设SQL搜索条件DisposalCourseFlag=2,利用DisposalCourseFlag列上的索引进行数据搜索效率,往往不比全表扫描的高,ORACLE因此对索引“视而不见”,从而在查询路径的选择中,用其他字段上的索引甚至全表扫描。根据我们上面的分析,数据值的分布很特殊,严重的不均匀。SQL优化(oracle)利用HINT强制指定索引SQL优化(oracle)利用HINT强制指定索引为了利用索引提高效率,此时,一方面可以单独对该字段或该表用analyze语句进行分析,对该列搜集足够的统计数据,使ORACLE在查询选择性较高的值时能用上索引;另一方面,可以利用HINT提示,在SELECT关键字后面,加上“/*+INDEX(表名称,索引名称)*/”的方式,强制ORACLE优化器用上该索引。比如:select*fromserviceinfowhereDisposalCourseFlag=1;SQL优化(oracle)利用HINT强制指定索引SQL优化(oracle)利用HINT强制指定索引上面的语句,实际执行中ORACLE用了全表扫描,加上蓝色提示部分后,用到索引查询。如下:
select/*+INDEX(SERVICEINFO,IX_S_DISPOSALCOURSEFLAG)*/*fromserviceinfowhereDisposalCourseFlag=1;
请注意,这种方法会加大代码维护的难度,而且该字段上索引的名称被改变之后,必须要同步所有指定索引的HINT代码,否则HINT提示将被ORACLE忽略掉。SQL优化(oracle)利用HINT强制指定索引SQL优化(oracle)屏蔽无用索引继续上面8的例子,由于实际查询中,还有涉及到DisposalCourseFlag=6的查询,而此时如果用上该字段上的索引,将是非常不明智的,效率也极低。因此这种情况下,我们需要用特殊的方法屏蔽该索引,以便ORACLE选择其他字段上的索引。比如,如果字段为数值型的就在表达式的字段名后,添加“+0”,为字符型的就并上空串:“||""”
如:select*fromserviceinfowhereDisposalCourseFlag+0=6andworkNo='36'。不过,不要把该用的索引屏蔽掉了,否则同样会产生低效率的全表扫描。SQL优化(oracle)屏蔽无用索引SQL优化(oracle)分解复杂查询,用常量代替变量对于复杂的Where条件组合,Where中含有多个带索引的字段,考虑用IF语句分情况进行讨论;同时,去掉不必要的外来参数条件,减低复杂度,以便在不同情况下用不同字段上的索引。SQL优化(oracle)分解复杂查询,用常量代替变量SQL优化(oracle)分解复杂查询,用常量代替变量继续上面9的例子,对于包含
Where(DisposalCourseFlag<v_DisPosalCourseFlag)or(v_DisPosalCourseFlagisnull)and....的查询,(这里v_DisPosalCourseFlag为一个输入变量,取值范围可能为[NULL,0,1,2,3,4,5,6,7]),可以考虑分情况用IF语句进行讨论,类似:
IFv_DisPosalCourseFlag=1THENWhereDisposalCourseFlag=1and....ELSIFv_DisPosalCourseFlag=2THENWhereDisposalCourseFlag=2and....
。。。。。。SQL优化(oracle)分解复杂查询,用常量代替变量SQL优化(oracle)like子句尽量前端匹配因为like参数使用的非常频繁,因此如果能够对like子句使用索引,将很高的提高查询的效率。例6:select*fromcitywherenamelike‘%S%’
以上查询的执行计划用了全表扫描(TABLEACCESSFULL),如果能够修改为:
select*fromcitywherenamelike‘S%’
那么查询的执行计划将会变成(INDEXRANGESCAN),成功的利用了name字段的索引。这意味着OracleSQL优化器会识别出用于索引的like子句,只要该查询的匹配端是具体值。因此我们在做like查询时,应该尽量使查询的匹配端是具体值,即使用like‘S%’。SQL优化(oracle)like子句尽量前端匹配SQL优化(oracle)用Case语句合并多重扫描我们常常必须基于多组数据表计算不同的聚集。例如下例通过三个独立查询:例8:1)selectcount(*)fromempwheresal<1000;2)selectcount(*)fromempwheresalbetween1000and5000;3)selectcount(*)fromempwheresal>5000;
这样我们需要进行三次全表查询,但是如果我们使用case语句:SQL优化(oracle)用Case语句合并多重扫描SQL优化(oracle)用Case语句合并多重扫描
selectcount(salewhensal<1000then1elsenullend)count_poor,count(salewhenbetween1000and5000then
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年标准消防设备销售合同范本版B版
- 2024年度技术转让合同-高新技术企业3篇
- 2024版实验室质量保证协议2篇
- 2024年度中铁工程劳务分包税务处理合同3篇
- 2024年度装配式建筑商品房代理销售服务协议3篇
- 2024年标准机械设备维修保障协议模板版B版
- 2024版冷链运输采购合同模板-新鲜直达协议3篇
- 门牌灯项目立项申请报告
- 新建检测仪项目可行性研究报告
- 年产xxxpvc包装膜项目可行性报告
- 钹式换能器的共振特性研究
- 《我们去看海》阅读答案
- 智慧酒店无人酒店综合服务解决方案
- 考研英语一新题型历年真题(2005-2012)
- 健身房会籍顾问基础培训资料
- 9脊柱与四肢、神经系统检查总结
- 秀场内外-走进服装表演艺术智慧树知到答案章节测试2023年武汉纺织大学
- 【高分复习笔记】王建《现代自然地理学》(第2版)笔记和课后习题详解
- TSGD0012023年压力管道安全技术监察规程-工业管道(高清晰版)
- SMM英国建筑工程标准计量规则中文 全套
- 2023-2024学年浙江省富阳市小学数学四年级上册期末通关题
评论
0/150
提交评论