Brian Walker
可能让h觉得很奇怪,但好像的没有什?/strong>“正式?/strong>”T-SQL ~码标准。早?/strong> 1999 q末的时候,我惊喜地发现 John Hindmarsh 提出?/strong> SQL Server 7.0 标准Q我?/strong> 2000 q?/strong> 2 月的C论中对他的某些q行了ȝ。(2000 q?/strong> 2 月以及本月的“下蝲”中都包括?/strong> John 原来的标准。)后来Q?/strong>Ron Talmage 撰写了一pd专栏文章Q提Z他对各种“最x?/strong>”的徏议,当然Q?/strong>SQL Server 组也已正式发布?/strong> SQL Server 最x法分析器 (SQLBPA)。现在,一位具有超q?/strong> 25 q经验的数据库管理员和应用程序开发员 Brian Walker 又提Z他的和提C?/strong>
q行 T-SQL ~程时常怼忽略~码标准Q但q些标准却是开发小l顺利开展工作的关键工具。这里介l的~码标准是我多年的开发成果。它们当然还没有得到普遍接受Q而且不可否认Q有些标准带有主观色彩。我的目的实际上更多的是Z提高大家的意识,而不是吹捧自己是 T-SQL 样式斚w的仲裁者:最重要的是要徏立某些合理的~码标准q循这些标准。您在这文章中会发现有?T-SQL ~程的一pd不同的编码标准、技巧和提示。它们ƈ未以M特定的优先或重要性顺序列出?/p>
让我们从格式开始。表面上QT-SQL 代码的格式似乎ƈ不重要,但一致的格式可以使您的同事(不论是同一组的成员还是更大范围的 T-SQL 开发团队的成员Q更L地浏览和理解您的代码。T-SQL 语句有一个结构,遵@一目了然的l构使您可以更轻村֜查找和确认语句的不同部分。统一的格式还使您可以更轻村֜在复?T-SQL 语句中增删代码段Q调试工作变得更容易。下面是 SELECT 语句的格式示例:
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 > 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
Z个嵌套代码块中的语句使用四个I格的羃q。(上述代码中的多行 SELECT 语句是一?SQL 语句。)在同一语句中开始新行时Q SQL 关键字右寚w。将代码~辑器配|ؓ使用I格Q而不是用制表符。这P不管使用何种E序查看代码Q格式都是一致的?/p>
►大写所有的 T-SQL 关键字,包括 T-SQL 函数。变量名U及光标名称使用混和大小写。数据类型用小写?/p>
名别名要短,但意义要量明确。通常Q用大写的表名作ؓ别名Q?AS 关键字指定表或字D늚别名?/p>
►当一?T-SQL 语句中涉及到多个表时Q始l用表名别名来限定字段名。这使其他h阅读h更清楚,避免了含义模p的引用?/p>
►当相关数字出现在连l的代码行中Ӟ例如一pd SUBSTRING 函数调用Q,它们排成列。这样容易浏览数字列表?/p>
Z用一个(而不是两个)I分隔 T-SQL 代码的逻辑块,只要需要就可以使用?/p>
►声?T-SQL 局部变量(例如 @lngTableIDQ时Q用适当的数据类型声明和一致的大写?/p>
?strong>始终指定字符数据cd的长度,q确保允许用户可能需要的最大字W数Q因出最大长度的字符会丢失?/p>
?strong>始终指定十进制数据类型的_ֺ和范_否则Q将默认为未指定_ֺ和整数范围?
Z用错误处理程序,但要C行首 (BOL) 中的错误查示例不会象介绍的那栯v作用。用来检?@@ERROR pȝ函数?T-SQL 语句 (IF) 实际上在q程中清除了 @@ERROR |无法再捕获除零之外的M倹{(即ɽCZ起作用,它们也只能捕h后发生的一个错误,而不是您更想捕获的第一个错误。)必须使用 SET ?SELECT 立即捕获错误代码Q如前面CZ所C。如果状态变量仍然ؓӞ应{换到状态变量?
►避免?#8220;未声明的”功能Q例如系l表中未声明的列、T-SQL 语句中未声明的功能或者未声明的系l存储过E或扩展的存储过E?
?strong>不要依赖M隐式的数据类型{换。例如,不能为数字变量赋予字W|而假?T-SQL 会进行必要的转换。相反,在ؓ变量赋值或比较g前,应用适当?CONVERT 函数使数据类型相匚w。另一个示例:虽然 T-SQL 会在q行比较之前对字W表辑ּq行隐式且自动的 RTRIMQ但不能依赖此行为,因ؓ兼容性别设|非字符表达式会使情况复杂化?/p>
?strong>不要空的变量值直接与比较q算W(W号Q比较。如果变量可能ؓI,应?IS NULL ?IS NOT NULL q行比较Q或者?ISNULL 函数?/p>
Z要?STR 函数q行舍入Q此函数只能用于整数。如果需要十q制值的字符串Ş式,应先使用 CONVERT 函数Q{至不同的范围Q或 ROUND 函数Q然后将其{换ؓ字符丌Ӏ也可以使用 CEILING ?FLOOR 函数?/p>
Z用数学公式时要小心,因ؓ T-SQL 可能会将表达式强制理解ؓ一个不需要的数据cd。如果需要十q制l果Q应在整数常量后加点和零 (.0)?/p>
►决不要依赖 SELECT 语句会按M特定序q回行,除非?ORDER BY 子句中指定了序?/p>
►通常Q应?ORDER BY 子句?SELECT 语句一起用。可预知的顺序(即不是最方便的)比不可预知的序强,其是在开发或调试q程中。(部v到生产环境中之前Q可能需要删?ORDER BY 子句。)在返回行的顺序无关紧要的情况下,可以忽略 ORDER BY 的开销?/p>
Z要在 T-SQL 代码中用双引号。应为字W常量用单引号。如果没有必要限定对象名Uͼ可以使用Q非 ANSI SQL 标准Q括号将名称括v来?/p>
►在 SQL Server 2000 中,量使用表变量来代替临时表。如果表变量包含大量数据Q请注意索引非常有限Q只有主键烦引)?/p>
►先在例E中创徏临时表,最后再昑ּ删除临时表。将 DDL ?DML 语句混合使用有助于处理额外的重新~译zd?/p>
认识C时表q不?/strong>不可使用Q适当C用它们可以某些例程更有效,例如Q当需要重复引用大型表或常用表中的某个数据集时。但是,对于一ơ性事Ӟ最好用导?
?/em>使用表?UDF 时要心Q因为在变量Q而不是常量)中传递某个参数时Q如果在 WHERE 子句中用该参数Q会D表扫描。还要避免在一个查询中多次使用相同的表?UDF。但是,表?UDF 实h某些非常方便的动态编译功能?em>[相关资料Q参?/em> Tom Moreau ?/em> 2003 q?/em> 11 月䆾“生成序列?/em>”专栏中的“使用 UDF 填充表变?/em>”。-~者按Q?/em>
►几乎所有的存储q程都应在开始时讄 SET NOCOUNT ONQ而在l束时设|?SET NOCOUNT OFF?em>[SET NOCOUNT ON ?/em> SQL Server 无需在执行存储过E的每个语句后向客户端发?/em> DONE_IN_PROC 消息?/em>- ~者按] 此标准同样适用于触发器?/p>
►只要在例程中用多个数据库修改语句Q包括在一个@环中多次执行一个语句,应考虑声明昑ּ事务?/p>
Z用基于光标的Ҏ或时表Ҏ之前Q应先寻扑֟于集的解x案来解决问题。基于集的方法通常更有效?/p>
Z临时表一P光标q不是不可用。对型数据集?FAST_FORWARD 光标通常要优于其他逐行处理ҎQ尤其是在必d用几个表才能获得所需的数据时。在l果集中包括“合计”的例E通常要比使用光标执行的速度快。如果开发时间允许,Z光标的方法和Z集的Ҏ都可以尝试一下,看哪一U方法的效果更好?/p>
Z用包含序P?1 ?NQ的表很方便?/p>
►理?CROSS JOIN 的工作原理ƈ加以利用。例如,您可以在工作数据表和序号表之间有效地使用 CROSS JOINQ结果集中将包含每个工作数据与序L合的记录? ►我的结束语是:T-SQL 代码往往很简z,因此如果某个代码块看h很难处理或重复内容较多,那么可能存在一U更单,更好的方法? l论 如果您对我的有Q何看法,Ƣ迎随时向我发送电子邮件进行讨论,也可以就其他问题提出您的。我希望您将此作话的开场白? 其他信息Q摘?/strong> Karen 2000 q?/strong> 2 月䆾的社?/strong> 在标准开发的前沿阵地上,有一股以 SQL Server 数据库管理员 John Hindmarsh 为首的独立的新生力量。MCT、MCSE ?MCDBA 都是最值得您花旉ȝI的。John 的A献是撰写了一份详l的白皮书,概述了他对各U?SQL Server 相关标准提出的徏议。我所知道的其他唯一提出cM的文章是 Andrew Zanevsky 的《Transact-SQL Programming?ISBN 1-56592-401-0) 中的“Format and Style”一章。Andrew、SQL Server Professional 的投Eh Tom Moreau ?Paul Munkenbeck 以及 John 的朋友兼同事 Stephen James 都ؓ John 的白皮书做出qA献。下面是 John 为编写存储过E提供的CZQ?/p>
使用 SQL-92 标准q接句法? Z提高性能Q应优先使用q接Q然后用子查询或嵌套查询? 保变量和参数的cd和大与表数据列相匹配? 保使用所有变量和参数Q或者全部删除? 可能将临时对象攄在本地? 只用在存储q程中创建的临时表? 查输入参数的有效性? 优先使用 SELECT...INTOQ然后?INSERT...SELECTQ以避免大量死锁? l护工作需要的逻辑单元Q在可以~短的情况下Q不要创建大量或长时间运行的q程? 不要在Q何代码中使用 SELECT *? 在过E中使用~进、块、制表符和空|参阅CZ脚本Q? T-SQL 语句要大写? 在过E中d大量注释Q确保可以识别进E。在有助于澄清处理步骤的地方使用行注释? 包括事务理Q除非要?MTS q程中调用过E。(?MTS q程~写独立的过E。) 监视 @@TRANCOUNT 以确定事务的责QU别? 避免使用 GOTOQ错误处理程序中除外? 避免使用嵌套q程? 避免隐式解析对象名称Q确保所有对象都?dbo 所有? 有关 SQL Server Professional ?Pinnacle Publishing 的详l信息,误问其 Web 站点 http://www.pinpub.com/ 注意Q这不是 Microsoft Corporation ?Web 站点。Microsoft 对该 Web 站点上的内容不承担Q何责仅R?/p>
本文转蝲?2004 q?12 月䆾?SQL Server Professional。除非另行说明,否则版权所?2004 Pinnacle Publishing, Inc.。保留所有权利。SQL Server Professional ?Pinnacle Publishing 独立发行的刊物。未l?Pinnacle Publishing, Inc. 事先同意Q不得以M方式使用或复制本文的M部分Q评论文章中的简短引用除外)。如需?Pinnacle Publishing, Inc. 联系Q请拨打 1-800-788-1900?/p>
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
]]>
ORACLE 的解析器按照从右到左的顺序处?/span>FROM子句中的表名Q?/span>FROM子句中写在最后的?/span>(基础?/span> driving table)被最先处理,?/span>FROM子句中包含多个表的情况下,你必选择记录条数最的表作为基表。如果有3个以上的表连接查?/span>, 那就需要选择交叉?/span>(intersection table)作ؓ基础?/span>, 交叉表是指那个被其他表所引用的表.
Q?/span>2Q?/span> WHERE子句中的q接序Q:
ORACLE采用自下而上的顺序解?/span>WHERE子句,Ҏq个原理,表之间的q接必须写在其他WHERE条g之前, 那些可以qo掉最大数量记录的条g必须写在WHERE子句的末?/span>.
Q?/span>3Q?/span> SELECT子句中避免?/span> ‘ * ‘Q?/span>
ORACLE在解析的q程?/span>, 会将'*' 依次转换成所有的列名, q个工作是通过查询数据字典完成?/span>, q意味着耗费更多的时?/span>
Q?/span>4Q?/span> 减少讉K数据库的ơ数Q?/span>
ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, l定变量 , L据块{;
Q?/span>5Q?/span> ?/span>SQL*Plus , SQL*Forms?/span>Pro*C中重新设|?/span>ARRAYSIZE参数, 可以增加每次数据库访问的索数据量 ,gؓ200
Q?/span>6Q?/span> 使用DECODE函数来减处理时_
使用DECODE函数可以避免重复扫描相同记录或重复连接相同的?/span>.
Q?/span>7Q?/span> 整合?/span>,无关联的数据库访问:
如果你有几个单的数据库查询语?/span>,你可以把它们整合C个查询中(即它们之间没有关系)
Q?/span>8Q?/span> 删除重复记录Q?/span>
最高效的删除重复记录方?/span> ( 因ؓ使用?/span>ROWID)例子Q?/span>
DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
Q?/span>9Q?/span> ?/span>TRUNCATE替代DELETEQ?/span>
当删除表中的记录?/span>,在通常情况?/span>, 回滚D?/span>(rollback segments ) 用来存放可以被恢复的信息. 如果你没?/span>COMMIT事务,ORACLE会将数据恢复到删除之前的状?/span>(准确地说是恢复到执行删除命o之前的状?/span>) 而当q用TRUNCATE?/span>, 回滚D不再存放Q何可被恢复的信息.当命令运行后,数据不能被恢?/span>.因此很少的资源被调用,执行旉也会很短. (译者按: TRUNCATE只在删除全表适用,TRUNCATE?/span>DDL不是DML)
Q?/span>10Q?/span> 量多?/span>COMMITQ?/span>
只要有可?/span>,在程序中量多?/span>COMMIT, q样E序的性能得到提高,需求也会因?/span>COMMIT所释放的资源而减?/span>:
COMMIT所释放的资?/span>:
a. 回滚D上用于恢复数据的信?/span>.
b. 被程序语句获得的?/span>
c. redo log buffer 中的I间
d. ORACLE为管理上q?/span>3U资源中的内部花?/span>
Q?/span>11Q?/span> ?/span>Where子句替换HAVING子句Q?/span>
避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集q行qo. q个处理需要排?/span>,总计{操?/span>. 如果能通过WHERE子句限制记录的数?/span>,那就能减这斚w的开销. (?/span>oracle?/span>)on?/span>where?/span>havingq三个都可以加条件的子句中,on是最先执行,whereơ之Q?/span>having最后,因ؓon是先把不W合条g的记录过滤后才进行统计,它就可以减少中间q算要处理的数据Q按理说应该速度是最快的Q?/span>where也应该比having快点的,因ؓ它过滤数据后才进?/span>sumQ在两个表联接时才用on的,所以在一个表的时候,剩?/span>where?/span>having比较了。在q单表查询统计的情况下,如果要过滤的条g没有涉及到要计算字段Q那它们的结果是一LQ只?/span>where可以使用rushmore技术,?/span>having׃能,在速度上后者要慢如果要涉及到计的字段Q就表示在没计算之前Q这个字D늚值是不确定的Q根据上写的工作流E,where的作用时间是在计之前就完成的,?/span>having是在计后才v作用的,所以在q种情况下,两者的l果会不同。在多表联接查询Ӟon?/span>where更早起作用。系l首先根据各个表之间的联接条Ӟ把多个表合成一个时表后,再由whereq行qoQ然后再计算Q计完后再?/span>havingq行qo。由此可见,要想qo条g起到正确的作用,首先要明白这个条件应该在什么时候v作用Q然后再军_攑֜那里
Q?/span>12Q?/span> 减少对表的查询:
在含有子查询?/span>SQL语句?/span>,要特别注意减对表的查询.例子Q?/span>
SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
Q?/span>13Q?/span> 通过内部函数提高SQL效率.Q?/span>
复杂?/span>SQL往往牺牲了执行效?/span>. 能够掌握上面的运用函数解决问题的Ҏ在实际工作中是非常有意义?/span>
Q?/span>14Q?/span> 使用表的别名(Alias)Q?/span>
当在SQL语句中连接多个表?/span>, 请用表的别名ƈ把别名前~于每?/span>Column?/span>.q样一?/span>,可以减解析的旉q减那些由Column歧义引v的语法错?/span>.
Q?/span>15Q?/span> ?/span>EXISTS替代IN、用NOT EXISTS替代NOT INQ?/span>
在许多基于基表的查询?/span>,Z满一个条?/span>,往往需要对另一个表q行联接.在这U情况下, 使用EXISTS(?/span>NOT EXISTS)通常提高查询的效率. 在子查询?/span>,NOT IN子句执行一个内部的排序和合q?/span>. 无论在哪U情况下,NOT IN都是最低效?/span> (因ؓ它对子查询中的表执行了一个全表遍?/span>). Z避免使用NOT IN ,我们可以把它改写成外q接(Outer Joins)?/span>NOT EXISTS.
例子Q?/span>
Q高效)SELECT * FROM EMP (基础?/span>) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X' FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB')
(低效)SELECT * FROM EMP (基础?/span>) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB')
Q?/span>16Q?/span> 识别'低效执行'?/span>SQL语句Q?/span>
虽然目前各种关于SQL优化的图形化工具层出不穷,但是写出自己?/span>SQL工具来解决问题始l是一个最好的ҎQ?/span>
SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,
ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,
ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,
SQL_TEXT
FROM V$SQLAREA
WHERE EXECUTIONS>0
AND BUFFER_GETS > 0
AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY 4 DESC;
Q?/span>17Q?/span> 用烦引提高效率:
索引是表的一个概念部?/span>,用来提高索数据的效率Q?/span>ORACLE使用了一个复杂的自^?/span>B-treel构. 通常,通过索引查询数据比全表扫描要?/span>. ?/span>ORACLE扑և执行查询?/span>Update语句的最佌\径时, ORACLE优化器将使用索引. 同样在联l多个表时用烦引也可以提高效率. 另一个用烦引的好处?/span>,它提供了主键(primary key)的唯一性验?/span>.。那?/span>LONG?/span>LONG RAW数据cd, 你可以烦引几乎所有的?/span>. 通常, 在大型表中用烦引特别有?/span>. 当然,你也会发?/span>, 在扫描小表时,使用索引同样能提高效?/span>. 虽然使用索引能得到查询效率的提高,但是我们也必L意到它的代h. 索引需要空间来存储,也需要定期维?/span>, 每当有记录在表中增减或烦引列被修Ҏ, 索引本n也会被修?/span>. q意味着每条记录?/span>INSERT , DELETE , UPDATEؓ此多付出4 , 5 ơ的盘I/O . 因ؓ索引需要额外的存储I间和处?/span>,那些不必要的索引反而会使查询反应时间变?/span>.。定期的重构索引是有必要?/span>.Q?/span>
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
Q?/span>18Q?/span> ?/span>EXISTS替换DISTINCTQ?/span>
当提交一个包含一对多表信?/span>(比如部门表和雇员?/span>)的查询时,避免?/span>SELECT子句中?/span>DISTINCT. 一般可以考虑?/span>EXIST替换, EXISTS 使查询更?/span>,因ؓRDBMS核心模块在子查询的条g一旦满_,立刻q回l果. 例子Q?/span>
(低效):
SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E
WHERE D.DEPT_NO = E.DEPT_NO
(高效):
SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X'
FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);
Q?/span>19Q?/span> sql语句用大写的Q因?/span>oracleL先解?/span>sql语句Q把写的字母{换成大写的再执行
Q?/span>20Q?/span> ?/span>java代码中尽量少用连接符“Q?#8221;q接字符Ԍ
Q?/span>21Q?/span> 避免在烦引列上?/span>NOT 通常Q
我们要避免在索引列上使用NOT, NOT会生在和在索引列上使用函数相同的媄?/span>. ?/span>ORACLE”遇到”NOT,他就会停止用烦引{而执行全表扫?/span>.
Q?/span>22Q?/span> 避免在烦引列上用计.
WHERE子句中,如果索引列是函数的一部分Q优化器不使用索引而用全表扫描.
举例:
低效Q?/span>
SELECT … FROM DEPT WHERE SAL * 12 > 25000;
高效:
SELECT … FROM DEPT WHERE SAL > 25000/12;
Q?/span>23Q?/span> ?/span>>=替代>
高效:
SELECT * FROM EMP WHERE DEPTNO >=4
低效:
SELECT * FROM EMP WHERE DEPTNO >3
两者的区别在于, 前?/span>DBMS直接蟩到第一?/span>DEPT{于4的记录而后者将首先定位?/span>DEPTNO=3的记录ƈ且向前扫描到W一?/span>DEPT大于3的记?/span>.
Q?/span>24Q?/span> ?/span>UNION替换OR (适用于烦引列)
通常情况?/span>, ?/span>UNION替换WHERE子句中的OR会起到较好的效?/span>. 对烦引列使用OR造成全表扫描. 注意, 以上规则只针对多个烦引列有效. 如果?/span>column没有被烦?/span>, 查询效率可能会因Z没有选择OR而降?/span>. 在下面的例子?/span>, LOC_ID ?/span>REGION上都建有索引.
高效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10
UNION
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE REGION = “MELBOURNE”
低效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10 OR REGION = “MELBOURNE”
如果你坚持要?/span>OR, 那就需要返回记录最的索引列写在最前面.
Q?/span>25Q?/span> ?/span>IN来替?/span>OR
q是一条简单易记的规则Q但是实际的执行效果q须验,?/span>ORACLE8i下,两者的执行路径g是相同的Q
低效:
SELECT…. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30
高效
SELECT… FROM LOCATION WHERE LOC_IN IN (10,20,30);
Q?/span>26Q?/span> 避免在烦引列上?/span>IS NULL?/span>IS NOT NULL
避免在烦引中使用M可以为空的列Q?/span>ORACLE无法用该索引Q对于单列烦引,如果列包含空|索引中将不存在此记录. 对于复合索引Q如果每个列都ؓI,索引中同样不存在此记?/span>. 如果臛_有一个列不ؓI,则记录存在于索引中.举例: 如果唯一性烦引徏立在表的A列和B列上, q且表中存在一条记录的A,Bgؓ(123,null) , ORACLE不接受下一条具有相?/span>A,B|123,nullQ的记录(插入). 然而如果所有的索引列都为空Q?/span>ORACLE认为整个键gؓI空不等于空. 因此你可以插?/span>1000 条具有相同键值的记录,当然它们都是I?/span>! 因ؓIg存在于烦引列?/span>,所?/span>WHERE子句中对索引列进行空值比较将?/span>ORACLE停用该烦?/span>.
低效: (索引失效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL;
高效: (索引有效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE >=0;
Q?/span>27Q?/span> L使用索引的第一个列Q?/span>
如果索引是徏立在多个列上, 只有在它的第一个列(leading column)?/span>where子句引用?/span>,优化器才会选择使用该烦?/span>. q也是一条简单而重要的规则Q当仅引用烦引的W二个列?/span>,优化器用了全表扫描而忽略了索引
Q?/span>28Q?/span> ?/span>UNION-ALL 替换UNION ( 如果有可能的?/span>)Q?/span>
?/span>SQL 语句需?/span>UNION两个查询l果集合?/span>,q两个结果集合会?/span>UNION-ALL的方式被合ƈ, 然后在输出最l结果前q行排序. 如果?/span>UNION ALL替代UNION, q样排序׃是必要了. 效率׃因此得到提高. 需要注意的是,UNION ALL 重复输Z个结果集合中相同记录. 因此各位q是要从业务需求分析?/span>UNION ALL的可行?/span>. UNION 对l果集合排序,q个操作会用到SORT_AREA_SIZEq块内存. 对于q块内存的优化也是相当重要的. 下面?/span>SQL可以用来查询排序的消耗量
低效Q?/span>
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
高效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION ALL
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
Q?/span>29Q?/span> ?/span>WHERE替代ORDER BYQ?/span>
ORDER BY 子句只在两种严格的条件下使用索引.
ORDER BY中所有的列必d含在相同的烦引中q保持在索引中的排列序.
ORDER BY中所有的列必d义ؓ非空.
WHERE子句使用的烦引和ORDER BY子句中所使用的烦引不能ƈ?/span>.
例如:
?/span>DEPT包含以下?/span>:
DEPT_CODE PK NOT NULL
DEPT_DESC NOT NULL
DEPT_TYPE NULL
低效: (索引不被使用)
SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_TYPE
高效: (使用索引)
SELECT DEPT_CODE FROM DEPT WHERE DEPT_TYPE > 0
Q?/span>30Q?/span> 避免改变索引列的cd.:
当比较不同数据类型的数据?/span>, ORACLE自动对列q行单的cd转换.
假设 EMPNO是一个数值类型的索引?/span>.
SELECT … FROM EMP WHERE EMPNO = ‘123'
实际?/span>,l过ORACLEcd转换, 语句转化?/span>:
SELECT … FROM EMP WHERE EMPNO = TO_NUMBER(‘123')
q运的是,cd转换没有发生在烦引列?/span>,索引的用途没有被改变.
现在,假设EMP_TYPE是一个字W类型的索引?/span>.
SELECT … FROM EMP WHERE EMP_TYPE = 123
q个语句?/span>ORACLE转换?/span>:
SELECT … FROM EMP WHERETO_NUMBER(EMP_TYPE)=123
因ؓ内部发生的类型{?/span>, q个索引不会被用到! Z避免ORACLE对你?/span>SQLq行隐式的类型{?/span>, 最好把cd转换用显式表现出?/span>. 注意当字W和数值比较时, ORACLE会优先{换数值类型到字符cd
Q?/span>31Q?/span> 需要当心的WHERE子句:
某些SELECT 语句中的WHERE子句不用烦?/span>. q里有一些例?/span>.
在下面的例子?/span>, (1)‘!=' 不使用索引. C, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表?/span>. (2) ‘||'是字W连接函?/span>. p其他函数那样, 停用了烦?/span>. (3) ‘+'是数学函?/span>. p其他数学函数那样, 停用了烦?/span>. (4)相同的烦引列不能互相比较,q将会启用全表扫?/span>.
Q?/span>32Q?/span> a. 如果索数据量过30%的表中记录数.使用索引没有显著的效率提高.
b. 在特定情况下, 使用索引也许会比全表扫描?/span>, 但这是同一个数量上的区别. 而通常情况?/span>,使用索引比全表扫描要块几倍乃臛_千?/span>!
Q?/span>33Q?/span> 避免使用耗费资源的操?/span>:
带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY?/span>SQL语句会启?/span>SQL引擎
执行耗费资源的排?/span>(SORT)功能. DISTINCT需要一ơ排序操?/span>, 而其他的臛_需要执行两ơ排?/span>. 通常, 带有UNION, MINUS , INTERSECT?/span>SQL语句都可以用其他方式重写. 如果你的数据库的SORT_AREA_SIZE调配得好, 使用UNION , MINUS, INTERSECT也是可以考虑?/span>, 毕竟它们的可L很?/span>
Q?/span>34Q?/span> 优化GROUP BY:
提高GROUP BY 语句的效?/span>, 可以通过不需要的记录?/span>GROUP BY 之前qo?/span>.下面两个查询q回相同l果但第二个明显快了许?/span>.
低效:
SELECT JOB , AVG(SAL)
FROM EMP
GROUP JOB
HAVING JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
高效:
SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
GROUP JOB