ä¸?、问题的提出
ã€?在应用系统开发初期,由于å¼?发数æ�?º“数据比较少,对于查è?SQLè¯?�¥,å?杂è?图的的编写等体会不出SQLè¯?�¥各ç?写法的æ?§能优劣,但æ˜??果将应用系统提交实际应用后,随着数据库中数据的å?加,系统的响应é?Ÿ度就成为目前系统需要解决的æœ?主è?的问题之ä¸?。系统优化中ä¸?ä¸?¾ˆ重è?的方面就是SQLè¯?�¥的优化ã?‚å?于海量数æ�?¼Œ劣质SQLè¯?�¥和优质SQLè¯?�¥之间的é?Ÿ度å·?ˆ«å�?»¥达到上百倍,å�??对于ä¸?ä¸?³»统不æ˜?®€单地能实现其功能就可,è?Œ是要写出高质量的SQLè¯?�¥,提高系统的å�?”¨性ã??
ã€?ã€?在å?数情况下,Oracle使用索引来更å¿?œ°遍历è¡?¼Œ优化器主要根æ�?®š义的索引来提高æ?§能。但æ˜?¼Œ如果在SQLè¯?�¥的where子句ä¸?†™的SQL代码不合理,就会造成优化器删去索引è?Œ使用全表扫描,ä¸?èˆ?°±这ç?SQLè¯?�¥就是æ‰?谓的劣质SQLè¯?�¥。在编写SQLè¯?�¥时我ä»?º”清æ?优化器根æ�?½•种原则来删除索引,这有助于写出高性能的SQLè¯?�¥ã€?
ã€?ã€?二ã?�SQLè¯?�¥编写注意é—??
ã€?ã€?下面就某些SQLè¯?�¥的where子句编写ä¸?œ€要注意的é—??作è?细介绍ã?‚在这些where子句ä¸?¼Œ即使某些列存在索引,但是由于编写了劣质的SQL,系统在运è?è¯?QLè¯?�¥时也不能使用该索引,而同样使用全表扫描,这就造成了响应é?Ÿ度的极大降低ã??
��1. IS NULL �IS NOT NULL
ã€?ã€?不能用null作索引,任何包含null值的列都将不会è?包含在索引中。即使索引有多列这样的情况下,只要这些列ä¸?œ‰ä¸?列含有null,è?列就会从索引ä¸?Ž’除ã?‚也就是说å?果某列存在空值,即使对è?列建索引也不会提高æ?§能ã€?
ã€?ã€?任何在where子句ä¸?½¿用is null或is not null的è?句优化器æ˜?¸�允è?使用索引的ã??
ã€?ã€?2. 联接åˆ?
ã€?ã€?对于有联接的列,即使æœ?后的联接值为ä¸?ä¸?�™态å?¼,优化器是不会使用索引的ã?‚我ä»?¸€起来看一ä¸?¾‹子,假定有一ä¸?�Œ工表(employee),å?于一ä¸?�Œ工的姓和名分成两列存æ”?FIRST_NAME和LAST_NAME),现在è?查è?ä¸?ä¸?�«比尔.克林é¡?Bill Cliton)的职工ã??
ã€?ã€?下面æ˜?¸€ä¸?‡‡用联接查询的SQLè¯?�¥ï¼?
select * from employss where first_name||''||last_name ='Beill Cliton';
上面这条è¯?�¥完全å�?»¥查è?出是否有Bill Cliton这个员工,但æ˜?¿™里需要注意,系统优化器å?基于last_name创建的索引没有使用ã??
ã€?ã€?当采用下面这种SQLè¯?�¥的编写,Oracle系统就可以采用基于last_name创建的索引ã??
*** where first_name ='Beill' and last_name ='Cliton';
. 带é?š配ç¬?%)的likeè¯?�¥
ã€?ã€?同样以上面的例子来看这ç?情况。目前的éœ?求是这样的,要求在职工表ä¸?Ÿ¥询名字中包含cliton的人。可以采用å?下的查è?SQLè¯?�¥:
select * from employee where last_name like '%cliton%';
这里由于通配ç¬?%)在搜寻词首出现,æ‰?ä»?racle系统不使用last_name的索引ã?‚在很å?情况下可能无法避免这种情况,但是ä¸?定è?心中有底,é?š配符å?此使用会降低查è?速度。然而当通配符出现在字ç?串其他位ç½?—¶,优化器就能利用索引。在下面的查è¯?¸索引得到了使ç”?
select * from employee where last_name like 'c%';
4. Order byè¯?�¥
ã€?ã€?ORDER BYè¯?�¥决定了Oracle如何将返回的查è?结果排序。Order byè¯?�¥对è?排序的列没有ä»?么特åˆ?š„限制,也å�?»¥将函数加入列ä¸?象联接或者附加等)。任何在Order byè¯?�¥的非索引项或者有计算表达式都将降低查询é?Ÿ度ã€?
ã€?ã€?仔细æ£?æŸ?rder byè¯?�¥以找出非索引项或者表达式,它ä»?¼š降低性能。解决这ä¸?—®题的办法就是重写order byè¯?�¥以使用索引,也可以为æ‰?使用的列建立另å?ä¸?ä¸?´¢引,同时应绝对避免在order by子句ä¸?½¿用表达式ã€?
5. NOT
ã€?ã€?我们在查询时经常在where子句使用ä¸?些é?»辑表达式,如大于ã?�小于ã?�等于以及不等于等等,也å�?»¥使用and(ä¸?、or(æˆ?以及not(é�?。NOTå�?”¨来å?任何逻辑运算符号取反。下面是ä¸?个NOT子句的例å?
... where not (status ='VALID')
如果要使用NOT,则应在取反的短è¯?‰�面加上括号,并在çŸ??前面加上NOT运算符ã?‚NOT运算符包å�?œ¨另å?ä¸?ä¸??»辑运算符中,这就是不等äº?<>)运算符ã?‚换句话说,即使不在查è?where子句ä¸?˜¾式地加入NOT词,NOT仍在运算符中,è?下例:
... where status <>'INVALID';
对这ä¸?Ÿ¥è¯?¼Œå�?»¥改写为不使用NOT:
select * from employee where salary<3000 or salary>3000;
虽然这两种查询的结果ä¸?样,但是ç¬?ºŒ种查询方案会比ç?ä¸?种查询方案更å¿?º›。ç?二ç?查è?允è?Oracle对salary列使用索引,而ç?ä¸?种查询则不能使用索引ã€?
虽然这两种查询的结果ä¸?样,但是ç¬?ºŒ种查询方案会比ç?ä¸?种查询方案更å¿?º›。ç?二ç?查è?允è?Oracle对salary列使用索引,而ç?ä¸?种查询则不能使用索引ã€?
===============================================================================================
我们要做到不但会写SQL,还è?做到写出性能优良的SQL,以下为笔者å?习ã?�摘录ã?�并汇æ?»部分资料与大å?分享ï¼?
ï¼?ï¼?nbsp; 选择æœ?有效率的表名顺序(å�?œ¨基于规则的优化器ä¸?œ‰æ•?ï¼?
ORACLE 的解析器按照从右到左的顺序å?理FROM子句ä¸?š„表名,FROM子句ä¸?†™在最后的è¡?基ç?è¡?driving table)将è?æœ?先å?理,在FROM子句ä¸?Œ…å�??ä¸?¡¨的情况下,你必须é?‰择记录条数æœ?少的表作为基ç¡?表ã?‚å?果有3ä¸?»¥上的表连接查è¯? 那就éœ?要é?‰择交叉è¡?intersection table)作为基ç?è¡? 交叉表是指那ä¸??其他表所引用的表.
ï¼?ï¼?nbsp; WHERE子句ä¸?š„连接顺序.:
ORACLE采用è‡?¸‹而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些å�?»¥过滤掉最大数量è?录的条件必须写在WHERE子句的末å°?
ï¼?ï¼?nbsp; SELECT子句ä¸?�¿免使ç”?â€?* ‘:
ORACLE在解析的过程ä¸? 会将'*' 依æ?è½?�¢成所有的列名, 这个工作æ˜??š过查è?数据字典完成çš? 这意味着将è?—费更å?的时é—?
ï¼?ï¼?nbsp; 减少访问数据库的次数ï¼?
ORACLE在内部执行了许å?工作: 解析SQLè¯?�¥, 估算索引的利用率, 绑定变量 , 读数æ�?�—等;
ï¼?ï¼?nbsp; 在SQL*Plus , SQL*Forms和Pro*Cä¸?‡�新è?置ARRAYSIZE参数, å�?»¥增加每æ?数据库è?é—?š„æ£?索数æ�?‡� ,建è?值为200
ï¼?ï¼?nbsp; 使用DECODE函数来减少å?理时间:
使用DECODE函数å�?»¥避免重å?æ‰?��相同记录或重复连接相同的è¡?
ï¼?ï¼?nbsp; 整合ç®?å�?无关联的数据库è?é—?¼š
如果你有几个ç®?单的数据库查询è?å�?你可以把它们整合到一ä¸?Ÿ¥è¯?¸(即使它们之间没有关系)
ï¼?ï¼?nbsp; 删除重å?记录ï¼?
æœ?高效的删除重复è?录方æ³?( 因为使用了ROWID)例子ï¼?
DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
ï¼?ï¼?nbsp; 用TRUNCATE替代DELETEï¼?
当删除表ä¸?š„记录æ—?在é?š常情况ä¸? 回滚æ®?rollback segments ) 用来存放å�?»¥è¢?�¢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢å?到删除之前的状æ??准确地è?æ˜?�¢复到执è?删除命令之前的状å†? 而当运用TRUNCATEæ—? 回滚段不再存放任何可è¢?�¢复的信息.当命令运行后,数据不能è¢?�¢å¤?因æ?很少的资源è?调用,执è?时间也会很短. (译è?…按: TRUNCATEå�?œ¨删除全表适用,TRUNCATE是DDL不是DML)
ï¼?0ï¼?尽量多使用COMMITï¼?
å�??有可èƒ?在程序中尽量多使用COMMIT, 这样程序的æ?§能得到提高,éœ?求也会因为COMMITæ‰?释放的资源è?Œ减å°?
COMMITæ‰?释放的资æº?
a. 回滚段上用于恢å?数据的信æ�?
b. è¢?¨‹序è?句获得的é”?
c. redo log buffer ä¸?š„空间
d. ORACLE为ç?理上è¿?种资源中的内部花è´?
ï¼?1ï¼?用Where子句替换HAVING子句ï¼?
避免使用HAVING子句, HAVING å�?¼š在æ?索出æ‰?有è?录之后才对结果集进è?过滤. 这个处理éœ?要排åº?总è?等操ä½? 如果能é?š过WHERE子句限制记录的数ç›?那就能减少这方面的开é”?. (非oracleä¸?on、where、having这三ä¸?ƒ½å�?»¥加条件的子句ä¸?¼Œonæ˜?œ€先执行,where次之,havingæœ?后,因为onæ˜?…ˆ把不 符合条件的è?录过滤后才进行统计,它就å�?»¥减少ä¸?—´运算要å?理的数据,按理è?应è?速度æ˜?œ€å¿?š„,where也应该比havingå¿?‚¹的,因为它过滤数æ�?�Ž 才进行sum,在两个表联接时才用on的,æ‰?以在ä¸?ä¸?¡¨的时候,就剩下where跟having比较了ã?‚在这单表查询统计的情况下,如果要过滤的条件没有涉及到è?计算字æ?,那它们的结果是ä¸?样的,只是whereå�?»¥使用rushmoreæŠ?æœ?¼Œ而having就不能,在é?Ÿ度上后者è?慢å?果è?涉及到è?算的å?段,就表示在没è?算之前,这个字æ?的å?¼是不确定的,根æ�?¸Š篇写的工作流程,where的作用时间是在è?算之前就完成的,而having就是在è?算后才起ä½?用的,所以在这ç?情况下,两è?…的结果会不同ã?‚在多表联接查è?时,on比where更早起作用ã?‚系统é?先根æ�?�„ä¸?¡¨之间的联接条件,把å?ä¸?¡¨合成ä¸?ä¸?¸´时表 后,再由where进è?过滤,然后再计算,è?算完后再由having进è?过滤。由此可见,要想过滤条件起到正确的作ç”?¼Œ首先要明白这ä¸?�¡件应该在ä»?么时候起作用,然后再决定放在那里
ï¼?2ï¼?减少对表的查è¯?¼š
在含有子查è?的SQLè¯?�¥ä¸?要特åˆ?³¨意减少å?表的查è?.例子ï¼?
SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
ï¼?3ï¼?通过内部函数提高SQL效率.ï¼?
复杂的SQLå¾?å¾?牺牲了执行效çŽ? 能å?掌握上面的运用函数解决问题的方法在实际工作中æ˜?�ž常有意义çš?
ï¼?4ï¼?使用表的åˆ?��(Alias)ï¼?
当在SQLè¯?�¥ä¸?¿ž接å?ä¸?¡¨æ—? 请使用表的别名并把别名前ç¼?于每个Columnä¸?这样ä¸?æ�?就可以减少解析的时间并减少那些由Column歧义引起的è?法错è¯?
ï¼?5ï¼?用EXISTS替代IN、用NOT EXISTS替代NOT INï¼?
在è?多基于基ç¡?表的查è?ä¸?为了满足ä¸?ä¸?�¡ä»?å¾?å¾?éœ?要å?另一ä¸?¡¨进è?联接.在这种情况下, 使用EXISTS(或NOT EXISTS)通常将提高查询的效率. 在子查è?ä¸?NOT IN子句将执行一ä¸?†…部的排序和合å¹? 无è?在哪种情况下,NOT IN都是æœ?低效çš?(因为它å?子查è¯?¸的表执è?了一ä¸?…¨表遍åŽ?. 为了避免使用NOT IN ,我们å�?»¥把它改写成å?连接(Outer Joins)或NOT EXISTS.
例子ï¼?
(高效)SELECT * FROM EMP (基ç?è¡? WHERE EMPNO > 0 AND EXISTS (SELECT ‘X' FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB')
(低效)SELECT * FROM EMP (基ç?è¡? WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB')
ï¼?6ï¼?识别'低效执è?'的SQLè¯?�¥ï¼?
虽然ç›?‰�各ç?关于SQL优化的图形化工具层出不穷,但是写出è‡?·±的SQL工具来解决问题å?终是ä¸?ä¸?œ€好的方法ï¼?
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;
ï¼?7ï¼?用索引提高效率:
索引æ˜?¡¨的一ä¸??念部åˆ?用来提高æ£?索数æ�?š„效率,ORACLE使用了一ä¸??杂的è‡?¹³è¡?-tree结构. 通常,通过索引查è?数据比全表扫描è?å¿? 当ORACLE找出执è?查è?和Updateè¯?�¥的最佳路径时, ORACLE优化器将使用索引. 同样在联结å?ä¸?¡¨时使用索引也å�?»¥提高效率. 另一ä¸?½¿用索引的好å?æ˜?它提供了主键(primary key)的唯ä¸?性验è¯?。那些LONG或LONG RAW数据类型, 你可以索引几乎所有的åˆ? 通常, 在大型表ä¸?½¿用索引特åˆ?œ‰æ•? 当然,你也会发çŽ? 在扫描小表时,使用索引同样能提高效çŽ? 虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价. 索引éœ?要空间来存储,也需要定期维æŠ? 每当有è?录在表中增减或索引列è¢?¿®改时, 索引æœ?º«也会è¢?¿®æ”? 这意味着每条记录的INSERT , DELETE , UPDATE将为此å?付出4 , 5 次的磁盘I/O . 因为索引éœ?要é?外的存储空间和å?ç�?那些不必要的索引反è?Œ会使查询反应时间变æ…?。定期的重构索引æ˜?œ‰必è?çš?ï¼?
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
18ï¼?用EXISTS替换DISTINCTï¼?
当提交一ä¸?Œ…å�?¸€对å?表信æ�?比å?部门表和雇员è¡?的查询时,避免在SELECT子句ä¸?½¿用DISTINCT. ä¸?èˆ?�¯以è?ƒ虑用EXIST替换, EXISTS 使查询更为迅é€?因为RDBMS核心模块将在子查询的条件ä¸?旦满足后,立刻返回结果. 例子ï¼?
(低效):
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);
ï¼?9ï¼?sqlè¯?�¥用大写的;因为oracle总是先解析sqlè¯?�¥,把小写的字母转换成大写的再执è?
ï¼?0ï¼?在java代码ä¸?°½量少用连接ç?“+”连接字符串ï¼?
ï¼?1ï¼?避免在索引列上使用NOT 通常,ã??
我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的影å“? 当ORACLE”遇到â?�NOT,他就会停æ?½¿用索引转而执行全表扫æ�?
ï¼?2ï¼?避免在索引列上使用è?算.
WHERE子句ä¸?¼Œ如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描.
举例:
低效ï¼?
SELECT �FROM DEPT WHERE SAL * 12 > 25000;
高效:
SELECT �FROM DEPT WHERE SAL > 25000/12;
ï¼?3ï¼?ç”?gt;=替代>
高效:
SELECT * FROM EMP WHERE DEPTNO >=4
低效:
SELECT * FROM EMP WHERE DEPTNO >3
两è?…的区别在于, 前è?…DBMS将直接跳到ç?ä¸?个DEPT等于4的è?录è?Œ后者将首先定位到DEPTNO=3的è?录并且向前扫描到ç¬?¸€个DEPT大于3的è?å½?
ï¼?4ï¼?用UNION替换OR (适用于索引列)
通常情况ä¸? 用UNION替换WHERE子句ä¸?š„OR将会起到较好的效æž? 对索引列使用OR将é? 成全表æ‰?��. 注意, 以上规则å�?’ˆ对å?ä¸?´¢引列有效. 如果有column没有è¢?´¢å¼? 查è?效率å�?ƒ½会因为你没有选择OR而降ä½? 在下面的例子ä¸? LOC_ID 和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â€?
如果你坚持è?用OR, 那就éœ?要返回è?录最少的索引列写在最前面.
ï¼?5ï¼?用IN来替æ�?R
这是ä¸?条简单易记的规则,但æ˜?®ž际的执è?效果还须æ£?验,在ORACLE8i下,两è?…的执è?è·?¾„似乎æ˜?›¸同的.ã??
低效:
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);
ï¼?6ï¼?避免在索引列上使用IS NULL和IS NOT NULL
避免在索引中使用任何å�?»¥为空的列,ORACLE将无法使用è?索引.å?于单列索引,如果列包å�?©º值,索引ä¸?°†不存在æ?记录. 对于复合索引,å?果每ä¸?ˆ—都为空,索引ä¸?�Œ样不存在此è?å½?ã€?如果至少有一ä¸?ˆ—不为空,则è?录存在于索引ä¸?¼Ž举例: 如果å”?¸€性索引建立在表的A列和B列上, 并且表中存在ä¸?条è?录的A,B值为(123,null) , ORACLE将不接受下一条具有相同A,B值(123,null)的记录(插入). 然è?Œå?果所有的索引列都为空,ORACLE将è?为整ä¸?”®值为空è?Œ空不等于空. 因æ?你可以插å…?000 条具有相同键值的记录,当然它们都是ç©? 因为空å?¼不存在于索引列ä¸?æ‰?ä»?HERE子句ä¸??索引列进行空值比较将使ORACLE停用该索å¼?
低效: (索引失效)
SELECT �FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL;
高效: (索引有效)
SELECT �FROM DEPARTMENT WHERE DEPT_CODE >=0;
ï¼?7ï¼?总是使用索引的ç?ä¸?ä¸?ˆ—ï¼?
如果索引æ˜?»º立在多个列上, å�?œ‰在它的ç?ä¸?ä¸?ˆ—(leading column)被where子句引用æ—?优化器才会é?‰择使用该索å¼? 这也æ˜?¸€条简单è?Œ重要的规则,当仅引用索引的ç¬?ºŒä¸?ˆ—æ—?优化器使用了全表æ‰?��而忽略了索引
28ï¼?用UNION-ALL 替换UNION ( 如果有可能的è¯?ï¼?
当SQL è¯?�¥éœ?要UNION两个查è?结果集合æ—?这两ä¸?»“果集合会ä»?NION-ALL的方式è?合并, 然后在输出最终结果前进è?排序. 如果用UNION ALL替代UNION, 这样排序就不æ˜?¿…要了. 效率就会因æ?得到提高. éœ?要注意的æ˜?¼ŒUNION ALL 将重复输出两ä¸?»“果集合中相同记录. 因æ?各位还是要从业务éœ?求分析使用UNION ALL的可行æ?? UNION 将å?结果集合排序,这个操作会使用到SORT_AREA_SIZE这块内存. 对于这块内存的优化也æ˜?›¸当重要的. 下面的SQLå�?»¥用来查è?排序的消耗量
低效ï¼?
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'
ï¼?9ï¼?用WHERE替代ORDER BYï¼?
ORDER BY 子句å�?œ¨两ç?严格的条件下使用索引.
ORDER BYä¸?‰€有的列必须包å�?œ¨相同的索引中并保持在索引ä¸?š„排列顺序.
ORDER BYä¸?‰€有的列必须定义为非空.
WHERE子句使用的索引和ORDER BY子句ä¸?‰€使用的索引不能并åˆ?
例å?:
表DEPT包含以下åˆ?
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
ï¼?0ï¼?避免改变索引列的类型.:
当比较不同数æ�?±»型的数据æ—? ORACLEè‡?Ѝ对列进è?ç®?单的类型è½?�¢.
假è? EMPNOæ˜?¸€ä¸?•°值类型的索引åˆ?
SELECT �nbsp; FROM EMP WHERE EMPNO = �23'
实际ä¸?经过ORACLE类型è½?�¢, è¯?�¥è½?Œ–ä¸?
SELECT �nbsp; FROM EMP WHERE EMPNO = TO_NUMBER(�23')
幸运的是,类型è½?�¢没有发生在索引列ä¸?索引的用途没有è?改变.
现在,假è?EMP_TYPEæ˜?¸€ä¸?—符类型的索引åˆ?
SELECT �nbsp; FROM EMP WHERE EMP_TYPE = 123
这个è¯?�¥被ORACLEè½?�¢ä¸?
SELECT �nbsp; FROM EMP WHERETO_NUMBER(EMP_TYPE)=123
因为内部发生的类型转æ�? 这个索引将不会è?用到! 为了避免ORACLE对你的SQL进è?隐式的类型转æ�? æœ?好把类型è½?�¢用显式表现出æ�? 注意当字符和数å?¼比较时, ORACLE会优先转换数值类型到字ç?类型
ï¼?1ï¼?éœ?要当心的WHERE子句:
某些SELECT è¯?�¥ä¸?š„WHERE子句不使用索å¼? 这里有一些例å?
在下面的例子é‡? (1)â€?=' 将不使用索引. 记住, 索引å�?ƒ½告诉你什么存在于表中, 而不能告诉你ä»?么不存在于表ä¸? (2) â€?¦ ¦'æ˜?—符连接函æ•? 就象其他函数那样, 停用了索å¼? (3) â€?'æ˜?•°学函æ•? 就象其他数å?函数那样, 停用了索å¼? (4)相同的索引列不能互相比较,这将会启用全表扫æ�?
ï¼?2ï¼?a. 如果æ£?索数æ�?‡�超过30%的表ä¸??录数.使用索引将没有显著的效率提高.
b. 在特定情况下, 使用索引也è?会比全表æ‰?��æ…? 但这æ˜?�Œä¸?ä¸?•°量级上的区别. 而é?š常情况ä¸?使用索引比全表扫描è?块几倍乃至几千å??
ï¼?3ï¼?避免使用耗费资源的操ä½?
带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQLè¯?�¥会启动SQL引擎
执è?耗费资源的排åº?SORT)功能. DISTINCTéœ?要一次排序操ä½? 而其他的至少éœ?要执行两次排åº? 通常, 带有UNION, MINUS , INTERSECT的SQLè¯?�¥都可以用其他方式重写. 如果你的数据库的SORT_AREA_SIZE调配得好, 使用UNION , MINUS, INTERSECT也是å�?»¥考虑çš? 毕竟它们的可读æ?§很å¼?
ï¼?4ï¼?优化GROUP BY:
提高GROUP BY è¯?�¥的效çŽ? å�?»¥通过将不éœ?要的记录在GROUP BY 之前过滤æŽ?下面两个查è?返回相同结果但ç?二个明显就快了è?å¤?
低效:
SELECT JOB , AVG(SAL)
FROM EMP
GROUP by JOB
HAVING JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
高效:
SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB = ‘PRESIDENT'
OR JOB = ‘MANAGER'
GROUP by JOB
====================================
====================================
如果你æ?在负责一ä¸?Ÿº于SQL Server的项ç›?¼Œ或è?…你刚刚接触SQL Server,你都有å�?ƒ½要面临一些数æ�?º“性能的问题,这篇文章会为你提供一些有用的指å?(其ä¸?¤§多数也可以用于其它的DBMS)ã??
在这里,我不打算介绍使用SQL Server的窍é—?¼Œ也不能提供一ä¸?Œ…治百病的方æ?,我æ‰?做的æ˜??»结ä¸?些经éª?---关于如何形成ä¸?ä¸?¥½的è?计ã?‚这些经验来è‡?ˆ‘过去几年ä¸?»�受的教è?,一直来,我看到许å?同样的è?计错è¯??ä¸?次又ä¸?次的重å?ã€?
ä¸?、了解你用的工具
不è?轻è?这一点,这是我在这篇文章ä¸??述的æœ?关键的一条ã?‚也许你也看到有很å?的SQL Server程序员没有掌握全部的T-SQL命令和SQL Server提供的那些有用的工具ã€?
“什么?我è?æµ?´¹ä¸?ä¸?œˆ的时间来学习那些我永远也不会用到的SQL命令???â?�,你也许会这样说ã?‚å?的,你不éœ?要这样做。但æ˜?½ 应è?用一ä¸?‘¨æœ?µ�览所有的 T-SQL命令。在这里,你的任务是了解,将来,当你设è?ä¸?ä¸?Ÿ¥询时,你会è?起来:â?œå?了,这里有一ä¸?‘½令可以完全实现我éœ?要的功能”,于是,到MSDN 查看这个命令的确切è?法ã??
二ã?�不要使用游æ ?
让我再重复一遍:不è?使用游标。å?果你想破坏整ä¸?³»统的性能的话,它ä»??’是你最有效的é?选办法ã?‚大多数的初学è?…都使用游标,è?Œ没有意识到它们对æ?§能造成的影响ã?‚它ä»?� 用内存,还用它们那些不可思è?的方式锁定表,另外,它们ç®?直就像蜗牛ã?‚è?Œ最糟糕的是,它ä»?�¯以使你的DBAæ‰?能做的一切æ?§能优化等于没做。不 知你æ˜?�¦知道每执行一æ¬?ETCH就等于执行一æ¬?ELECT命令?这意味ç�?如果你的游标æœ?0000条è?录,它将执è?10000æ¬?ELECT!å?果你 使用ä¸?组SELECT、UPDATE或è?…DELETE来完成相应的工作,那将有效率的å?ã€?
初å?者一èˆ??为使用游标是ä¸?种比较熟悉和舒é?‚的编程方式,可很不幸,这会导致糟糕的æ?§能。显然,SQL的æ?»体ç›?š„æ˜?½ 要实现什么,而不æ˜??Ž样实现ã€?
我曾经用T-SQL重写了一ä¸?Ÿº于游标的存储过程,那ä¸?¡¨å�?œ‰100,000条è?录,原来的存储过程用äº?0分钟才执行完毕,而新的存储过程只用了10秒钟。在这里,我想你应è?å�?»¥看到ä¸?ä¸?¸�称职的程序员究竟在干了什么!!!
我们å�?»¥写一ä¸?°�程序来取得和处理数据并且更新数据库,这样做有时会更有效ã?‚è?住:对于å¾?ޝ,T-SQL无能为力ã€?
我再重新提醒ä¸?下:使用游标没有好å?。除了DBA的工作å?,我从来没有看到过使用游标可以有效的完成任何工作ã€?
三ã?�è?范化你的数据è¡?
为什么不规范化数æ�?º“?大概有两个借口:出于æ?§能的è?ƒ虑和纯粹因为懒惰ã?‚至于ç?二点,你迟早得为此付出代价ã?‚è?Œ关于æ?§能的问题,你不éœ?要优化根æœ?°±不慢的东西ã?‚我经常看到ä¸?些程序员“反规范化â?�数æ�?º“,他ä»?š„理由æ˜??œ原来的设è?å¤?…¢了â?�,å�?»“果却常常æ˜?»–ä»??系统更慢了ã?‚DBMSè¢??计用来å?理è?范数æ�?º“ 的,因æ?,è?住:按照规范化的要求设è?数据库ã??
四ã?�不要使用SELECT *
这点不太容易做到,我å¤?º†解了,因为我è‡?·±就经常这样干。可æ˜?¼Œ如果在SELECTä¸?Œ‡定你æ‰?éœ?要的列,那将会带来以下的好å?ï¼?
1 减少内存耗费和网络的带å?
2 你可以得到更安全的è?è®?
3 给查è¯?¼˜化器机会从索引è?取所有需要的åˆ?
五ã?�了解你将è?对数æ�?¿›行的操作
为你的数æ�?º“创建ä¸?ä¸?�¥å£?š„索引,那å�?˜¯功德ä¸?件ã?‚可要做到这ä¸?点简直就æ˜?¸€门艺æœ??‚每当你为一ä¸?¡¨添加ä¸?ä¸?´¢引,SELECT会更å¿?º†,可INSERT 和DELETE却大大的变慢了,因为创建了维护索引需要è?多é?外的工作。显然,这里é—??的关é”?˜¯:你要å?这张表进行什么样的操作ã?‚这ä¸?—®题不å¤?¥½把握,特åˆ?˜¯涉及DELETE和UPDATE时,因为这些è¯?�¥经常在WHERE部分包含SELECT命令ã€?
å…??�不要给“æ?§别”列创建索引
首先,我ä»?¿…须了解索引是如何加é?Ÿå?表的访问的ã?‚你å�?»¥将索引理解为基于ä¸?定的标准上å?表进行划分的ä¸?种方式ã?‚å?果你给类似于“æ?§别”这样的列创建了ä¸?ä¸?索引,你仅仅æ˜?°†表划分为两部分:男和女ã?‚你在å?理一ä¸?œ‰1,000,000条è?录的è¡?¼Œ这样的划分有ä»?么意义?记住:维护索引是比较费时的ã?‚当你è?计索 引时,è?遵循这样的è?则:根据列可能包å�?¸�同内容的数目从å?到少排列,比如:姓名+省份+性别ã€?
七ã?�使用事åŠ?
请使用事务,特别æ˜?½“查è?比较耗时。å?果系统出现问题,这样做会救你ä¸?命的。一èˆ?œ‰些经验的程序员都有体ä¼?----你经常会碰到ä¸?些不å�??料的情况会å?致存储过程崩溃ã??
å…??�小心æ?é”?
按照ä¸?定的次序来è?é—?½ 的表。å?果你先锁住表A,再锁住表B,那么在æ‰?有的存储过程ä¸?ƒ½要按照这ä¸?¡º序来锁定它们。å?果你(不经意的)某个存储过程ä¸?…ˆ锁定表B,再锁定表A,这å�?ƒ½就会导致ä¸?ä¸??锁ã?‚å?果锁定顺序没有è?预先详细的è?计好,æ?锁是不太容易è¢?�‘现的ã€?
九ã?�不要打å¼?大的数据é›?
ä¸?ä¸?»�常è?提出的问题是:我怎样才能迅é?Ÿ的å°?00000条è?录添加到ComboBoxä¸?¼Ÿ这是不å?的,你不能也不需要这样做。很ç®?单,你的用户要浏è§?100000条è?录才能找到需要的记录,他ä¸?定会诅咒你的。在这里,你éœ?要的æ˜?¸€ä¸?›´好的UI,你éœ?要为你的用户显示不超è¿?00æˆ?00条è?录ã??
十ã?�不要使用服务器ç«?¸¸æ ?
与服务器ç«?¸¸标比起来,å?户ç?游标å�?»¥减少服务器和网络的系统开é”?,并且还减少锁定时间ã€?
十一、使用参数查è¯?
有时,我在CSDNæŠ?æœ??坛看到类似这样的é—??:â?œSELECT * FROM a WHERE a.id='A'B,因为单引号查è?发生异常,我该æ?Ž么办?”,而普遍的回答æ˜?¼š用两ä¸?�•引号代替单引号ã?‚这æ˜?”™è¯?š„。这样治标不治本,因为你还会在其ä»?ä¸?些字符上遇到这样的问题,更何况这样会导致严重的bug,除此以外,这样做还会使SQL Server的缓冲系统无法发挥应有的作用。使用参数查è¯?¼Œ釜底抽薪,这些问题统统不存在了ã??
十二、在程序编码时使用大数据量的数据åº?
程序员在å¼?发中使用的测试数æ�?º“ä¸?èˆ?•°æ�?‡�都不大,å�?»�常的æ˜?œ€终用户的数据量都很大。我ä»??š常的做法是不å?的,原因很简单:现在ç¡?›˜不是很贵,可为什么æ?§能é—??却è?等到已经无可挽回的时候才è¢?³¨意呢ï¼?
十三、不要使用INSERT导入大批的数æ�?
请不要这样做,除非那æ˜?¿…须的。使用UTS或è?…BCP,这样你å�?»¥ä¸?举è?Œ兼得灵活æ?§和速度ã€?
十四、注意超时问é¢?
查è?数据库时,一èˆ?•°æ�?º“的缺省都比较小,比å?15秒或è€?0秒ã?‚è?Œ有些查询运行时间è?比这长,特别æ˜?½“数据库的数据量不æ–?�˜大时ã€?
十五、不要忽略同时修改同ä¸?记录的问é¢?
有时候,两个用户会同时修改同ä¸?记录,这样,后一ä¸?¿®改è?…修改了前一ä¸?¿®改è?…的操作,某些更新就会丢失ã?‚å?理这种情况不æ˜?¾ˆ难:创建ä¸?个timestamp字æ?,在写入前æ?查它,å?果允许,就合并修改,如果存在冲突,提示用户ã??
十六、在细节表中插入çº?½•时,不è?在主表执行SELECT MAX(ID)
这是ä¸?ä¸?™®遍的错è?,当两个用户在同ä¸?时间插入数据时,这会导致错è?。你å�?»¥使用SCOPE_IDENTITY,IDENT_CURRENT和IDENTITY。å?果可能,不è?使用IDENTITY,因为在有触发器的情况下,它会引起一些问题(详è?这里的è?论)ã€?
十七、避免将列è?为NULLable
如果å�?ƒ½的话,你应è?避免将列设为NULLable。系统会为NULLable列的每一行分配一ä¸??外的字节,查询时会带来更多的系统å¼?é”?。另外,将列设为NULLable使编码变得å?杂,因为每一次è?é—?¿™些列时都必须先进行æ?查ã??
我并不是说NULLSæ˜?º»烦的根源,尽管有些人这样认为。我认为如果你的业务规则ä¸?…�许â?œ空数据”,那么,将列è?为NULLable有时会发挥很好的作用,但æ˜?¼Œ如果在类似下面的情况ä¸?½¿用NULLable,那ç®?直就æ˜?‡ª讨苦吃ã??
CustomerName1
CustomerAddress1
CustomerEmail1
CustomerName2
CustomerAddress2
CustomerEmail3
CustomerName1
CustomerAddress2
CustomerEmail3
如果出现这ç?情况,你éœ?要è?范化你的表了ã€?
十八、尽量不要使用TEXT数据类型
除非你使用TEXT处理ä¸?ä¸?¾ˆ大的数据,否则不要使用它。因为它不易于查è¯?¼Œ速度æ…?¼Œ用的不好还会æµ?´¹大量的空间ã?‚一èˆ?š„,VARCHARå�?»¥更好的å?理你的数æ�???
十九、尽量不要使用临时表
尽量不è?使用临时è¡?¼Œ除非你必须这样做。一èˆ?½¿用子查è?å�?»¥代替临时表ã?‚使用临时表会带来系统开é”?,å?果你æ˜?”¨COM+进è?编程,它还会给你带来很大的麻 烦,因为COM+使用数据库连接池而临时表却自始至终都存在。SQL Server提供了一些替代方案,比å?Table数据类型ã€?
二十、å?会分析查è¯?
SQL Server查è?分析器是你的好伙伴,通过它你å�?»¥了解查è?和索引是如何影响性能的ã??
二十ä¸?、使用参照完整æ??
定义主健、唯ä¸?性约束和外键,这样做å�?»¥节约大量的时间ã??
================================================================================================
【IT168 æŠ?æœ?–‡档ã?‘任何事情都有它的源头,要解决问题,也得从源头开始,影响ORACLE性能的源头非常å?,主要包æ‹??下方é�?¼š数据库的ç¡?»¶配置:CPU、内存ã?�网络条件ã??
ã€?ã€?1. CPU:在任何机器中CPU的数æ�??理能力往å¾?æ˜?¡¡量è?算机性能的一ä¸? ‡志,并且ORACLEæ˜?¸€ä¸?��供并行能力的数据库系统,在CPU方面的è?求就更高了,如果运è?队列数目超过了CPU处理的数ç›?¼Œ性能就会下降,我ä»??解决的问题就æ˜??适当增加CPU的数量了,当然我ä»?¿˜å�?»¥将需要è?多资源的进程KILLæŽ?
ã€?ã€?2. 内存:衡量机器性能的另外一ä¸?Œ‡标就æ˜?†…存的多少了,在ORACLEä¸?†…存和我们在建数据库中的交换区进è?数据的交æ�?¼Œ读数æ�?—¶,ç?盘I/O必须等待物理I/O操作完成,在出现ORACLE的内存瓶颈时,我ä»??ä¸?ä¸??考虑的是增加内存,由于I/O的响应时间是影响ORACLE性能的主要参数,我将在这方面进è?详细的è?è§?
ã€?ã€?3. 网络条件:NET*SQL负责数据在网络上的来å¾?,大量的SQL会令网络速度变慢。比å¦?0M的网卡和100的网卡就对NET*SQL有非常明显的影响,还有交换机、集线器等等网络设å?的æ?§能对网络的影响很明显,建è?在任何网络中不è?试图ç”?ä¸?›†线器来将网æ?互联ã€?
ã€?ã€?OS参数的è?ç½?
ã€?ã€?下表给出了OS的参数è?ç½?�Š说明,DBAå�?»¥根据实际éœ?要å?这些参数进è?设置
ã€?ã€?内核参数å�?
ã€?ã€?说明
��bufpages
ã€?ã€?对buffer空间不按静æ?�分配,采用动æ?�分配,使bufpages值随nbufä¸?起å?buffer空间进è?动æ?�分配ã??
��create_fastlinks
ã€?ã€?对HFS文件系统允è?å¿??Ÿç?号链æŽ?
��dbc_max_pct
ã€?ã€?加大æœ?大动态buffer空间æ‰?占物理内存的百分比,以满足应用系统的读写命中率的éœ?要ã??
��dbc_min_pct
ã€?ã€?设置æœ?小动态buffer空间æ‰?占物理内存的百分æ¯?
��desfree
ã€?ã€?提高å¼?始交换操作的æœ?低空闲内存下限,保障系统的稳定æ?§,防æ?出现不可预è?的系统崩æº?Crash)ã€?
��fs_async
ã€?ã€?允è?进è?磁盘异æ?操作,提高CPU和ç?盘的利用çŽ?
��lotsfree
ã€?ã€?提高系统解除换页操作的空闲内存的上限值,保证应用程序有足够的å�?”¨内存空间ã€?
��maxdsiz
ã€?ã€?针å?系统数据量大的特点,加大æœ?大数æ�??的大小,保证应用的需要ã??32ä½?
��maxdsiz_64bit
��maximum process data segment size for 64_bit
��Maxssiz
ã€?ã€?加大æœ?大堆栈æ?的大小ã??32_bit)
��maxssiz_64bit
ã€?ã€?加大æœ?大堆栈æ?的大小ã??64_bit)
��Maxtsiz
ã€?ã€?提高æœ?大代码æ?大小,满足应用è?æ±?
��maxtsiz_64bit
ã€?ã€?原å?¼过大,应调å°?
��Minfree
ã€?ã€?提高停æ?交换操作的自由内存的上限
��Shmem
ã€?ã€?允è?进è?内存共享,以提高内存的利用率
��Shmmax
ã€?ã€?设置æœ?大共äº?†…存æ?的大小,完全满足ç›?‰�的需è¦?
��Timeslice
ã€?ã€?由于系统的瓶颈主要反映在磁盘I/O上,因æ?ã€?降低时间片的大小,一方面å�?�¿免因磁盘I/O不畅造成CPU的等待,从è?Œ提高了CPU的综合利用率。另ä¸?方面减少了进程的阻å?量ã??
��unlockable_mem
ã€?ã€?提高了不å�?”�内存的大小,使可用于换页和交换的内存空间扩大,用以满足系统对内存ç?理的要求ã€?
用户SQL质量
ã€?ã€?以上讲的都是ç¡?»¶方面的东西,在条件有限的条件下,我们å�?»¥调整应用程序的SQL质量:
ã€?ã€?1. 不è?进è?全表æ‰?��(Full Table Scan):全表æ‰?��导致大量的I/O
ã€?ã€?2. 尽量建好和使用好索引:建索引也æ˜?œ‰讲究的,在建索引时,也不æ˜?´¢引越多越好,当一ä¸?¡¨的索引达åˆ?ä¸?»¥上时,ORACLE的æ?§能å�?ƒ½还是改善不了,因为OLTP系统每表超过5ä¸?´¢引即会降低æ?§能,è?Œ且在一个sql ä¸?¼Œ Oracle 从不能使用超è¿?5ä¸?´¢å¼?当我ä»?”¨到GROUP BY和ORDER BYæ—?ORACLE就会è‡?Ѝ对数æ�?¿›行排åº?而ORACLE在INIT.ORAä¸?†³定了sort_area_size区的大小,当排序不能在我们给定的排序区完成æ—?ORACLE就会在ç?盘中进è?排序,也就æ˜?ˆ‘ä»??的临时表空间ä¸?Ž’åº? 过å?的ç?盘排序将会令 free buffer waits 的å?¼变é«?而这ä¸?Œº间并不只æ˜?”¨于排序的,对于å¼?发人员我提出如下忠告:
ã€?ã€?1)、select,update,delete è¯?�¥ä¸?š„子查询应当有规律地查找少äº?0%的表è¡?如果ä¸?ä¸??句查找的行数超过总è?数的20%,它将不能通过使用索引获得性能上的提高.
ã€?ã€?2)、索引可能产生ç?ç‰?因为记录从表ä¸?ˆ 除时,相应也从表的索引ä¸?ˆ é™?表释放的空间å�?»¥再用,而索引释放的空间却不能再ç”?频繁进è?删除操作的è?索引的表,应当阶æ?性地重建索引,以避免在索引ä¸?? 成空间碎片,影响性能.在è?å�?š„条件ä¸?也可以阶段æ?§地truncateè¡?truncate命令删除表中æ‰?有è?å½?也删除索引ç?ç‰?
ã€?ã€?3)、在使用索引时一定è?按索引å?应字段的顺序进è?引用ã€?
ã€?ã€?4)、用(+)比用NOT IN更有效率ã€?
ã€?ã€?降低ORACLE的竞äº?
ã€?ã€?先è?几个ORACLE的几ä¸?�‚数,这几ä¸?�‚数关系到ORACLE的竞äº?
ã€?ã€?1)、freelists å’?freelist ç»?他们负责ORACLE的å?理表和索引的空间管理;
ã€?ã€?2)、pctfree å�?pctused:该参数决定了freelists å’?freelist 组的行为,pctfree 和pctused 参数的唯ä¸?ç›?š„就是为了控制块å?何在 freelists ä¸?¿›å‡?
ã€?ã€?设置好pctfree å�?pctused对块在freelists的移走和读取很重要ã??
ã€?ã€?其他参数的è?ç½?
ã€?ã€?1)、包括SGAåŒ?系统全局åŒ?:系统全局åŒ?SGA)æ˜?¸€ä¸?ˆ†配给Oracle 的包å�?¸€ä¸?Oracle 实例的数æ�?º“的控制信æ�?†…存æ?ã€?
ã€?ã€?主è?包括数据库高速缓å?the database buffer cache)ï¼?
ã€?ã€?重演日志缓存(the redo log buffer)ï¼?
ã€?ã€?共享æ±?the shared pool)ï¼?
ã€?ã€?数据字典缓存(the data dictionary cache)以及其它各方面的信息
ã€?ã€?2)、db_block_buffers(数据高é?Ÿ缓冲区)访问过的数据都放在这ä¸?片内存区域,该参数越大,Oracle在内存中找到相同数据的可能æ?§就越大,也即加å¿?º†查è?速度ã€?
ã€?ã€?3)、share_pool_size (SQL共享缓冲æ±?:该参数是库高速缓存和数据字典的高速缓存ã??
ã€?ã€?4)、Log_buffer (重演日志缓冲åŒ?
ã€?ã€?5)、sort_area_size(排序åŒ?
ã€?ã€?6)、processes (同时连接的进程数)
ã€?ã€?7)、db_block_size (数据库块大小):Oracle默è?块为2KB,太小了,因为å?果我ä»?œ‰ä¸?ä¸?KB的数æ�?¼Œåˆ?KB块的数据库è?è¯?次盘,才能è?完,è€?KB块的数据库只è¦?次就读完了,大大减少了I/O操作。数æ�?º“安è?完成后,就不能再改变db_block_size的å?¼了,只能重新建立数æ�?º“并且建库时,要é?‰择手工安è?数据库ã??
ã€?ã€?8)、open_links (同时打开的链接数)
ã€?ã€?9)、dml_locks
ã€?ã€?10)、open_cursors (打开光标æ•?
ã€?ã€?11)、dbwr_io_slaves (后台写进程数)
�
ã€?ã€?6. IN和EXISTS
ã€?ã€?有时候会将一列和ä¸?系列值相比较。最ç®?单的办法就是在where子句ä¸?½¿用子查è?。在where子句ä¸?�¯以使用两种格式的子查è¯???
ã€?ã€?ç¬?¸€种格式是使用IN操作ç¬?
... where column in(select * from ... where ...);
ç¬?ºŒ种格式是使用EXIST操作ç¬?
... where exists (select 'X' from ...where ...);