﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-够了,让我们实践吧..-随笔分类-Oracle</title><link>http://www.blogjava.net/zhuzi1987/category/33216.html</link><description>JAVA+YOU!中国的开发者们加油!!</description><language>zh-cn</language><lastBuildDate>Fri, 05 Dec 2008 21:15:59 GMT</lastBuildDate><pubDate>Fri, 05 Dec 2008 21:15:59 GMT</pubDate><ttl>60</ttl><item><title>【转】T-SQL 编码标准--对ORACLE开发也很有启发</title><link>http://www.blogjava.net/zhuzi1987/archive/2008/12/02/243866.html</link><dc:creator>竹子</dc:creator><author>竹子</author><pubDate>Tue, 02 Dec 2008 02:50:00 GMT</pubDate><guid>http://www.blogjava.net/zhuzi1987/archive/2008/12/02/243866.html</guid><wfw:comment>http://www.blogjava.net/zhuzi1987/comments/243866.html</wfw:comment><comments>http://www.blogjava.net/zhuzi1987/archive/2008/12/02/243866.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhuzi1987/comments/commentRss/243866.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhuzi1987/services/trackbacks/243866.html</trackback:ping><description><![CDATA[<h1>T-SQL 编码标准</h1>
<h2 class="subtitle"></h2>
<div class="date">发布日期： 4/15/2005<span class="datePipe"> | </span>更新日期： 4/15/2005</div>
<div class="overview">
<p><em>Brian Walker</em></p>
<p><strong>可能让人觉得很奇怪，但好像的确没有什么</strong><strong>&#8220;</strong><strong>正式的</strong><strong>&#8221;T-SQL </strong><strong>编码标准。早在</strong><strong> 1999 </strong><strong>年末的时候，我惊喜地发现</strong><strong> John Hindmarsh </strong><strong>提出的</strong><strong> SQL Server 7.0 </strong><strong>标准，我在</strong><strong> 2000 </strong><strong>年</strong><strong> 2 </strong><strong>月的社论中对他的某些建议进行了总结。（</strong><strong>2000 </strong><strong>年</strong><strong> 2 </strong><strong>月以及本月的</strong><strong>&#8220;</strong><strong>下载</strong><strong>&#8221;</strong><strong>中都包括了</strong><strong> John </strong><strong>原来的标准。）后来，</strong><strong>Ron Talmage </strong><strong>撰写了一系列专栏文章，提出了他对各种</strong><strong>&#8220;</strong><strong>最佳方法</strong><strong>&#8221;</strong><strong>的建议，当然，</strong><strong>SQL Server </strong><strong>小组也已正式发布了</strong><strong> SQL Server </strong><strong>最佳方法分析器</strong><strong> (SQLBPA)</strong><strong>。现在，一位具有超过</strong><strong> 25 </strong><strong>年经验的数据库管理员和应用程序开发员</strong><strong> Brian Walker </strong><strong>又提出了他的建议和提示。</strong></p>
</div>
<center><img title="" height="6" alt="*" src="http://img.microsoft.com/library/gallery/templates/MNP2.Common/images/3squares.gif" width="30" border="0" /></center>
<div style="height: 18px"></div>
<p>进行 T-SQL 编程时常常会忽略编码标准，但这些标准却是开发小组顺利开展工作的关键工具。这里介绍的编码标准是我多年的开发成果。它们当然还没有得到普遍接受，而且不可否认，有些标准带有主观色彩。我的目的实际上更多的是为了提高大家的意识，而不是吹捧自己是 T-SQL 样式方面的仲裁者：最重要的是要建立某些合理的编码标准并遵循这些标准。您在这篇文章中会发现有关 T-SQL 编程的一系列不同的编码标准、技巧和提示。它们并未以任何特定的优先级或重要性顺序列出。</p>
<p>让我们从格式开始。表面上，T-SQL 代码的格式似乎并不重要，但一致的格式可以使您的同事（不论是同一小组的成员还是更大范围的 T-SQL 开发团队的成员）更轻松地浏览和理解您的代码。T-SQL 语句有一个结构，遵循一目了然的结构使您可以更轻松地查找和确认语句的不同部分。统一的格式还使您可以更轻松地在复杂 T-SQL 语句中增删代码段，使调试工作变得更容易。下面是 SELECT 语句的格式示例：</p>
<pre class="codeSample">       SELECT C.Name
, E.NameLast
, E.NameFirst
, E.Number
, ISNULL(I.Description,'NA') AS Description
FROM tblCompany AS C
JOIN tblEmployee AS E
ON C.CompanyID = E.CompanyID
LEFT JOIN tblCoverage AS V
ON E.EmployeeID = V.EmployeeID
LEFT JOIN tblInsurance AS I
ON V.InsuranceID = I.InsuranceID
WHERE C.Name LIKE @Name
AND V.CreateDate &gt; CONVERT(smalldatetime,
'01/01/2000')
ORDER BY C.Name
, E.NameLast
, E.NameFirst
, E.Number
, ISNULL(I.Description,'NA')
SELECT @Retain = @@ERROR, @Rows = @@ROWCOUNT
IF @Status = 0 SET @Status = @Retain
</pre>
<p>►一个嵌套代码块中的语句使用四个空格的缩进。（上述代码中的多行 SELECT 语句是一个 SQL 语句。）在同一语句中开始新行时，使 SQL 关键字右对齐。将代码编辑器配置为使用空格，而不是使用制表符。这样，不管使用何种程序查看代码，格式都是一致的。</p>
<p>►大写所有的 T-SQL 关键字，包括 T-SQL 函数。变量名称及光标名称使用混和大小写。数据类型使用小写。</p>
<p>►表名别名要简短，但意义要尽量明确。通常，使用大写的表名作为别名，使用 AS 关键字指定表或字段的别名。</p>
<p>►当一个 T-SQL 语句中涉及到多个表时，始终使用表名别名来限定字段名。这使其他人阅读起来更清楚，避免了含义模糊的引用。</p>
<p>►当相关数字出现在连续的代码行中时（例如一系列 SUBSTRING 函数调用），将它们排成列。这样容易浏览数字列表。</p>
<p>►使用一个（而不是两个）空行分隔 T-SQL 代码的逻辑块，只要需要就可以使用。</p>
<p>►声明 T-SQL 局部变量（例如 @lngTableID）时，使用适当的数据类型声明和一致的大写。</p>
<p>►<strong>始终</strong>指定字符数据类型的长度，并确保允许用户可能需要的最大字符数，因为超出最大长度的字符会丢失。</p>
<p>►<strong>始终</strong>指定十进制数据类型的精度和范围，否则，将默认为未指定精度和整数范围。 </p>
<p>►使用错误处理程序，但要记住行首 (BOL) 中的错误检查示例不会象介绍的那样起作用。用来检查 @@ERROR 系统函数的 T-SQL 语句 (IF) 实际上在进程中清除了 @@ERROR 值，无法再捕获除零之外的任何值。（即使示例起作用，它们也只能捕获最后发生的一个错误，而不是您更想捕获的第一个错误。）必须使用 SET 或 SELECT 立即捕获错误代码，如前面示例所示。如果状态变量仍然为零，应转换到状态变量。 </p>
<p>►避免使用&#8220;未声明的&#8221;功能，例如系统表中未声明的列、T-SQL 语句中未声明的功能或者未声明的系统存储过程或扩展的存储过程。 </p>
<p>►<strong>不要</strong>依赖任何隐式的数据类型转换。例如，不能为数字变量赋予字符值，而假定 T-SQL 会进行必要的转换。相反，在为变量赋值或比较值之前，应使用适当的 CONVERT 函数使数据类型相匹配。另一个示例：虽然 T-SQL 会在进行比较之前对字符表达式进行隐式且自动的 RTRIM，但不能依赖此行为，因为兼容性级别设置非字符表达式会使情况复杂化。</p>
<p>►<strong>不要</strong>将空的变量值直接与比较运算符（符号）比较。如果变量可能为空，应使用 IS NULL 或 IS NOT NULL 进行比较，或者使用 ISNULL 函数。</p>
<p>►不要使用 STR 函数进行舍入，此函数只能用于整数。如果需要十进制值的字符串形式，应先使用 CONVERT 函数（转至不同的范围）或 ROUND 函数，然后将其转换为字符串。也可以使用 CEILING 和 FLOOR 函数。</p>
<p>►使用数学公式时要小心，因为 T-SQL 可能会将表达式强制理解为一个不需要的数据类型。如果需要十进制结果，应在整数常量后加点和零 (.0)。</p>
<p>►决不要依赖 SELECT 语句会按任何特定顺序返回行，除非在 ORDER BY 子句中指定了顺序。</p>
<p>►通常，应将 ORDER BY 子句与 SELECT 语句一起使用。可预知的顺序（即使不是最方便的）比不可预知的顺序强，尤其是在开发或调试过程中。（部署到生产环境中之前，可能需要删除 ORDER BY 子句。）在返回行的顺序无关紧要的情况下，可以忽略 ORDER BY 的开销。</p>
<p>►不要在 T-SQL 代码中使用双引号。应为字符常量使用单引号。如果没有必要限定对象名称，可以使用（非 ANSI SQL 标准）括号将名称括起来。</p>
<p>►在 SQL Server 2000 中，尽量使用表变量来代替临时表。如果表变量包含大量数据，请注意索引非常有限（只有主键索引）。</p>
<p>►先在例程中创建临时表，最后再显式删除临时表。将 DDL 与 DML 语句混合使用有助于处理额外的重新编译活动。</p>
<p>►要认识到临时表<strong>并不是</strong>不可使用，适当地使用它们可以使某些例程更有效，例如，当需要重复引用大型表或常用表中的某个数据集时。但是，对于一次性事件，最好使用导出表。 </p>
<p><em>►</em>使用表值 UDF 时要小心，因为在变量（而不是常量）中传递某个参数时，如果在 WHERE 子句中使用该参数，会导致表扫描。还要避免在一个查询中多次使用相同的表值 UDF。但是，表值 UDF 确实具有某些非常方便的动态编译功能。<em>[</em><em>相关资料：参阅</em><em> Tom Moreau </em><em>在</em><em> 2003 </em><em>年</em><em> 11 </em><em>月份</em><em>&#8220;</em><em>生成序列号</em><em>&#8221;</em><em>专栏中的</em><em>&#8220;</em><em>使用</em><em> UDF </em><em>填充表变量</em><em>&#8221;</em><em>。－</em><em></em><em>编者按］</em></p>
<p>►几乎所有的存储过程都应在开始时设置 SET NOCOUNT ON，而在结束时设置 SET NOCOUNT OFF。<em>[SET NOCOUNT ON </em><em>使</em><em> SQL Server </em><em>无需在执行存储过程的每个语句后向客户端发送</em><em> DONE_IN_PROC </em><em>消息。</em><em>- </em><em>编者按</em><em>] </em>此标准同样适用于触发器。</p>
<p>►只要在例程中使用多个数据库修改语句，包括在一个循环中多次执行一个语句，就应考虑声明显式事务。</p>
<p>►使用基于光标的方法或临时表方法之前，应先寻找基于集的解决方案来解决问题。基于集的方法通常更有效。</p>
<p>►与临时表一样，光标并不是不可使用。对小型数据集使用 FAST_FORWARD 光标通常要优于其他逐行处理方法，尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括&#8220;合计&#8221;的例程通常要比使用光标执行的速度快。如果开发时间允许，基于光标的方法和基于集的方法都可以尝试一下，看哪一种方法的效果更好。</p>
<p>►使用包含序号（从 1 到 N）的表很方便。</p>
<p>►理解 CROSS JOIN 的工作原理并加以利用。例如，您可以在工作数据表和序号表之间有效地使用 CROSS JOIN，结果集中将包含每个工作数据与序号组合的记录。 </p>
<p>►我的结束语是：T-SQL 代码往往很简洁，因此如果某个代码块看起来很难处理或重复内容较多，那么可能存在一种更简单，更好的方法。 </p>
<p><strong>结论</strong></p>
<p>如果您对我的建议有任何看法，欢迎随时向我发送电子邮件进行讨论，也可以就其他问题提出您的建议。我希望您将此作为谈话的开场白。 </p>
<p><strong>其他信息：摘自</strong><strong> Karen 2000 </strong><strong>年</strong><strong> 2 </strong><strong>月份的社论</strong></p>
<p>在标准开发的前沿阵地上，有一股以 SQL Server 数据库管理员 John Hindmarsh 为首的独立的新生力量。MCT、MCSE 和 MCDBA 都是最值得您花时间去研究的。John 的贡献是撰写了一份详细的白皮书，概述了他对各种 SQL Server 相关标准提出的建议。我所知道的其他唯一提出类似建议的文章是 Andrew Zanevsky 的《Transact-SQL Programming》(ISBN 1-56592-401-0) 中的&#8220;Format and Style&#8221;一章。Andrew、SQL Server Professional 的投稿人 Tom Moreau 和 Paul Munkenbeck 以及 John 的朋友兼同事 Stephen James 都为 John 的白皮书做出过贡献。下面是 John 为编写存储过程提供的建议示例：</p>
<table cellspacing="0" cellpadding="0" border="0">
    <tbody>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>使用 SQL-92 标准连接句法。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>为了提高性能，应优先使用连接，然后使用子查询或嵌套查询。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>确保变量和参数的类型和大小与表数据列相匹配。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>确保使用所有变量和参数，或者全部删除。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>尽可能将临时对象放置在本地。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>只使用在存储过程中创建的临时表。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>检查输入参数的有效性。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>优先使用 SELECT...INTO，然后使用 INSERT...SELECT，以避免大量死锁。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>维护工作需要的逻辑单元；在可以缩短的情况下，不要创建大量或长时间运行的进程。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>不要在任何代码中使用 SELECT *。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>在过程中使用缩进、块、制表符和空格（参阅示例脚本）。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>T-SQL 语句要大写。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>在过程中添加大量注释，确保可以识别进程。在有助于澄清处理步骤的地方使用行注释。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>包括事务管理，除非要从 MTS 进程中调用过程。（为 MTS 进程编写独立的过程。） </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>监视 @@TRANCOUNT 以确定事务的责任级别。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>避免使用 GOTO，错误处理程序中除外。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>避免使用嵌套过程。 </p>
            </td>
        </tr>
        <tr>
            <td class="listBullet" valign="top">&#8226;</td>
            <td class="listItem">
            <p>避免隐式解析对象名称，确保所有对象都归 dbo 所有。 </p>
            </td>
        </tr>
    </tbody>
</table>
<p><a href="http://download.microsoft.com/download/5/d/3/5d32aa05-5b4a-4ec7-8a3b-de511fedde38/SQL04-12Brian.exe"><em>下载</em><em> 412BRIAN.ZIP</em></a></p>
<p><strong>链接至</strong><strong></strong><a href="http://www.microsoft.com/downloads/details.aspx?displayla%20ng=en&amp;familyid=B352EB1F-D3CA-44EE-893E-9E07339C1F22&amp;displaylang=en"><em>www.microsoft.com/downloads/details.aspx?displayla%20ng=en&amp;familyid=B352EB1F-D3CA-44EE-893E-9E07339C1F22&amp;displaylang=en</em></a></p>
<p>有关 SQL Server Professional 和 Pinnacle Publishing 的详细信息，请访问其 Web 站点 <a href="http://www.pinpub.com/"><em>http://www.pinpub.com/</em></a></p>
<p>注意：这不是 Microsoft Corporation 的 Web 站点。Microsoft 对该 Web 站点上的内容不承担任何责任。</p>
<p>本文转载自 2004 年 12 月份的 SQL Server Professional。除非另行说明，否则版权所有 2004 Pinnacle Publishing, Inc.。保留所有权利。SQL Server Professional 是 Pinnacle Publishing 独立发行的刊物。未经 Pinnacle Publishing, Inc. 事先同意，不得以任何方式使用或复制本文的任何部分（评论文章中的简短引用除外）。如需与 Pinnacle Publishing, Inc. 联系，请拨打 1-800-788-1900。</p>
<p><a href="http://www.microsoft.com/info/cpyright.mspx" target="_blank">&#169; 2005 Microsoft Corporation 版权所有。保留所有权利。使用规定。</a><br />
<br />
原文出处:<font style="color: #800000; background-color: #c4ecc9">http://www.microsoft.com/china/msdn/library/data/sqlserver/sp04l9.mspx?mfr=true</font></p>
<img src ="http://www.blogjava.net/zhuzi1987/aggbug/243866.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhuzi1987/" target="_blank">竹子</a> 2008-12-02 10:50 <a href="http://www.blogjava.net/zhuzi1987/archive/2008/12/02/243866.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL优化34条—开发必备</title><link>http://www.blogjava.net/zhuzi1987/archive/2008/12/02/243864.html</link><dc:creator>竹子</dc:creator><author>竹子</author><pubDate>Tue, 02 Dec 2008 02:42:00 GMT</pubDate><guid>http://www.blogjava.net/zhuzi1987/archive/2008/12/02/243864.html</guid><wfw:comment>http://www.blogjava.net/zhuzi1987/comments/243864.html</wfw:comment><comments>http://www.blogjava.net/zhuzi1987/archive/2008/12/02/243864.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhuzi1987/comments/commentRss/243864.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhuzi1987/services/trackbacks/243864.html</trackback:ping><description><![CDATA[<span style="color: red"><span style="color: #800000">&nbsp; </span></span><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>1<span style="font-family: 宋体">）</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">选择最有效率的表名顺序</span>(<span style="font-family: 宋体">只在基于规则的优化器中有效</span>)<span style="font-family: 宋体">：</span></span></span>
<p><span style="color: red"><span style="color: #800000">ORACLE <span style="font-family: 宋体">的解析器按照从右到左的顺序处理</span>FROM<span style="font-family: 宋体">子句中的表名，</span>FROM<span style="font-family: 宋体">子句中写在最后的表</span>(<span style="font-family: 宋体">基础表</span> driving table)<span style="font-family: 宋体">将被最先处理，在</span>FROM<span style="font-family: 宋体">子句中包含多个表的情况下</span>,<span style="font-family: 宋体">你必须选择记录条数最少的表作为基础表。如果有</span>3<span style="font-family: 宋体">个以上的表连接查询</span>, <span style="font-family: 宋体">那就需要选择交叉表</span>(intersection table)<span style="font-family: 宋体">作为基础表</span>, <span style="font-family: 宋体">交叉表是指那个被其他表所引用的表</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>2<span style="font-family: 宋体">）</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE<span style="font-family: 宋体">子句中的连接顺序．：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">ORACLE<span style="font-family: 宋体">采用自下而上的顺序解析</span>WHERE<span style="font-family: 宋体">子句</span>,<span style="font-family: 宋体">根据这个原理</span>,<span style="font-family: 宋体">表之间的连接必须写在其他</span>WHERE<span style="font-family: 宋体">条件之前</span>, <span style="font-family: 宋体">那些可以过滤掉最大数量记录的条件必须写在</span>WHERE<span style="font-family: 宋体">子句的末尾</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>3<span style="font-family: 宋体">）</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT<span style="font-family: 宋体">子句中避免使用</span> <span style="font-family: 宋体">&#8216;</span> * <span style="font-family: 宋体">&#8216;：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">ORACLE<span style="font-family: 宋体">在解析的过程中</span>, <span style="font-family: 宋体">会将</span>'*' <span style="font-family: 宋体">依次转换成所有的列名</span>, <span style="font-family: 宋体">这个工作是通过查询数据字典完成的</span>, <span style="font-family: 宋体">这意味着将耗费更多的时间</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>4<span style="font-family: 宋体">）</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">减少访问数据库的次数：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">ORACLE<span style="font-family: 宋体">在内部执行了许多工作</span>: <span style="font-family: 宋体">解析</span>SQL<span style="font-family: 宋体">语句</span>, <span style="font-family: 宋体">估算索引的利用率</span>, <span style="font-family: 宋体">绑定变量</span> , <span style="font-family: 宋体">读数据块等；</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>5<span style="font-family: 宋体">）</span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: 宋体">在</span>SQL*Plus , SQL*Forms<span style="font-family: 宋体">和</span>Pro*C<span style="font-family: 宋体">中重新设置</span>ARRAYSIZE<span style="font-family: 宋体">参数</span>, <span style="font-family: 宋体">可以增加每次数据库访问的检索数据量</span> ,<span style="font-family: 宋体">建议值为</span>200</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>6<span style="font-family: 宋体">）</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">使用</span>DECODE<span style="font-family: 宋体">函数来减少处理时间：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">使用</span>DECODE<span style="font-family: 宋体">函数可以避免重复扫描相同记录或重复连接相同的表</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>7<span style="font-family: 宋体">）</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">整合简单</span>,<span style="font-family: 宋体">无关联的数据库访问：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">如果你有几个简单的数据库查询语句</span>,<span style="font-family: 宋体">你可以把它们整合到一个查询中</span>(<span style="font-family: 宋体">即使它们之间没有关系</span>)</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>8<span style="font-family: 宋体">）</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">删除重复记录：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">最高效的删除重复记录方法</span> ( <span style="font-family: 宋体">因为使用了</span>ROWID)<span style="font-family: 宋体">例子：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">DELETE&nbsp;FROM&nbsp;EMP E&nbsp;WHERE&nbsp;E.ROWID &gt; (SELECT MIN(X.ROWID) </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM&nbsp;EMP X&nbsp;WHERE&nbsp;X.EMP_NO = E.EMP_NO);</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>9<span style="font-family: 宋体">）</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">用</span>TRUNCATE<span style="font-family: 宋体">替代</span>DELETE<span style="font-family: 宋体">：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">当删除表中的记录时</span>,<span style="font-family: 宋体">在通常情况下</span>, <span style="font-family: 宋体">回滚段</span>(rollback segments ) <span style="font-family: 宋体">用来存放可以被恢复的信息</span>. <span style="font-family: 宋体">如果你没有</span>COMMIT<span style="font-family: 宋体">事务</span>,ORACLE<span style="font-family: 宋体">会将数据恢复到删除之前的状态</span>(<span style="font-family: 宋体">准确地说是恢复到执行删除命令之前的状况</span>) <span style="font-family: 宋体">而当运用</span>TRUNCATE<span style="font-family: 宋体">时</span>, <span style="font-family: 宋体">回滚段不再存放任何可被恢复的信息</span>.<span style="font-family: 宋体">当命令运行后</span>,<span style="font-family: 宋体">数据不能被恢复</span>.<span style="font-family: 宋体">因此很少的资源被调用</span>,<span style="font-family: 宋体">执行时间也会很短</span>. (<span style="font-family: 宋体">译者按</span>: TRUNCATE<span style="font-family: 宋体">只在删除全表适用</span>,TRUNCATE<span style="font-family: 宋体">是</span>DDL<span style="font-family: 宋体">不是</span>DML)</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>10<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">尽量多使用</span>COMMIT<span style="font-family: 宋体">：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">只要有可能</span>,<span style="font-family: 宋体">在程序中尽量多使用</span>COMMIT, <span style="font-family: 宋体">这样程序的性能得到提高</span>,<span style="font-family: 宋体">需求也会因为</span>COMMIT<span style="font-family: 宋体">所释放的资源而减少</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">COMMIT<span style="font-family: 宋体">所释放的资源</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">a. <span style="font-family: 宋体">回滚段上用于恢复数据的信息</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000">b. <span style="font-family: 宋体">被程序语句获得的锁</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">c. redo log buffer <span style="font-family: 宋体">中的空间</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">d. ORACLE<span style="font-family: 宋体">为管理上述</span>3<span style="font-family: 宋体">种资源中的内部花费</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>11<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">用</span>Where<span style="font-family: 宋体">子句替换</span>HAVING<span style="font-family: 宋体">子句：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">避免使用</span>HAVING<span style="font-family: 宋体">子句</span>, HAVING <span style="font-family: 宋体">只会在检索出所有记录之后才对结果集进行过滤</span>. <span style="font-family: 宋体">这个处理需要排序</span>,<span style="font-family: 宋体">总计等操作</span>. <span style="font-family: 宋体">如果能通过</span>WHERE<span style="font-family: 宋体">子句限制记录的数目</span>,<span style="font-family: 宋体">那就能减少这方面的开销</span>. (<span style="font-family: 宋体">非</span>oracle<span style="font-family: 宋体">中</span>)on<span style="font-family: 宋体">、</span>where<span style="font-family: 宋体">、</span>having<span style="font-family: 宋体">这三个都可以加条件的子句中，</span>on<span style="font-family: 宋体">是最先执行，</span>where<span style="font-family: 宋体">次之，</span>having<span style="font-family: 宋体">最后，因为</span>on<span style="font-family: 宋体">是先把不符合条件的记录过滤后才进行统计，它就可以减少中间运算要处理的数据，按理说应该速度是最快的，</span>where<span style="font-family: 宋体">也应该比</span>having<span style="font-family: 宋体">快点的，因为它过滤数据后才进行</span>sum<span style="font-family: 宋体">，在两个表联接时才用</span>on<span style="font-family: 宋体">的，所以在一个表的时候，就剩下</span>where<span style="font-family: 宋体">跟</span>having<span style="font-family: 宋体">比较了。在这单表查询统计的情况下，如果要过滤的条件没有涉及到要计算字段，那它们的结果是一样的，只是</span>where<span style="font-family: 宋体">可以使用</span>rushmore<span style="font-family: 宋体">技术，而</span>having<span style="font-family: 宋体">就不能，在速度上后者要慢如果要涉及到计算的字段，就表示在没计算之前，这个字段的值是不确定的，根据上篇写的工作流程，</span>where<span style="font-family: 宋体">的作用时间是在计算之前就完成的，而</span>having<span style="font-family: 宋体">就是在计算后才起作用的，所以在这种情况下，两者的结果会不同。在多表联接查询时，</span>on<span style="font-family: 宋体">比</span>where<span style="font-family: 宋体">更早起作用。系统首先根据各个表之间的联接条件，把多个表合成一个临时表后，再由</span>where<span style="font-family: 宋体">进行过滤，然后再计算，计算完后再由</span>having<span style="font-family: 宋体">进行过滤。由此可见，要想过滤条件起到正确的作用，首先要明白这个条件应该在什么时候起作用，然后再决定放在那里</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>12<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">减少对表的查询：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">在含有子查询的</span>SQL<span style="font-family: 宋体">语句中</span>,<span style="font-family: 宋体">要特别注意减少对表的查询</span>.<span style="font-family: 宋体">例子：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">&nbsp;&nbsp;&nbsp;&nbsp; SELECT&nbsp;TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT</span></span></p>
<p><span style="color: red"><span style="color: #800000">TAB_NAME,DB_VER FROM&nbsp;TAB_COLUMNS&nbsp;WHERE&nbsp;VERSION = 604)</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>13<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">通过内部函数提高</span>SQL<span style="font-family: 宋体">效率</span>.<span style="font-family: 宋体">：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">复杂的</span>SQL<span style="font-family: 宋体">往往牺牲了执行效率</span>. <span style="font-family: 宋体">能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>14<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">使用表的别名</span>(Alias)<span style="font-family: 宋体">：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">当在</span>SQL<span style="font-family: 宋体">语句中连接多个表时</span>, <span style="font-family: 宋体">请使用表的别名并把别名前缀于每个</span>Column<span style="font-family: 宋体">上</span>.<span style="font-family: 宋体">这样一来</span>,<span style="font-family: 宋体">就可以减少解析的时间并减少那些由</span>Column<span style="font-family: 宋体">歧义引起的语法错误</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>15<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">用</span>EXISTS<span style="font-family: 宋体">替代</span>IN<span style="font-family: 宋体">、用</span>NOT EXISTS<span style="font-family: 宋体">替代</span>NOT IN<span style="font-family: 宋体">：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">在许多基于基础表的查询中</span>,<span style="font-family: 宋体">为了满足一个条件</span>,<span style="font-family: 宋体">往往需要对另一个表进行联接</span>.<span style="font-family: 宋体">在这种情况下</span>, <span style="font-family: 宋体">使用</span>EXISTS(<span style="font-family: 宋体">或</span>NOT EXISTS)<span style="font-family: 宋体">通常将提高查询的效率</span>. <span style="font-family: 宋体">在子查询中</span>,NOT IN<span style="font-family: 宋体">子句将执行一个内部的排序和合并</span>. <span style="font-family: 宋体">无论在哪种情况下</span>,NOT IN<span style="font-family: 宋体">都是最低效的</span> (<span style="font-family: 宋体">因为它对子查询中的表执行了一个全表遍历</span>). <span style="font-family: 宋体">为了避免使用</span>NOT IN ,<span style="font-family: 宋体">我们可以把它改写成外连接</span>(Outer Joins)<span style="font-family: 宋体">或</span>NOT EXISTS.</span></span></p>
<p><span style="font-family: 宋体"><span style="color: red"><span style="color: #800000">例子：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（高效）</span>SELECT * FROM&nbsp;EMP (<span style="font-family: 宋体">基础表</span>)&nbsp;WHERE&nbsp;EMPNO &gt; 0&nbsp;AND&nbsp;EXISTS (SELECT <span style="font-family: 宋体">&#8216;</span>X'&nbsp;FROM DEPT&nbsp;WHERE&nbsp;DEPT.DEPTNO = EMP.DEPTNO&nbsp;AND&nbsp;LOC = <span style="font-family: 宋体">&#8216;</span>MELB')</span></span></p>
<p><span style="color: red"><span style="color: #800000">(<span style="font-family: 宋体">低效</span>)SELECT&nbsp;* FROM&nbsp;EMP (<span style="font-family: 宋体">基础表</span>)&nbsp;WHERE&nbsp;EMPNO &gt; 0&nbsp;AND&nbsp;DEPTNO IN(SELECT DEPTNO&nbsp;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;LOC = <span style="font-family: 宋体">&#8216;</span>MELB')</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>16<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">识别</span>'<span style="font-family: 宋体">低效执行</span>'<span style="font-family: 宋体">的</span>SQL<span style="font-family: 宋体">语句：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">虽然目前各种关于</span>SQL<span style="font-family: 宋体">优化的图形化工具层出不穷</span>,<span style="font-family: 宋体">但是写出自己的</span>SQL<span style="font-family: 宋体">工具来解决问题始终是一个最好的方法：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT&nbsp;EXECUTIONS , DISK_READS, BUFFER_GETS, </span></span></p>
<p><span style="color: red"><span style="color: #800000">ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio, </span></span></p>
<p><span style="color: red"><span style="color: #800000">ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run, </span></span></p>
<p><span style="color: red"><span style="color: #800000">SQL_TEXT </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM&nbsp;V$SQLAREA </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE&nbsp;EXECUTIONS&gt;0 </span></span></p>
<p><span style="color: red"><span style="color: #800000">AND&nbsp;BUFFER_GETS &gt; 0 </span></span></p>
<p><span style="color: red"><span style="color: #800000">AND&nbsp;(BUFFER_GETS-DISK_READS)/BUFFER_GETS &lt; 0.8 </span></span></p>
<p><span style="color: red"><span style="color: #800000">ORDER BY&nbsp;4 DESC;</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>17<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">用索引提高效率：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">索引是表的一个概念部分</span>,<span style="font-family: 宋体">用来提高检索数据的效率，</span>ORACLE<span style="font-family: 宋体">使用了一个复杂的自平衡</span>B-tree<span style="font-family: 宋体">结构</span>. <span style="font-family: 宋体">通常</span>,<span style="font-family: 宋体">通过索引查询数据比全表扫描要快</span>. <span style="font-family: 宋体">当</span>ORACLE<span style="font-family: 宋体">找出执行查询和</span>Update<span style="font-family: 宋体">语句的最佳路径时</span>, ORACLE<span style="font-family: 宋体">优化器将使用索引</span>. <span style="font-family: 宋体">同样在联结多个表时使用索引也可以提高效率</span>. <span style="font-family: 宋体">另一个使用索引的好处是</span>,<span style="font-family: 宋体">它提供了主键</span>(primary key)<span style="font-family: 宋体">的唯一性验证</span>.<span style="font-family: 宋体">。那些</span>LONG<span style="font-family: 宋体">或</span>LONG RAW<span style="font-family: 宋体">数据类型</span>, <span style="font-family: 宋体">你可以索引几乎所有的列</span>. <span style="font-family: 宋体">通常</span>, <span style="font-family: 宋体">在大型表中使用索引特别有效</span>. <span style="font-family: 宋体">当然</span>,<span style="font-family: 宋体">你也会发现</span>, <span style="font-family: 宋体">在扫描小表时</span>,<span style="font-family: 宋体">使用索引同样能提高效率</span>. <span style="font-family: 宋体">虽然使用索引能得到查询效率的提高</span>,<span style="font-family: 宋体">但是我们也必须注意到它的代价</span>. <span style="font-family: 宋体">索引需要空间来存储</span>,<span style="font-family: 宋体">也需要定期维护</span>, <span style="font-family: 宋体">每当有记录在表中增减或索引列被修改时</span>, <span style="font-family: 宋体">索引本身也会被修改</span>. <span style="font-family: 宋体">这意味着每条记录的</span>INSERT , DELETE , UPDATE<span style="font-family: 宋体">将为此多付出</span>4 , 5 <span style="font-family: 宋体">次的磁盘</span>I/O . <span style="font-family: 宋体">因为索引需要额外的存储空间和处理</span>,<span style="font-family: 宋体">那些不必要的索引反而会使查询反应时间变慢</span>.<span style="font-family: 宋体">。定期的重构索引是有必要的</span>.<span style="font-family: 宋体">：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">ALTER&nbsp;INDEX &lt;INDEXNAME&gt; REBUILD &lt;TABLESPACENAME&gt;</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>18<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">用</span>EXISTS<span style="font-family: 宋体">替换</span>DISTINCT<span style="font-family: 宋体">：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">当提交一个包含一对多表信息</span>(<span style="font-family: 宋体">比如部门表和雇员表</span>)<span style="font-family: 宋体">的查询时</span>,<span style="font-family: 宋体">避免在</span>SELECT<span style="font-family: 宋体">子句中使用</span>DISTINCT. <span style="font-family: 宋体">一般可以考虑用</span>EXIST<span style="font-family: 宋体">替换</span>, EXISTS <span style="font-family: 宋体">使查询更为迅速</span>,<span style="font-family: 宋体">因为</span>RDBMS<span style="font-family: 宋体">核心模块将在子查询的条件一旦满足后</span>,<span style="font-family: 宋体">立刻返回结果</span>. <span style="font-family: 宋体">例子：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (<span style="font-family: 宋体">低效</span>): </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT&nbsp;DISTINCT&nbsp;DEPT_NO,DEPT_NAME&nbsp;FROM&nbsp;DEPT D , EMP E </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE&nbsp;D.DEPT_NO = E.DEPT_NO </span></span></p>
<p><span style="color: red"><span style="color: #800000">(<span style="font-family: 宋体">高效</span>): </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT&nbsp;DEPT_NO,DEPT_NAME&nbsp;FROM&nbsp;DEPT D&nbsp;WHERE&nbsp;EXISTS ( SELECT &#8216;X' </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM&nbsp;EMP E&nbsp;WHERE E.DEPT_NO = D.DEPT_NO);</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>19<span style="font-family: 宋体">）</span> sql<span style="font-family: 宋体">语句用大写的；因为</span>oracle<span style="font-family: 宋体">总是先解析</span>sql<span style="font-family: 宋体">语句，把小写的字母转换成大写的再执行</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>20<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">在</span>java<span style="font-family: 宋体">代码中尽量少用连接符&#8220;＋&#8221;连接字符串！</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>21<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">避免在索引列上使用</span>NOT <span style="font-family: 宋体">通常，　</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">我们要避免在索引列上使用</span>NOT, NOT<span style="font-family: 宋体">会产生在和在索引列上使用函数相同的影响</span>. <span style="font-family: 宋体">当</span>ORACLE<span style="font-family: 宋体">&#8221;遇到&#8221;</span>NOT,<span style="font-family: 宋体">他就会停止使用索引转而执行全表扫描</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>22<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">避免在索引列上使用计算．</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE<span style="font-family: 宋体">子句中，如果索引列是函数的一部分．优化器将不使用索引而使用全表扫描．</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">举例</span>: </span></span></p>
<p><span style="font-family: 宋体"><span style="color: red"><span style="color: #800000">低效：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT &#8230; FROM&nbsp;DEPT&nbsp;WHERE SAL * 12 &gt; 25000; </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">高效</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT &#8230; FROM DEPT WHERE SAL &gt; 25000/12;</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>23<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">用</span>&gt;=<span style="font-family: 宋体">替代</span>&gt;</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">高效</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT * FROM&nbsp;EMP&nbsp;WHERE&nbsp;DEPTNO &gt;=4 </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">低效</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT * FROM EMP WHERE DEPTNO &gt;3 </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">两者的区别在于</span>, <span style="font-family: 宋体">前者</span>DBMS<span style="font-family: 宋体">将直接跳到第一个</span>DEPT<span style="font-family: 宋体">等于</span>4<span style="font-family: 宋体">的记录而后者将首先定位到</span>DEPTNO=3<span style="font-family: 宋体">的记录并且向前扫描到第一个</span>DEPT<span style="font-family: 宋体">大于</span>3<span style="font-family: 宋体">的记录</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>24<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">用</span>UNION<span style="font-family: 宋体">替换</span>OR (<span style="font-family: 宋体">适用于索引列</span>)</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">通常情况下</span>, <span style="font-family: 宋体">用</span>UNION<span style="font-family: 宋体">替换</span>WHERE<span style="font-family: 宋体">子句中的</span>OR<span style="font-family: 宋体">将会起到较好的效果</span>. <span style="font-family: 宋体">对索引列使用</span>OR<span style="font-family: 宋体">将造成全表扫描</span>. <span style="font-family: 宋体">注意</span>, <span style="font-family: 宋体">以上规则只针对多个索引列有效</span>. <span style="font-family: 宋体">如果有</span>column<span style="font-family: 宋体">没有被索引</span>, <span style="font-family: 宋体">查询效率可能会因为你没有选择</span>OR<span style="font-family: 宋体">而降低</span>. <span style="font-family: 宋体">在下面的例子中</span>, LOC_ID <span style="font-family: 宋体">和</span>REGION<span style="font-family: 宋体">上都建有索引</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">高效</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT LOC_ID , LOC_DESC , REGION </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM LOCATION </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE LOC_ID = 10 </span></span></p>
<p><span style="color: red"><span style="color: #800000">UNION</span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT LOC_ID , LOC_DESC , REGION </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM LOCATION </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE REGION = &#8220;MELBOURNE&#8221; </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">低效</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT LOC_ID , LOC_DESC , REGION </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM LOCATION </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE LOC_ID = 10 OR REGION = &#8220;MELBOURNE&#8221; </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">如果你坚持要用</span>OR, <span style="font-family: 宋体">那就需要返回记录最少的索引列写在最前面</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>25<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">用</span>IN<span style="font-family: 宋体">来替换</span>OR&nbsp;</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">这是一条简单易记的规则，但是实际的执行效果还须检验，在</span>ORACLE8i<span style="font-family: 宋体">下，两者的执行路径似乎是相同的．　</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">低效</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT&#8230;. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30 </span></span></p>
<p><span style="font-family: 宋体"><span style="color: red"><span style="color: #800000">高效</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT&#8230; FROM LOCATION WHERE LOC_IN&nbsp;IN (10,20,30);</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>26<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">避免在索引列上使用</span>IS NULL<span style="font-family: 宋体">和</span>IS NOT NULL</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">避免在索引中使用任何可以为空的列，</span>ORACLE<span style="font-family: 宋体">将无法使用该索引．对于单列索引，如果列包含空值，索引中将不存在此记录</span>. <span style="font-family: 宋体">对于复合索引，如果每个列都为空，索引中同样不存在此记录</span>.<span style="font-family: 宋体">　如果至少有一个列不为空，则记录存在于索引中．举例</span>: <span style="font-family: 宋体">如果唯一性索引建立在表的</span>A<span style="font-family: 宋体">列和</span>B<span style="font-family: 宋体">列上</span>, <span style="font-family: 宋体">并且表中存在一条记录的</span>A,B<span style="font-family: 宋体">值为</span>(123,null) , ORACLE<span style="font-family: 宋体">将不接受下一条具有相同</span>A,B<span style="font-family: 宋体">值（</span>123,null<span style="font-family: 宋体">）的记录</span>(<span style="font-family: 宋体">插入</span>). <span style="font-family: 宋体">然而如果所有的索引列都为空，</span>ORACLE<span style="font-family: 宋体">将认为整个键值为空而空不等于空</span>. <span style="font-family: 宋体">因此你可以插入</span>1000 <span style="font-family: 宋体">条具有相同键值的记录</span>,<span style="font-family: 宋体">当然它们都是空</span>! <span style="font-family: 宋体">因为空值不存在于索引列中</span>,<span style="font-family: 宋体">所以</span>WHERE<span style="font-family: 宋体">子句中对索引列进行空值比较将使</span>ORACLE<span style="font-family: 宋体">停用该索引</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">低效</span>: (<span style="font-family: 宋体">索引失效</span>) </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT &#8230; FROM&nbsp;DEPARTMENT&nbsp;WHERE&nbsp;DEPT_CODE IS NOT NULL; </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">高效</span>: (<span style="font-family: 宋体">索引有效</span>) </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT &#8230; FROM&nbsp;DEPARTMENT&nbsp;WHERE&nbsp;DEPT_CODE &gt;=0;</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>27<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">总是使用索引的第一个列：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">如果索引是建立在多个列上</span>, <span style="font-family: 宋体">只有在它的第一个列</span>(leading column)<span style="font-family: 宋体">被</span>where<span style="font-family: 宋体">子句引用时</span>,<span style="font-family: 宋体">优化器才会选择使用该索引</span>. <span style="font-family: 宋体">这也是一条简单而重要的规则，当仅引用索引的第二个列时</span>,<span style="font-family: 宋体">优化器使用了全表扫描而忽略了索引</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>28<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">用</span>UNION-ALL <span style="font-family: 宋体">替换</span>UNION ( <span style="font-family: 宋体">如果有可能的话</span>)<span style="font-family: 宋体">：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">当</span>SQL <span style="font-family: 宋体">语句需要</span>UNION<span style="font-family: 宋体">两个查询结果集合时</span>,<span style="font-family: 宋体">这两个结果集合会以</span>UNION-ALL<span style="font-family: 宋体">的方式被合并</span>, <span style="font-family: 宋体">然后在输出最终结果前进行排序</span>. <span style="font-family: 宋体">如果用</span>UNION ALL<span style="font-family: 宋体">替代</span>UNION, <span style="font-family: 宋体">这样排序就不是必要了</span>. <span style="font-family: 宋体">效率就会因此得到提高</span>. <span style="font-family: 宋体">需要注意的是，</span>UNION ALL <span style="font-family: 宋体">将重复输出两个结果集合中相同记录</span>. <span style="font-family: 宋体">因此各位还是要从业务需求分析使用</span>UNION ALL<span style="font-family: 宋体">的可行性</span>. UNION <span style="font-family: 宋体">将对结果集合排序</span>,<span style="font-family: 宋体">这个操作会使用到</span>SORT_AREA_SIZE<span style="font-family: 宋体">这块内存</span>. <span style="font-family: 宋体">对于这块内存的优化也是相当重要的</span>. <span style="font-family: 宋体">下面的</span>SQL<span style="font-family: 宋体">可以用来查询排序的消耗量</span></span></span></p>
<p><span style="font-family: 宋体"><span style="color: red"><span style="color: #800000">低效：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT&nbsp;ACCT_NUM, BALANCE_AMT </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM&nbsp;DEBIT_TRANSACTIONS </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE TRAN_DATE = '31-DEC-95' </span></span></p>
<p><span style="color: red"><span style="color: #800000">UNION</span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT ACCT_NUM, BALANCE_AMT </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM DEBIT_TRANSACTIONS </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE TRAN_DATE = '31-DEC-95' </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">高效</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT ACCT_NUM, BALANCE_AMT </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM DEBIT_TRANSACTIONS </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE TRAN_DATE = '31-DEC-95' </span></span></p>
<p><span style="color: red"><span style="color: #800000">UNION ALL </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT ACCT_NUM, BALANCE_AMT </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM DEBIT_TRANSACTIONS </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE TRAN_DATE = '31-DEC-95'</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>29<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">用</span>WHERE<span style="font-family: 宋体">替代</span>ORDER BY<span style="font-family: 宋体">：</span></span></span></p>
<p><span style="color: red"><span style="color: #800000">ORDER BY <span style="font-family: 宋体">子句只在两种严格的条件下使用索引</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000">ORDER BY<span style="font-family: 宋体">中所有的列必须包含在相同的索引中并保持在索引中的排列顺序</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000">ORDER BY<span style="font-family: 宋体">中所有的列必须定义为非空</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE<span style="font-family: 宋体">子句使用的索引和</span>ORDER BY<span style="font-family: 宋体">子句中所使用的索引不能并列</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">例如</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">表</span>DEPT<span style="font-family: 宋体">包含以下列</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">DEPT_CODE PK NOT NULL </span></span></p>
<p><span style="color: red"><span style="color: #800000">DEPT_DESC NOT NULL </span></span></p>
<p><span style="color: red"><span style="color: #800000">DEPT_TYPE NULL</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">低效</span>: (<span style="font-family: 宋体">索引不被使用</span>) </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT DEPT_CODE FROM&nbsp;DEPT&nbsp;ORDER BY&nbsp;DEPT_TYPE </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">高效</span>: (<span style="font-family: 宋体">使用索引</span>) </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT DEPT_CODE&nbsp;FROM&nbsp;DEPT&nbsp;WHERE&nbsp;DEPT_TYPE &gt; 0</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>30<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">避免改变索引列的类型</span>.:</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">当比较不同数据类型的数据时</span>, ORACLE<span style="font-family: 宋体">自动对列进行简单的类型转换</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">假设</span> EMPNO<span style="font-family: 宋体">是一个数值类型的索引列</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT &#8230;&nbsp;FROM EMP&nbsp;WHERE&nbsp;EMPNO = &#8216;123' </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">实际上</span>,<span style="font-family: 宋体">经过</span>ORACLE<span style="font-family: 宋体">类型转换</span>, <span style="font-family: 宋体">语句转化为</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT &#8230;&nbsp;FROM EMP&nbsp;WHERE&nbsp;EMPNO = TO_NUMBER(&#8216;123') </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">幸运的是</span>,<span style="font-family: 宋体">类型转换没有发生在索引列上</span>,<span style="font-family: 宋体">索引的用途没有被改变</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">现在</span>,<span style="font-family: 宋体">假设</span>EMP_TYPE<span style="font-family: 宋体">是一个字符类型的索引列</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT &#8230;&nbsp;FROM EMP&nbsp;WHERE EMP_TYPE = 123 </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">这个语句被</span>ORACLE<span style="font-family: 宋体">转换为</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT &#8230;&nbsp;FROM EMP&nbsp;WHERETO_NUMBER(EMP_TYPE)=123 </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">因为内部发生的类型转换</span>, <span style="font-family: 宋体">这个索引将不会被用到</span>! <span style="font-family: 宋体">为了避免</span>ORACLE<span style="font-family: 宋体">对你的</span>SQL<span style="font-family: 宋体">进行隐式的类型转换</span>, <span style="font-family: 宋体">最好把类型转换用显式表现出来</span>. <span style="font-family: 宋体">注意当字符和数值比较时</span>, ORACLE<span style="font-family: 宋体">会优先转换数值类型到字符类型</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>31<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">需要当心的</span>WHERE<span style="font-family: 宋体">子句</span>:</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">某些</span>SELECT <span style="font-family: 宋体">语句中的</span>WHERE<span style="font-family: 宋体">子句不使用索引</span>. <span style="font-family: 宋体">这里有一些例子</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">在下面的例子里</span>, (1)<span style="font-family: 宋体">&#8216;</span>!=' <span style="font-family: 宋体">将不使用索引</span>. <span style="font-family: 宋体">记住</span>, <span style="font-family: 宋体">索引只能告诉你什么存在于表中</span>, <span style="font-family: 宋体">而不能告诉你什么不存在于表中</span>. (2) <span style="font-family: 宋体">&#8216;</span>||'<span style="font-family: 宋体">是字符连接函数</span>. <span style="font-family: 宋体">就象其他函数那样</span>, <span style="font-family: 宋体">停用了索引</span>. (3) <span style="font-family: 宋体">&#8216;</span>+'<span style="font-family: 宋体">是数学函数</span>. <span style="font-family: 宋体">就象其他数学函数那样</span>, <span style="font-family: 宋体">停用了索引</span>. (4)<span style="font-family: 宋体">相同的索引列不能互相比较</span>,<span style="font-family: 宋体">这将会启用全表扫描</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>32<span style="font-family: 宋体">）</span> a. <span style="font-family: 宋体">如果检索数据量超过</span>30%<span style="font-family: 宋体">的表中记录数</span>.<span style="font-family: 宋体">使用索引将没有显著的效率提高</span>. </span></span></p>
<p><span style="color: red"><span style="color: #800000">b. <span style="font-family: 宋体">在特定情况下</span>, <span style="font-family: 宋体">使用索引也许会比全表扫描慢</span>, <span style="font-family: 宋体">但这是同一个数量级上的区别</span>. <span style="font-family: 宋体">而通常情况下</span>,<span style="font-family: 宋体">使用索引比全表扫描要块几倍乃至几千倍</span>!</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>33<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">避免使用耗费资源的操作</span>:</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">带有</span>DISTINCT,UNION,MINUS,INTERSECT,ORDER BY<span style="font-family: 宋体">的</span>SQL<span style="font-family: 宋体">语句会启动</span>SQL<span style="font-family: 宋体">引擎</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">执行耗费资源的排序</span>(SORT)<span style="font-family: 宋体">功能</span>. DISTINCT<span style="font-family: 宋体">需要一次排序操作</span>, <span style="font-family: 宋体">而其他的至少需要执行两次排序</span>. <span style="font-family: 宋体">通常</span>, <span style="font-family: 宋体">带有</span>UNION, MINUS , INTERSECT<span style="font-family: 宋体">的</span>SQL<span style="font-family: 宋体">语句都可以用其他方式重写</span>. <span style="font-family: 宋体">如果你的数据库的</span>SORT_AREA_SIZE<span style="font-family: 宋体">调配得好</span>, <span style="font-family: 宋体">使用</span>UNION , MINUS, INTERSECT<span style="font-family: 宋体">也是可以考虑的</span>, <span style="font-family: 宋体">毕竟它们的可读性很强</span></span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">（</span>34<span style="font-family: 宋体">）</span> <span style="font-family: 宋体">优化</span>GROUP BY:</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">提高</span>GROUP BY <span style="font-family: 宋体">语句的效率</span>, <span style="font-family: 宋体">可以通过将不需要的记录在</span>GROUP BY <span style="font-family: 宋体">之前过滤掉</span>.<span style="font-family: 宋体">下面两个查询返回相同结果但第二个明显就快了许多</span>.</span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">低效</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT JOB , AVG(SAL) </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM EMP </span></span></p>
<p><span style="color: red"><span style="color: #800000">GROUP JOB </span></span></p>
<p><span style="color: red"><span style="color: #800000">HAVING JOB = &#8216;PRESIDENT' </span></span></p>
<p><span style="color: red"><span style="color: #800000">OR JOB = &#8216;MANAGER' </span></span></p>
<p><span style="color: red"><span style="color: #800000"><span style="font-family: 宋体">高效</span>: </span></span></p>
<p><span style="color: red"><span style="color: #800000">SELECT JOB , AVG(SAL) </span></span></p>
<p><span style="color: red"><span style="color: #800000">FROM EMP </span></span></p>
<p><span style="color: red"><span style="color: #800000">WHERE JOB = &#8216;PRESIDENT' </span></span></p>
<p><span style="color: red"><span style="color: #800000">OR JOB = &#8216;MANAGER' </span></span></p>
<p><span style="color: red"><span style="color: #800000">GROUP JOB</span></span></p>
<img src ="http://www.blogjava.net/zhuzi1987/aggbug/243864.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhuzi1987/" target="_blank">竹子</a> 2008-12-02 10:42 <a href="http://www.blogjava.net/zhuzi1987/archive/2008/12/02/243864.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库性能优化有哪些措施?</title><link>http://www.blogjava.net/zhuzi1987/archive/2008/11/20/241552.html</link><dc:creator>竹子</dc:creator><author>竹子</author><pubDate>Thu, 20 Nov 2008 01:47:00 GMT</pubDate><guid>http://www.blogjava.net/zhuzi1987/archive/2008/11/20/241552.html</guid><wfw:comment>http://www.blogjava.net/zhuzi1987/comments/241552.html</wfw:comment><comments>http://www.blogjava.net/zhuzi1987/archive/2008/11/20/241552.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhuzi1987/comments/commentRss/241552.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhuzi1987/services/trackbacks/241552.html</trackback:ping><description><![CDATA[<span style="color: #800000">&nbsp;<br />
<br />
<br />
l l 数据库回滚段是否足够？ <br />
<br />
<br />
l l 是否需要建立ORACLE数据库索引、聚集、散列？ <br />
<br />
<br />
l l 系统全局区（SGA）大小是否足够？ <br />
<br />
<br />
l l SQL语句是否高效？ <br />
<br />
<br />
2、2、数据仓库系统（Data Warehousing），这种信息系统的主要任务是从ORACLE的海量数据中进行查询，得到数据之间的某些规律。数据库管理员需要为这种类型的ORACLE数据库着重考虑下述参数： <br />
<br />
<br />
l l 是否采用B*-索引或者bitmap索引？ <br />
<br />
<br />
l l 是否采用并行SQL查询以提高查询效率？ <br />
<br />
<br />
l l 是否采用PL/SQL函数编写存储过程？ <br />
<br />
<br />
l l 有必要的话，需要建立并行数据库提高数据库的查询效率 <br />
<br />
<br />
SQL语句的调整原则 <br />
<br />
<br />
SQL语言是一种灵活的语言，相同的功能可以使用不同的语句来实现，但是语句的执行效率是很不相同的。程序员可以使用EXPLAIN PLAN语句来比较各种实现方案，并选出最优的实现方案。总得来讲，程序员写SQL语句需要满足考虑如下规则： <br />
<br />
<br />
1、1、尽量使用索引。试比较下面两条SQL语句： <br />
<br />
<br />
语句A：SELECT dname, deptno FROM dept WHERE deptno NOT IN <br />
<br />
<br />
(SELECT deptno FROM emp); <br />
<br />
<br />
语句B：SELECT dname, deptno FROM dept WHERE NOT EXISTS <br />
<br />
<br />
(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno); <br />
<br />
<br />
这两条查询语句实现的结果是相同的，但是执行语句A的时候，ORACLE会对整个emp表进行扫描，没有使用建立在emp表上的deptno索引，执行语句B的时候，由于在子查询中使用了联合查询，ORACLE只是对emp表进行的部分数据扫描，并利用了deptno列的索引，所以语句B的效率要比语句A的效率高一些。 <br />
<br />
<br />
2、2、选择联合查询的联合次序。考虑下面的例子： <br />
<br />
<br />
SELECT stuff FROM taba a, tabb b, tabc c <br />
<br />
<br />
WHERE a.acol between :alow and :ahigh <br />
<br />
<br />
AND b.bcol between :blow and :bhigh <br />
<br />
<br />
AND c.ccol between :clow and :chigh <br />
<br />
<br />
AND a.key1 = b.key1 <br />
<br />
<br />
AMD a.key2 = c.key2; <br />
<br />
<br />
这个SQL例子中，程序员首先需要选择要查询的主表，因为主表要进行整个表数据的扫描，所以主表应该数据量最小，所以例子中表A的acol列的范围应该比表B和表C相应列的范围小。 <br />
<br />
<br />
3、3、在子查询中慎重使用IN或者NOT IN语句，使用where (NOT) exists的效果要好的多。 <br />
<br />
<br />
4、4、慎重使用视图的联合查询，尤其是比较复杂的视图之间的联合查询。一般对视图的查询最好都分解为对数据表的直接查询效果要好一些。 <br />
<br />
<br />
5、5、可以在参数文件中设置SHARED_POOL_RESERVED_SIZE参数，这个参数在SGA共享池中保留一个连续的内存空间，连续的内存空间有益于存放大的SQL程序包。 <br />
<br />
<br />
6、6、ORACLE公司提供的DBMS_SHARED_POOL程序可以帮助程序员将某些经常使用的存储过程&#8220;钉&#8221;在SQL区中而不被换出内存，程序员对于经常使用并且占用内存很多的存储过程&#8220;钉&#8221;到内存中有利于提高最终用户的响应时间。 <br />
<br />
<br />
CPU参数的调整 <br />
<br />
<br />
CPU是服务器的一项重要资源，服务器良好的工作状态是在工作高峰时CPU的使用率在90％以上。如果空闲时间CPU使用率就在90％以上，说明服务器缺乏CPU资源，如果工作高峰时CPU使用率仍然很低，说明服务器CPU资源还比较富余。 <br />
<br />
<br />
使用操作相同命令可以看到CPU的使用情况，一般UNIX操作系统的服务器，可以使用sar &#8211;u命令查看CPU的使用率，NT操作系统的服务器，可以使用NT的性能管理器来查看CPU的使用率。 <br />
<br />
<br />
数据库管理员可以通过查看v$sysstat数据字典中&#8220;CPU used by this session&#8221;统计项得知ORACLE数据库使用的CPU时间，查看&#8220;OS User level CPU time&#8221;统计项得知操作系统用户态下的CPU时间，查看&#8220;OS System call CPU time&#8221;统计项得知操作系统系统态下的CPU时间，操作系统总的CPU时间就是用户态和系统态时间之和，如果ORACLE数据库使用的CPU时间占操作系统总的CPU时间90％以上，说明服务器CPU基本上被ORACLE数据库使用着，这是合理，反之，说明服务器CPU被其它程序占用过多，ORACLE数据库无法得到更多的CPU时间。 <br />
<br />
<br />
数据库管理员还可以通过查看v$sesstat数据字典来获得当前连接ORACLE数据库各个会话占用的CPU时间，从而得知什么会话耗用服务器CPU比较多。 <br />
<br />
<br />
出现CPU资源不足的情况是很多的：SQL语句的重解析、低效率的SQL语句、锁冲突都会引起CPU资源不足。 <br />
<br />
<br />
1、数据库管理员可以执行下述语句来查看SQL语句的解析情况： <br />
<br />
<br />
SELECT * FROM V$SYSSTAT <br />
<br />
<br />
WHERE NAME IN <br />
<br />
<br />
('parse time cpu', 'parse time elapsed', 'parse count (hard)'); <br />
<br />
<br />
这里parse time cpu是系统服务时间，parse time elapsed是响应时间，用户等待时间 <br />
<br />
<br />
waite time = parse time elapsed &#8211; parse time cpu <br />
<br />
<br />
由此可以得到用户SQL语句平均解析等待时间＝waite time / parse count。这个平均等待时间应该接近于0，如果平均解析等待时间过长，数据库管理员可以通过下述语句 <br />
<br />
<br />
SELECT SQL_TEXT, PARSE_CALLS, EXECUTIONS FROM V$SQLAREA <br />
<br />
<br />
ORDER BY PARSE_CALLS; <br />
<br />
<br />
来发现是什么SQL语句解析效率比较低。程序员可以优化这些语句，或者增加ORACLE参数SESSION_CACHED_CURSORS的值。 <br />
<br />
<br />
2、数据库管理员还可以通过下述语句： <br />
<br />
<br />
SELECT BUFFER_GETS, EXECUTIONS, SQL_TEXT FROM V$SQLAREA; <br />
<br />
<br />
查看低效率的SQL语句，优化这些语句也有助于提高CPU的利用率。 <br />
<br />
<br />
3、3、数据库管理员可以通过v$system_event数据字典中的&#8220;latch free&#8221;统计项查看ORACLE数据库的冲突情况，如果没有冲突的话，latch free查询出来没有结果。如果冲突太大的话，数据库管理员可以降低spin_count参数值，来消除高的CPU使用率。 <br />
<br />
<br />
内存参数的调整 <br />
<br />
<br />
内存参数的调整主要是指ORACLE数据库的系统全局区（SGA）的调整。SGA主要由三部分构成：共享池、数据缓冲区、日志缓冲区。 <br />
<br />
<br />
1、 1、 共享池由两部分构成：共享SQL区和数据字典缓冲区，共享SQL区是存放用户SQL命令的区域，数据字典缓冲区存放数据库运行的动态信息。数据库管理员通过执行下述语句： <br />
<br />
<br />
select (sum(pins - reloads)) / sum(pins) "Lib Cache" from v$librarycache; <br />
<br />
<br />
来查看共享SQL区的使用率。这个使用率应该在90％以上，否则需要增加共享池的大小。数据库管理员还可以执行下述语句： <br />
<br />
<br />
select (sum(gets - getmisses - usage - fixed)) / sum(gets) "Row Cache" from v$rowcache; <br />
<br />
<br />
查看数据字典缓冲区的使用率，这个使用率也应该在90％以上，否则需要增加共享池的大小。 <br />
<br />
<br />
2、 2、 数据缓冲区。数据库管理员可以通过下述语句： <br />
<br />
<br />
SELECT name, value FROM v$sysstat WHERE name IN ('db block gets', 'consistent gets','physical reads'); <br />
<br />
<br />
来查看数据库数据缓冲区的使用情况。查询出来的结果可以计算出来数据缓冲区的使用命中率＝1 - ( physical reads / (db block gets + consistent gets) )。 <br />
<br />
<br />
这个命中率应该在90％以上，否则需要增加数据缓冲区的大小。 <br />
<br />
<br />
3、 3、 日志缓冲区。数据库管理员可以通过执行下述语句： <br />
<br />
<br />
select name,value from v$sysstat where name in ('redo entries','redo log space requests');查看日志缓冲区的使用情况。查询出的结果可以计算出日志缓冲区的申请失败率： <br />
<br />
申请失败率＝requests/entries，申请失败率应该接近于0，否则说明日志缓冲区开设太小，需要增加ORACLE数据库的日志缓冲区。</span>
 <img src ="http://www.blogjava.net/zhuzi1987/aggbug/241552.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhuzi1987/" target="_blank">竹子</a> 2008-11-20 09:47 <a href="http://www.blogjava.net/zhuzi1987/archive/2008/11/20/241552.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>oracle性能调优篇----Oracle9i 的查询优化</title><link>http://www.blogjava.net/zhuzi1987/archive/2008/11/20/241551.html</link><dc:creator>竹子</dc:creator><author>竹子</author><pubDate>Thu, 20 Nov 2008 01:46:00 GMT</pubDate><guid>http://www.blogjava.net/zhuzi1987/archive/2008/11/20/241551.html</guid><wfw:comment>http://www.blogjava.net/zhuzi1987/comments/241551.html</wfw:comment><comments>http://www.blogjava.net/zhuzi1987/archive/2008/11/20/241551.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/zhuzi1987/comments/commentRss/241551.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/zhuzi1987/services/trackbacks/241551.html</trackback:ping><description><![CDATA[<div class="t_msgfont" id="postmessage_7119255" style="color: #800000">本文描述了<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=Oracle">Oracle</span> 的查询优化<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%B3%CC%D0%F2">程序</span>，它是<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%CA%FD%BE%DD%BF%E2"><span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%CA%FD%BE%DD">数据</span>库</span>的关键组件，能让<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=Oracle">Oracle</span> 的<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%D3%C3%BB%A7">用户</span>获得极佳的执行性能。<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=Oracle">Oracle</span> 的查询优化<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%BC%BC%CA%F5">技术</span>在<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%B9%A6%C4%DC">功能</span>上无与伦比，本文详细讨论了查询优化的所有重要领域。 <br />
<br />
　　简介 <br />
<br />
　　什么是查询优化程序？ <br />
<br />
　　查询优化对于关系数据库的性能，特别是对于执行复杂SQL 语句的性能而言至关重要。查询优化程序确定执行每一次查询的最佳策略。 <br />
<br />
　　例如，查询优化程序选择对于指定的查询是否使用索引，以及在联接多个表时采用哪一种联接技术。这类决策对SQL 语句的执行性能有很大的影响，查询优化对于每一种<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%D3%A6%D3%C3">应用</span>程序都是关键技术，<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%D3%A6%D3%C3">应用</span>程序涉及的范围从操作<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%CF%B5%CD%B3">系统</span>到数据仓库，从分析<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%CF%B5%CD%B3">系统</span>到内容<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%B9%DC%C0%ED">管理</span><span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%CF%B5%CD%B3">系统</span>。查询优化程序对于<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%D3%A6%D3%C3">应用</span>程序和最终用户是完全透明的。 <br />
<br />
　　由于应用程序可能生成非常复杂的SQL 语句, 查询优化程序必须精心构建、功能强大，以保障良好的执行性能。例如，查询优化程序可转换SQL 语句，使复杂的语句转换成为等价的但执行性能更好的SQL 语句。查询优化程序的典型特征是基于开销。在基于开销的优化策略中，对于给定查询生成多个执行计划，然后对每个计划估算开销。查询优化程序选用估算开销最低的计划。 <br />
<br />
　　Oracle 在查询优化方面提供了什么？ <br />
<br />
　　Oracle 的优化程序可称是业界最成功的优化程序。基于开销的优化程序自1992 年随Oracle7 推出后，通过10 年的丰富的实际用户经验，不断得到提高和改进。好的查询优化程序不是基于纯粹的理论假设及谓词在实验室中开发出来的，而是通过适合实际用户需求开发和磨合出来的。<br />
<br />
　　Oracle 的查询优化程序比任何其他查询优化程序在数据库应用程序的应用都要多，而且Oracle 的优化程序一直由于实际应用的反馈而得到改进。 <br />
<br />
　　Oracle 的优化程序包含4 大主要部分（本文将在以下章节详细讨论这些部分）： <br />
<br />
　　SQL 语句转换：在查询优化中Oracle 使用一系列精深技术对SQL 语句进行转换。查询优化的这一步骤的目的是将原有的SQL 语句转换成为语义相同而处理效率更高的SQL 语句。 <br />
<br />
　　执行计划选择：对于每个SQL 语句, 优化程序选择一个执行计划（可使用Oracle 的EXPLAIN PLAN <span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%B9%A4%BE%DF">工具</span>或通过Oracle 的&#8220;v$sql_plan&#8221; 视图查看）。执行计划描述了执行SQL 时的所有步骤，如访问表的顺序；如何将这些表联接在一起；以及是否通过索引来访问这些表。优化程序为每个SQL 语句设计许多可能的执行计划，并选出最好的一个。 <br />
<br />
　　开销模型与统计：Oracle 的优化程序依赖于执行SQL 语句的所有单个操作的开销估算。想要优化程序能选出最好的执行计划，需要最好的开销估算方法。开销估算需要详细了解某些知识，这些知识包括：明白每个查询所需的I/O、CPU 和<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%C4%DA%B4%E6">内存</span><span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%D7%CA%D4%B4">资源</span>以及数据库对象相关的统计信息（表、索引和物化视图），还有有关硬件<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%B7%FE%CE%F1%C6%F7"><span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%B7%FE%CE%F1">服务</span>器</span>平台的性能信息。收集这些统计和性能信息的过程应高效并且高度<span class="t_tag" onclick="tagshow(event)" href="tag.php?name=%D7%D4%B6%AF">自动</span>化。 <br />
<br />
　　动态运行时间优化：并不是SQL 执行的每个方面都可以事先进行优化。Oracle 因此要根据当前数据库负载对查询处理策略进行动态调整。该动态优化的目标是获得优化的执行性能，即使每个查询可能不能够获得理想的CPU 或内存资源。Oracle 另有一个原来的优化程序，即基于规则的优化程序。该优化程序仅向后兼容，在Oracle 的下个版本将不再得到支持。绝大多数Oracle 用户目前使用基于开销的优化程序。所有主要的应用程序供应商（如Oracle 应用程序、SAP 和Peoplesoft，仅列出这几家）以及大量近来开发的客户应用程序都使用基于开销的优化程序来获得优良的执行性能，故本文仅讲述基于开销的优化程序。 <br />
<br />
　　SQL 语句转换 <br />
<br />
　　使用SQL 语句表示复杂查询可以有多种方式。提交到数据库的SQL 语句类型通常是最终用户或应用程序可以最简单的方式生成的SQL 类型。但是这些人工编写或机器生成的查询公式不一定是执行查询最高效的SQL 语句。例如，由应用程序生成的查询通常含有一些无关紧要的条件，这些条件可以去掉。或者，有些从某查询谓词出的附加条件应当添加到该SQL 语句中。SQL 转换语句的目的是将给定的SQL 语句转换成语义相同（即返回相同结果的SQL 语句）并且性能更好的SQL 语句。 <br />
<br />
　　所有的这些转换对应用程序及最终用户完全透明。SQL 语句转换在查询优化过程中自动实现。 <br />
<br />
　　Oracle 实现了多种SQL 语句转换。这些转换大概可分成两类： <br />
<br />
　　试探查询转换：在可能的情况下对进来的SQL 语句都会进行这种转换。这种转换能够提供相同或较好的查询性能，所以Oracle 知道实施这种转换不会降低执行性能。 基于开销的查询转换：Oracle 使用基于开销的方法进行几类查询转换。借助这种方法，转换后的查询会与原查询相比较，然后Oracle 的优化程序从中选出最佳执行策略。 <br />
<br />
　　以下部分将讨论Oracle 转换技术的几个示例。这些示例并非是权威的，仅用于帮助读者理解该关键转换技术及其益处。 <br />
<br />
　　试探查询转换 <br />
<br />
　　简单视图合并 <br />
<br />
　　可能最简单的查询转换是视图合并。对于包含视图的查询，通常可以通过把视图定义与查询&#8220;合并&#8221;来将视图从查询中去掉。例如，请看下面的非常简单的视图及查询。 <br />
<br />
　　CREATE VIEW TEST_VIEW AS SELECT ENAME, DNAME, SAL FROM EMP E, DEPT D WHERE E.DEPTNO = D.DEPTNO; <br />
　　SELECT ENAME, DNAME FROM TEST_VIEW WHERE SAL &gt; 10000; <br />
<br />
　　如果不加任何转换，处理该查询的唯一方法是将EMP 的所有行联接到DEPT 表的所有行，然后筛选有适当的SAL 的值的那些行。 <br />
<br />
　　如果使用视图合并，上述查询可以转换为： <br />
<br />
　　SELECT ENAME, DNAME FROM EMP E, DEPT D WHERE E.DEPTNO = D.DEPTNO AND E.SAL &gt; 10000; <br />
<br />
　　处理该转换后的查询时，可以在联接EMP 和DEPT 表前使用谓词&#8216;SAL&gt;10000&#8217;。这一转换由于减少了联接的数据量而大大提高了查询的执行性能。即便在这样一个非常简单的示例里，查询转换的益处和重要性也显而易见。 <br />
<br />
　　复杂视图合并 <br />
<br />
　　许多视图合并操作都是直截了当的，如以上示例。但是，较复杂的视图，如包含GROUP BY 或DISTINCT 操作符的视图合并起来就不那么容易了。Oracle 为合并这类复杂视图提供了一些高级技术。 <br />
<br />
　　请看以下带有GROUP BY 语句的视图。在该示例中，视图计算每个部门的平均工资。 <br />
<br />
　　CREATE VIEW AVG_SAL_VIEW AS SELECT DEPTNO, AVG(SAL) AVG_SAL_DEPT FROM EMP GROUP BY DEPTNO <br />
<br />
　　查询的目的是要找出Oakland 每个部门的平均工资： <br />
<br />
　　SELECT DEPT.NAME, AVG_SAL_DEPT FROM DEPT, AVG_SAL_VIEW WHERE DEPT.DEPTNO = AVG_SAL_VIEW.DEPTNO AND DEPT.LOC = 'OAKLAND' <br />
<br />
　　可以转换为： <br />
<br />
　　SELECT DEPT.NAME, AVG(SAL) FROM DEPT, EMP WHERE DEPT.DEPTNO = EMP.DEPTNO AND DEPT.LOC = 'OAKLAND' GROUP BY DEPT.ROWID, DEPT.NAME <br />
<br />
　　该特殊转换的执行性能优点立即显现：该转换把EMP 数据在分组聚合前进行联接和筛选，而不是在联接前将EMP 表的所有数据分组聚合。 <br />
<br />
　　子查询&#8220;展平&#8221; <br />
<br />
　　Oracle 有一些转换能将不同类型的子查询转变为联接、半联接或反联接。作为该领域内的技术示例，我们来看下面这个查询，找出有工资超过10000 的员工的那些部门： <br />
<br />
　　SELECT D.DNAME FROM DEPT D WHERE D.DEPTNO IN (SELECT E.DEPTNO FROM EMP E WHERE E.SAL &gt; 10000) <br />
<br />
　　存在一系列可以优化本查询的执行计划。Oracle 会考虑这些可能的不同转换，基于开销选出最佳计划。 <br />
<br />
　　如果不进行任何转换，这一查询的执行计划如下： <br />
<br />
　　OPERATION OBJECT_NAME OPTIONS <br />
　　SELECT STATEMENT <br />
　　FILTER <br />
　　TABLE ACCESS DEPT FULL <br />
　　TABLE ACCESS EMP FULL <br />
<br />
　　按照该执行计划，将扫描DEPT 表的每一行查找所有满足子查询条件的EMP 记录。通常，这不是一种高效的执行策略。然而，查询转换可以实现效率更高的计划。 <br />
<br />
　　该查询的可能计划之一是将查询作为&#8220;半联接&#8221;来执行。&#8220;半联接&#8221;是一种特殊类型的联接，它消除了联接中来自内表的冗余值（这实际上就是该子查询的原本的语义）。在该示例中，优化程序选择了一个散列半联接，尽管Oracle 也支持排序-合并以及嵌套-循环半联接： <br />
<br />
　　OPERATION OBJECT_NAME OPTIONS <br />
　　SELECT STATEMENT <br />
　　HASH JOIN SEMI <br />
　　TABLE ACCESS DEPT FULL <br />
　　TABLE ACCESS EMP FULL <br />
<br />
　　由于SQL 没有用于半联接的直接语法，此转换过的查询不能使用标准的SQL 来表示。但是，转换后的伪SQL 将是：<br />
<br />
　　SELECT DNAME FROM EMP E, DEPT D WHERE D.DEPTNO E.DEPTNO AND E.SAL &gt; 10000; <br />
<br />
　　另一个可能的计划是优化程序可以决定将DEPT 表作为联接的内表。在这种情况下，查询作为通常的联接来执行，但对EMP 表进行特别排序，以消除冗余的部门号： <br />
<br />
　　OPERATION OBJECT_NAME OPTIONS <br />
　　SELECT STATEMENT <br />
　　HASH JOIN <br />
　　SORT UNIQUE <br />
　　TABLE ACCESS EMP FULL <br />
　　TABLE ACCESS DEPT FULL <br />
<br />
　　转换后的SQL 语句为： <br />
<br />
　　SELECT D.DNAME FROM (SELECT DISTINCT DEPTNO FROM EMP) E, DEPT D WHERE E.DEPTNO = D.DEPTNO AND E.SAL &gt; 10000; <br />
<br />
　　与视图合并一样，子查询展平也是获得良好查询执行性能的基本优化办法。 <br />
<br />
　　传递谓词生成 <br />
<br />
　　在某些查询中，由于表间的联接关系，一个表中的谓词可以转化为另一个表中的谓词。Oracle 会以这种方式演绎出新的谓词，这类谓词被称为传递谓词。例如，来看一个查询，找出定货当天运出的所有商品： <br />
<br />
　　SELECT COUNT(DISTINCT O_ORDERKEY) FROM ORDER, LINEITEM WHERE O_ORDERKEY = L_ORDERKEY AND O_ORDERDATE = L_SHIPDATE AND O_ORDERDATE BETWEEN '1-JAN-2002' AND '31-JAN-2002' <br />
<br />
　　利用传递性，该ORDER 表中的谓词也可以用于LINEITEM 表： <br />
<br />
　　SELECT COUNT(DISTINCT O_ORDERKEY) FROM ORDER, LINEITEM WHERE</div>
 <img src ="http://www.blogjava.net/zhuzi1987/aggbug/241551.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/zhuzi1987/" target="_blank">竹子</a> 2008-11-20 09:46 <a href="http://www.blogjava.net/zhuzi1987/archive/2008/11/20/241551.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>