SQL编写规范和优化讲稿.ppt_第1页
SQL编写规范和优化讲稿.ppt_第2页
SQL编写规范和优化讲稿.ppt_第3页
SQL编写规范和优化讲稿.ppt_第4页
SQL编写规范和优化讲稿.ppt_第5页
已阅读5页,还剩55页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

SQL编写规范和优化 SQL编写规范 1 原则定义1 要求代码行清晰 整齐 具有一定的可观赏性 2 代码编写要充分考虑执行速度最优的原则 3 代码行整体层次分明 结构化强 4 代码中应有必要的注释以增强代码的可读性 5 规范要求非强制性约束代码开发人员的代码编写行为 在实际应用中在不违反常规要求的前提下允许存在可理解的偏差 SQL编写规范 2 大小写规则1 所有的SQL语句中的保留字均采用全部大写 不要使用缩写 表别名也要大写 如ALLASCASECREATEDATABASEDELETEFROMININSERTJOINLEFTNONOTNULLOUTSELECTTABLETITLEUPDATEVIEWWHERE等 2 表名 视图名 宏和存储过程名 全部小写 SQL编写规范 2 大小写规则3 字段名 每个单词的首字母大写 其余部分小写 如party id loc id prod inst id Acct Id Type Id等 使用如下语句获得字段列表 SQL编写规范 3 缩进和换行整个的SQL语句最好按照子句进行分行编写 SELECT FROM WHERE UPDATE INSERT等每个关键字都要另起一行 如 SQL编写规范 3 缩进和换行 SQL编写规范 3 缩进和换行1 同一级别的子句间要对齐2 逗号放在每行的开头3 分号放在SQL语句的最后 单独占一行4 每行宽度不超过120字符 每个字符为8个点阵宽 超过行宽的代码可折行与上行对齐编排 5 每个字段后面使用字段标题作为注释6 使用给出的语句获得字段列表和字段标题 借助UltraEdit列模式快速编辑 SQL编写规范 3 缩进和换行下面的编写方式不是好的形式 在所有需要缩进的地方 每次缩进4格 在以下情况下需要缩进 1 不同层次的SQL语句之间2 SELECTINSERT等关键字之后的字段列表和关键字之间 SQL编写规范 4 别名SQL语句别名的命名 分层命名 从第一层次至第四层次 分别用P S U D 都是大写字母 表示 取意为Part Segment Unit Detail 对于同一层次的多个子句 在字母后加1 2 3 4 区分 SQL编写规范 4 别名如下图所示 SQL编写规范 5 运算符前后间隔要求算术运算符 逻辑运算符的前后至少要保留一个空格 如下图所示 SQL编写规范 6 变量引用1 在SQL语句中引用变量时 要在变量名两端加花括号2 对日期变量的引用要在单引号内 如 MYDATE SQL编写规范 7 注释针对复杂的SQL语句 请尽量增加相应的注释说明 以便自己和其它同事事后可以比较容易的读懂和修改 注释中应包含以下内容 1 编写人 编写日期2 修改人 修改日期3 该脚本的编写目的与主要内容4 如果有特殊处理 特别的技巧等内容 一定要在注释中详细说明 SQL编写规范 7 注释5 每一段SQL的前面必须要有注释 重点说明该SQL的技术含义和应用含义 选择理由 技术含义指这段SQL在技术上这么写的原因 好处 应用含义指这段SQL从应用的角度将 是为了达到一个什么样的目的 如果有可能 还需要说明为什么这么选择 而不选择别的方式的理由 如果发现了不足 还可记录不足的原因和建议的解决办法等 SQL编写规范 8 连接的使用对于内连接和外连接的使用 要求该使用外连接的地方都已经使用了外连接 不需要外连接的地方一定不使用外连接 表中的字段若是从其它表引用的 要确保该字段在被引用的表中存在 SQL编写规范 8 连接的使用要求所有的连接都写成JOIN的形式 如 SQL编写规范 8 连接的使用而不要写成 SQL编写规范 8 连接的使用另外 为了保证多表连接的连接条件穿透性 要求在多表连接的SQL书写时将连接条件有机的闭环起来 尤其是多表PI相同 并用PI连接时 SQL编写规范 8 连接的使用例如 SQL编写规范 8 连接的使用即连接条件如下所示 SQL优化 teradata SQL脚本优化原则要优化脚本 在深刻理解业务逻辑的基础上 一个重要的方式是一段一段的查看SQL的执行计划 然后针对执行计划中不合理 不优化的地方对SQL进行优化编写 这项工作需要实践经验 经常看执行计划会有所帮助 SQL优化 teradata SQL脚本优化原则表级优化可以参照以下以下优化原则 1 如果过滤性不很强 又不需要重分布 对大表尽可能不要只做一下过滤就进一次SPOOL 最好是直接与别的表JOIN 边JOIN边过滤了 2 如果过滤性非常强 可以只做一下过滤就进一次SPOOL 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脚本优化原则 4 尽量避免大表重分布 5 当大表与很小的表 记录数量级在5位数以内 JOIN时 尽量让小表Duplicate 6 如果必须有重分布时 尽量使之靠后 7 尽量减少较大的中间过程中的SPOOL空间重分布的次数 SQL优化 teradata SQL脚本优化原则 8 遇到productjoin时要小心一些 9 尽量减少对大表的扫描次数 10 在拆SQL时也应注意 合起来虽然可能大些 但只扫描一次大表 而拆成多句后就要多次扫描大表 可能效率反降 SQL优化 oracle 基于索引的SQL语句优化数据库的优化方法有很多种 在应用层来说 主要是基于索引的优化 难就难在如何判断哪些索引是必要的 哪些又是不必要的 判断的最终标准是看这些索引是否对我们的数据库性能有所帮助 具体到方法上 就必须熟悉数据库应用程序中的所有SQL语句 从中统计出常用的可能对性能有影响的部分SQL 分析 归纳出作为Where条件子句的字段及其组合方式 在这一基础上可以初步判断出哪些表的哪些字段应该建立索引 SQL优化 oracle 基于索引的SQL语句优化其次 必须熟悉应用程序 必须了解哪些表是数据操作频繁的表 哪些表经常与其他表进行连接 哪些表中的数据量可能很大 对于数据量大的表 其中各个字段的数据分布情况如何 等等 对于满足以上条件的这些表 必须重点关注 因为在这些表上的索引 将对SQL语句的性能产生举足轻重的影响 SQL优化 oracle 基于索引的SQL语句优化建立索引常用的规则如下 1 表的主键 外键必须有索引 2 数据量超过300的表应该有索引 3 经常与其他表进行连接的表 在连接字段上应该建立索引 4 经常出现在Where子句中的字段 特别是大表的字段 应该建立索引 5 索引应该建在选择性高的字段上 SQL优化 oracle 基于索引的SQL语句优化6 索引应该建在小字段上 对于大的文本字段甚至超长字段 不要建索引 7 复合索引的建立需要进行仔细分析 尽量考虑用单字段索引代替 A 正确选择复合索引中的主列字段 一般是选择性较好的字段 B 复合索引的几个字段是否经常同时以AND方式出现在Where子句中 单字段查询是否极少甚至没有 如果是 则可以建立复合索引 否则考虑单字段索引 SQL优化 oracle 基于索引的SQL语句优化C 如果复合索引中包含的字段经常单独出现在Where子句中 则分解为多个单字段索引 D 如果复合索引所包含的字段超过3个 那么仔细考虑其必要性 考虑减少复合的字段 E 如果既有单字段索引 又有这几个字段上的复合索引 一般可以删除复合索引 SQL优化 oracle 基于索引的SQL语句优化8 频繁进行数据操作的表 不要建立太多的索引 9 删除无用的索引 避免对执行计划造成负面影响 以上是一些普遍的建立索引时的判断依据 一言以蔽之 索引的建立必须慎重 对每个索引的必要性都应该经过仔细分析 要有建立的依据 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 避免对列的操作由于where子句中对列的任何操作结果都是在SQL运行时逐行计算得到的 因此它不得不进行表扫描 而没有使用该列上面的索引 如果这些结果在查询编译时就能得到 那么就可以被SQL优化器优化 使用索引 避免表扫描 因此将SQL重写如下 select fromrecordwhereCardNolike 5378 1秒 select fromrecordwhereamount 1000 30 1秒 select fromrecordwhereActionTime to date 19991201 yyyymmdd 1秒 差别是很明显的 SQL优化 oracle 避免不必要的类型转换需要注意的是 尽量避免潜在的数据类型转换 如将字符型数据与数值型数据比较 ORACLE会自动将字符型用to number 函数进行转换 从而导致全表扫描 例2 表tab1中的列col1是字符型 char 则以下语句存在类型转换 selectcol1 col2fromtab1wherecol1 10 应该写为 selectcol1 col2fromtab1wherecol1 10 SQL优化 oracle 增加查询的范围限制增加查询的范围限制 避免全范围的搜索 例3 以下查询表record中时间ActionTime小于2001年3月1日的数据 select fromrecordwhereActionTime to date 20010301 yyyymm 查询计划表明 上面的查询对表进行全表扫描 如果我们知道表中的最早的数据为2001年1月1日 那么 可以增加一个最小时间 使查询在一个完整的范围之内 修改如下 SQL优化 oracle 增加查询的范围限制select fromrecordwhereActionTimeto date 20010101 yyyymm 后一种SQL语句将利用上ActionTime字段上的索引 从而提高查询效率 把 20010301 换成一个变量 根据取值的机率 可以有一半以上的机会提高效率 同理 对于大于某个值的查询 如果知道当前可能的最大值 也可以在Where子句中加上 AND列名 MAX 最大值 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 尽量去掉 尽量去掉 避免全表扫描 如果数据是枚举值 且取值范围固定 则修改为 OR 方式 例5 UPDATESERVICEINFOSETSTATE 0WHERESTATE0 以上语句由于其中包含了 执行计划中用了全表扫描 TABLEACCESSFULL 没有用到state字段上的索引 实际应用中 由于业务逻辑的限制 字段state为枚举值 只能等于0 1或2 而且 值等于 1 2的很少 因此可以去掉 利用索引来提高效率 修改为 UPDATESERVICEINFOSETSTATE 0WHERESTATE 1ORSTATE 2 进一步的修改可以参考第4种方法 SQL优化 oracle 去掉Where子句中的ISNULL和ISNOTNULLWhere字句中的ISNULL和ISNOTNULL将不会使用索引而是进行全表搜索 因此需要通过改变查询方式 分情况讨论等方法 去掉Where子句中的ISNULL和ISNOTNULL SQL优化 oracle 索引提高数据分布不均匀时查询效率索引的选择性低 但数据的值分布差异很大时 仍然可以利用索引提高效率 A 数据分布不均匀的特殊情况下 选择性不高的索引也要创建 表ServiceInfo中数据量很大 假设有一百万行 其中有一个字段DisposalCourseFlag 取值范围为枚举值 0 1 2 3 4 5 6 7 按照前面说的索引建立的规则 选择性不高的字段不应该建立索引 该字段只有8种取值 索引值的重复率很高 索引选择性明显很低 因此不建索引 然而 由于该字段上数据值的分布情况非常特殊 具体如下表 SQL优化 oracle 索引提高数据分布不均匀时查询效率而且 常用的查询中 查询DisposalCourseFlag 6的情况既多又频繁 毫无疑问 如果能够建立索引 并且被应用 那么将大大提高这种情况的查询效率 因此 我们需要在该字段上建立索引 SQL优化 oracle 利用HINT强制指定索引在ORACLE优化器无法用上合理索引的情况下 利用HINT强制指定索引 继续上面7的例子 ORACLE缺省认定 表中列的值是在所有数据行中均匀分布的 也就是说 在一百万数据量下 每种DisposalCourseFlag值各有12 5万数据行与之对应 假设SQL搜索条件DisposalCourseFlag 2 利用DisposalCourseFlag列上的索引进行数据搜索效率 往往不比全表扫描的高 ORACLE因此对索引 视而不见 从而在查询路径的选择中 用其他字段上的索引甚至全表扫描 根据我们上面的分析 数据值的分布很特殊 严重的不均匀 SQL优化 oracle 利用HINT强制指定索引为了利用索引提高效率 此时 一方面可以单独对该字段或该表用analyze语句进行分析 对该列搜集足够的统计数据 使ORACLE在查询选择性较高的值时能用上索引 另一方面 可以利用HINT提示 在SELECT关键字后面 加上 INDEX 表名称 索引名称 的方式 强制ORACLE优化器用上该索引 比如 select fromserviceinfowhereDisposalCourseFlag 1 SQL优化 oracle 利用HINT强制指定索引上面的语句 实际执行中ORACLE用了全表扫描 加上蓝色提示部分后 用到索引查询 如下 select INDEX SERVICEINFO IX S DISPOSALCOURSEFLAG fromserviceinfowhereDisposalCourseFlag 1 请注意 这种方法会加大代码维护的难度 而且该字段上索引的名称被改变之后 必须要同步所有指定索引的HINT代码 否则HINT提示将被ORACLE忽略掉 SQL优化 oracle 屏蔽无用索引继续上面8的例子 由于实际查询中 还有涉及到DisposalCourseFlag 6的查询 而此时如果用上该字段上的索引 将是非常不明智的 效率也极低 因此这种情况下 我们需要用特殊的方法屏蔽该索引 以便ORACLE选择其他字段上的索引 比如 如果字段为数值型的就在表达式的字段名后 添加 0 为字符型的就并上空串 如 select fromserviceinfowhereDisposalCourseFlag 0 6andworkNo 36 不过 不要把该用的索引屏蔽掉了 否则同样会产生低效率的全表扫描 SQL优化 oracle 分解复杂查询 用常量代替变量对于复杂的Where条件组合 Where中含有多个带索引的字段 考虑用IF语句分情况进行讨论 同时 去掉不必要的外来参数条件 减低复杂度 以便在不同情况下用不同字段上的索引 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 like子句尽量前端匹配因为like参数使用的非常频繁 因此如果能够对like子句使用索引 将很高的提高查询的效率 例6 select fromcitywherenamelike S 以上查询的执行计划用了全表扫描 TABLEACCESSFULL 如果能够修改为 select fromcitywherenamelike S 那么查询的执行计划将会变成 INDEXRANGESCAN 成功的利用了name字段的索引 这意味着OracleSQL优化器会识别出用于索引的like子句 只要该查询的匹配端是具体值 因此我们在做like查询时 应该尽量使查询的匹配端是具体值 即使用like S SQL优化 oracle 用Case语句合并多重扫描我们常常必须基于多组数据表计算不同的聚集 例如下例通过三个独立查询 例8 1 selectcount fromempwheresal5000 这样我们需要进行三次全表查询 但是如果我们使用case语句 SQL优化 oracle 用Case语句合并多重扫描selectcount salewhensal5000then1elsenullend count poorfromemp 这样查询的结果一样 但是执行计划只进行了一次全表查询 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 使用基于函数的索引前面谈到任何对列的操作都可能导致全表扫描 例如 select fromempwheresubstr ename 1 2 SM 但是这种查询在客服系统又经常使用 我们可以创建一个带有substr函数的基于函数的索引 createindexemp ename substroneemp substr ename 1 2 这样在执行上面的查询语句时 这个基于函数的索引将排上用场 执行计划将是 INDEXRANGESCAN SQL优化 oracle 基于函数的索引要求等式匹配上面的例子中 我们创建了基于函数的索引 但是如果执行下面的查询 select fromempwheresubstr ename 1 1 S 得到的执行计划将还是 TABLEACCESSFULL 因为只有当数据列能够等式匹配时 基于函数的索引才能生效 这样对于这种索引的计划和维护的要求都很高 请注意 向表中添加索引是非常危险的操作 因为这将导致许多查询执行计划的变更 然而 如果我们使用基于函数的索引就不会产生这样的问题 因为Oracle只有在查询使用了匹配的内置函数时才会使用这种类型的索引 SQL优化 oracle 使用分区索引在用分析命令对分区索引进行分析时 每一个分区的数据值的范围信息会放入Oracle的数据字典中 Oracle可以利用这个信息来提取出那些只与SQL查询相关的数据分区 例如 假设你已经定义了一个分区索引 并且某个SQL语句需要在一个索引分区中进行一次索引扫描 Oracle会仅仅访问这个索引分区 而且会在这个分区上调用一个此索引范围的快速全扫描 因为不需要访问整个索引 所以提高了查询的速度 SQL优化 oracle 使用位图索引位图索引可以从本质上提高使用了小于1000个唯一数据值的数据列的查询速度 因为在位图索引中进行的检索是在RAM中完成的 而且也总是比传统的B树索引的速度要快 对于那些少于1000个唯一数据值

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论