Oracle SQL效能優化的40條軍規
- SQL語句執行步驟
語法分析> 語義分析> 檢視轉換 >表示式轉換> 選擇優化器 >選擇連線方式 >選擇連線順序 >選擇資料的搜尋路徑 >執行“執行計劃”
- 選用適合的Oracle優化器
RULE
(基於規則) COST
(基於成本) CHOOSE
(選擇性)
-
訪問
Table
的方式 -
全表掃描 全表掃描就是順序地訪問表中每條記錄,ORACLE採用一次讀入多個資料塊(
database block
)的方式優化全表掃描。 -
通過ROWID訪問表
ROWID包含了表中記錄的物理位置資訊,ORACLE採用索引實現了資料和存放資料的物理位置(ROWID)之間的聯絡,通常索引提供了快速訪問ROWID的方法,因此那些基於索引列的查詢就可以得到效能上的提高。 -
共享 SQL 語句
-
Oracle提供對執行過的SQL語句進行高速緩衝的機制。被解析過並且確定了執行路徑的SQL語句存放在SGA的共享池中。
-
Oracle執行一個SQL語句之前每次先從SGA共享池中查詢是否有緩衝的SQL語句,如果有則直接執行該SQL語句。
-
可以通過適當調整SGA共享池大小來達到提高Oracle執行效能的目的。
- 選擇最有效率的表名順序
-
ORACLE的解析器按照從右到左的順序處理FROM子句中的表名,因此FROM子句中寫在最後的表(基礎表 driving table)將被最先處理。
-
當ORACLE處理多個表時,會運用排序及合併的方式連線它們。首先,掃描第一個表(FROM子句中最後的那個表)並對記錄進行派序,然後掃描第二個表(FROM子句中最後第二個表),最後將所有從第二個表中檢索出的記錄與第一個表中合適記錄進行合併。
-
只在基於規則的優化器中有效。
舉例:
表 TAB1 16,384 條記錄
表 TAB2 1 條記錄
/*選擇TAB2作為基礎表 (最好的方法)*/
select count(*) from tab1,tab2 執行時間0.96秒
/*選擇TAB2作為基礎表 (不佳的方法)*/
select count(*) from tab2,tab1 執行時間26.09秒
如果有3個以上的表連線查詢, 那就需要選擇交叉表(intersection table
)作為基礎表, 交叉表是指那個被其他表所引用的表。
SELECT * FROM LOCATION L, CATEGORY C, EMP E
WHERE E.EMP_NO BETWEEN 1000 AND 2000
AND E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
將比下列SQL更有效率
SELECT * FROM EMP E, LOCATION L, CATEGORY C
WHERE E.CAT_NO = C.CAT_NO
AND E.LOCN = L.LOCN
AND E.EMP_NO BETWEEN 1000 AND 2000
Where
子句中的連線順序
Oracle採用自下而上的順序解析WHERE
子句。 根據這個原理,表之間的連線必須寫在其他WHERE
條件之前,那些可以過濾掉最大數量記錄的條件必須寫在WHERE
子句的末尾。
/*低效,執行時間156.3秒*/
SELECT …
FROM EMP E
WHERE SAL > 50000
AND JOB = ‘MANAGER’
AND 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR = E.EMPNO)
/*高效,執行時間10.6秒*/
SELECT …
FROM EMP E
WHERE 25 < (SELECT COUNT(*) FROM EMP
WHERE MGR=E.EMPNO)
AND SAL > 50000
AND JOB = ‘MANAGER’
SELECT
子句中避免使用“*
”
Oracle在解析SQL語句的時候,對於“*
”將通過查詢資料庫字典來將其轉換成對應的列名。
如果在Select
子句中需要列出所有的Column
時,建議列出所有的Column
名稱,而不是簡單的用“*”來替代,這樣可以減少多於的資料庫查詢開銷。
- 減少訪問資料庫的次數
當執行每條SQL語句時, ORACLE
在內部執行了許多工作: 解析SQL
語句 > 估算索引的利用率 > 繫結變數 > 讀資料塊等等
由此可見, 減少訪問資料庫的次數 , 就能實際上減少ORACLE的工作量。
- 整個簡單無關聯的資料庫訪問
如果有幾個簡單的資料庫查詢語句,你可以把它們整合到一個查詢中(即使它們之間沒有關係),以減少多於的資料庫IO
開銷。
雖然採取這種方法,效率得到提高,但是程式的可讀性大大降低,所以還是要權衡之間的利弊。
- 使用
Truncate
而非Delete
Delete
表中記錄的時候,Oracle會在Rollback
段中儲存刪除資訊以備恢復。Truncate
刪除表中記錄的時候不儲存刪除資訊,不能恢復。因此Truncate
刪除記錄比Delete
快,而且佔用資源少。
刪除表中記錄的時候,如果不需要恢復的情況之下應該儘量使用Truncate
而不是Delete
。
Truncate
僅適用於刪除全表的記錄。
- 儘量多使用
COMMIT
只要有可能,在程式中儘量多使用COMMIT
, 這樣程式的效能得到提高,需求也會因為COMMIT
所釋放的資源而減少。
COMMIT
所釋放的資源:
- 回滾段上用於恢復資料的資訊.
- 被程式語句獲得的鎖
redo log buffer
中的空間- ORACLE為管理上述3種資源中的內部花費
- 計算記錄條數
Select count(*) from tablename;
Select count(1) from tablename;
Select max(rownum) from tablename;
一般認為,在沒有索引的情況之下,第一種方式最快。 如果有索引列,使用索引列當然最快。
- 用
Where
子句替換Having
子句
避免使用HAVING
子句,HAVING
只會在檢索出所有記錄之後才對結果集進行過濾。這個處理需要排序、總計等操作。 如果能通過WHERE
子句限制記錄的數目,就能減少這方面的開銷。
- 減少對錶的查詢操作
在含有子查詢的SQL語句中,要注意減少對錶的查詢操作。
低效:
SELECT TAB_NAME FROM TABLES
WHERE TAB_NAME =(SELECT TAB_NAME
FROM TAB_COLUMNS
WHERE VERSION = 604)
AND DB_VER =(SELECT DB_VER
FROM TAB_COLUMNS
WHERE VERSION = 604)
高效:
SELECT TAB_NAME FROM TABLES
WHERE (TAB_NAME,DB_VER)=
(SELECT TAB_NAME,DB_VER
FROM TAB_COLUMNS
WHERE VERSION = 604)
- 使用表的別名(
Alias
)
當在SQL語句中連線多個表時, 請使用表的別名並把別名字首於每個Column
上.這樣一來,就可以減少解析的時間並減少那些由Column
歧義引起的語法錯誤。
Column
歧義指的是由於SQL中不同的表具有相同的Column
名,當SQL語句中出現這個Column
時,SQL解析器無法判斷這個Column
的歸屬。
- 用
EXISTS
替代IN
在許多基於基礎表的查詢中,為了滿足一個條件 ,往往需要對另一個表進行聯接。在這種情況下,使用EXISTS
(或NOT EXISTS
)通常將提高查詢的效率。
低效:
SELECT * FROM EMP (基礎表)
WHERE EMPNO > 0
AND DEPTNO IN (SELECT DEPTNO
FROM DEPT
WHERE LOC = ‘MELB’)
高效:
SELECT * FROM EMP (基礎表)
WHERE EMPNO > 0
AND EXISTS (SELECT ‘X’
FROM DEPT
WHERE DEPT.DEPTNO = EMP.DEPTNO
AND LOC = ‘MELB’)
- 用
NOT EXISTS
替代NOT IN
在子查詢中,NOT IN
子句將執行一個內部的排序和合並,對子查詢中的表執行一個全表遍歷,因此是非常低效的。
為了避免使用NOT IN
,可以把它改寫成外連線(Outer Joins
)或者NOT EXISTS
。
低效:
SELECT …
FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO
FROM DEPT
WHERE DEPT_CAT=’A’)
高效:
SELECT ….
FROM EMP E
WHERE NOT EXISTS (SELECT ‘X’
FROM DEPT D
WHERE D.DEPT_NO = E.DEPT_NO
AND DEPT_CAT = ‘A’)
- 用表連線替換
EXISTS
通常來說 ,採用表連線的方式比EXISTS
更有效率 。
低效:
SELECT ENAME
FROM EMP E
WHERE EXISTS (SELECT ‘X’
FROM DEPT
WHERE DEPT_NO = E.DEPT_NO
AND DEPT_CAT = ‘A’)
高效:
SELECT ENAME
FROM DEPT D,EMP E
WHERE E.DEPT_NO = D.DEPT_NO
AND DEPT_CAT = ‘A’
- 用
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
- 識別低效的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
另外也可以使用SQL Trace
工具來收集正在執行的SQL
的效能狀態資料,包括解析次數,執行次數,CPU使用時間等 。
- 用
Explain Plan
分析SQL
語句
EXPLAIN PLAN
是一個很好的分析SQL語句的工具, 它甚至可以在不執行SQL的情況下分析語句. 通過分析, 我們就可以知道ORACLE是怎麼樣連線表, 使用什麼方式掃描表(索引掃描或全表掃描)以及使用到的索引名稱。
SQL PLUS
的TRACE
SQL> list
1 SELECT *
2 FROM dept, emp
3* WHERE emp.deptno = dept.deptno
SQL> set autotrace traceonly /*traceonly 可以不顯示執行結果*/
SQL> /
14 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 NESTED LOOPS
2 1 TABLE ACCESS (FULL) OF 'EMP'
3 1 TABLE ACCESS (BY INDEX ROWID) OF 'DEPT'
4 3 INDEX (UNIQUE SCAN) OF 'PK_DEPT' (UNIQUE)
- 用索引提高效率
(1)特點
優點: 提高效率 主鍵的唯一性驗證
代價: 需要空間儲存 定期維護
重構索引:
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
(2)Oracle
對索引有兩種訪問模式
- 索引唯一掃描 (
Index Unique Scan
) - 索引範圍掃描 (
Index Range Scan
)
(3)基礎表的選擇
- 基礎表(
Driving Table
)是指被最先訪問的表(通常以全表掃描的方式被訪問)。
根據優化器的不同,SQL
語句中基礎表的選擇是不一樣的。 - 如果你使用的是
CBO
(COST BASED OPTIMIZER
),優化器會檢查SQL語句中的每個表的物理大小,索引的狀態,然後選用花費最低的執行路徑。 - 如果你用
RBO
(RULE BASED OPTIMIZER
), 並且所有的連線條件都有索引對應,在這種情況下,基礎表就是FROM
子句中列在最後的那個表。
(4)多個平等的索引
- 當SQL語句的執行路徑可以使用分佈在多個表上的多個索引時,ORACLE會同時使用多個索引並在執行時對它們的記錄進行合併,檢索出僅對全部索引有效的記錄。
- 在ORACLE選擇執行路徑時,唯一性索引的等級高於非唯一性索引。然而這個規則只有當
WHERE
子句中索引列和常量比較才有效。如果索引列和其他表的索引類相比較。這種子句在優化器中的等級是非常低的。 - 如果不同表中兩個相同等級的索引將被引用,FROM子句中表的順序將決定哪個會被率先使用。 FROM子句中最後的表的索引將有最高的優先順序。
- 如果相同表中兩個相同等級的索引將被引用,WHERE子句中最先被引用的索引將有最高的優先順序。
(5)等式比較優先於範圍比較
DEPTNO
上有一個非唯一性索引,EMP_CAT
也有一個非唯一性索引。
SELECT ENAME
FROM EMP
WHERE DEPTNO > 20
AND EMP_CAT = ‘A’;
這裡只有EMP_CAT
索引被用到,然後所有的記錄將逐條與DEPTNO
條件進行比較. 執行路徑如下:
TABLE ACCESS BY ROWID ON EMP
INDEX RANGE SCAN ON CAT_IDX
即使是唯一性索引,如果做範圍比較,其優先順序也低於非唯一性索引的等式比較。
(6)不明確的索引等級
當ORACLE無法判斷索引的等級高低差別,優化器將只使用一個索引,它就是在WHERE
子句中被列在最前面的。
DEPTNO
上有一個非唯一性索引,EMP_CAT
也有一個非唯一性索引。
SELECT ENAME
FROM EMP
WHERE DEPTNO > 20
AND EMP_CAT > ‘A’;
這裡, ORACLE
只用到了DEPT_NO
索引. 執行路徑如下:
TABLE ACCESS BY ROWID ON EMP
INDEX RANGE SCAN ON DEPT_IDX
(7)強制索引失效
如果兩個或以上索引具有相同的等級,你可以強制命令ORACLE優化器使用其中的一個(通過它,檢索出的記錄數量少) 。
SELECT ENAME
FROM EMP
WHERE EMPNO = 7935
AND DEPTNO + 0 = 10 /*DEPTNO上的索引將失效*/
AND EMP_TYPE || ‘’ = ‘A’ /*EMP_TYPE上的索引將失效*/
(8)避免在索引列上使用計算
WHERE
子句中,如果索引列是函式的一部分。優化器將不使用索引而使用全表掃描。
低效:
SELECT …
FROM DEPT
WHERE SAL * 12 > 25000;
高效:
SELECT …
FROM DEPT
WHERE SAL > 25000/12;
(9)自動選擇索引
如果表中有兩個以上(包括兩個)索引,其中有一個唯一性索引,而其他是非唯一性索引。在這種情況下,ORACLE將使用唯一性索引而完全忽略非唯一性索引。
SELECT ENAME
FROM EMP
WHERE EMPNO = 2326
AND DEPTNO = 20 ;
這裡,只有EMPNO
上的索引是唯一性的,所以EMPNO
索引將用來檢索記錄。
TABLE ACCESS BY ROWID ON EMP
INDEX UNIQUE SCAN ON EMP_NO_IDX
(10)避免在索引列上使用NOT
通常,我們要避免在索引列上使用NOT
,NOT
會產生在和在索引列上使用函式相同的影響。當ORACLE
遇到NOT
,它就會停止使用索引轉而執行全表掃描。
低效: (這裡,不使用索引)
SELECT …
FROM DEPT
WHERE NOT DEPT_CODE = 0
高效:(這裡,使用了索引)
SELECT …
FROM DEPT
WHERE DEPT_CODE > 0
- 用
>=
替代>
如果DEPTNO
上有一個索引
高效:
SELECT *
FROM EMP
WHERE DEPTNO >=4
低效:
SELECT *
FROM EMP
WHERE DEPTNO >3
兩者的區別在於,前者DBMS將直接跳到第一個DEPT
等於4的記錄,而後者將首先定位到DEPTNO
等於3的記錄並且向前掃描到第一個DEPT
大於3的記錄.
- 用
Union
替換OR
(適用於索引列)
通常情況下,用UNION
替換WHERE
子句中的OR
將會起到較好的效果。對索引列使用OR
將造成全表掃描。 注意,以上規則只針對多個索引列有效。
高效:
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”
- 用
IN
替換OR
低效:
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)
實際的執行效果還須檢驗,在ORACLE8i
下, 兩者的執行路徑似乎是相同的。
- 避免在索引列上使用
is null
和is not null
避免在索引中使用任何可以為空的列,ORACLE
將無法使用該索引。
低效:(索引失效)
SELECT …
FROM DEPARTMENT
WHERE DEPT_CODE IS NOT NULL;
高效:(索引有效)
SELECT …
FROM DEPARTMENT
WHERE DEPT_CODE >=0;
- 總是使用索引的第一個列
如果索引是建立在多個列上, 只有在它的第一個列(leading column
)被where
子句引用時, 優化器才會選擇使用該索引。
SQL> create index multindex on multiindexusage(inda,indb);
Index created.
SQL> select * from multiindexusage where indb = 1;
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE
1 0 TABLE ACCESS (FULL) OF 'MULTIINDEXUSAGE‘
很明顯, 當僅引用索引的第二個列時,優化器使用了全表掃描而忽略了索引。
- 使用
UNION ALL
替代UNION
當SQL語句需要UNION
兩個查詢結果集合時,這兩個結果集合會以UNION-ALL
的方式被合併,然後在輸出最終結果前進行排序。如果用UNION ALL
替代UNION
,這樣排序就不是必要了,效率就會因此得到提高。
由於UNION ALL
的結果沒有經過排序,而且不過濾重複的記錄,因此是否進行替換需要根據業務需求而定。
- 對
UNION
的優化
由於UNION
會對查詢結果進行排序,而且過濾重複記錄,因此其執行效率沒有UNION ALL
高。 UNION
操作會使用到SORT_AREA_SIZE
記憶體塊,因此對這塊記憶體的優化也非常重要。
可以使用下面的SQL
來查詢排序的消耗量 :
select substr(name,1,25) "Sort Area Name",
substr(value,1,15) "Value"
from v$sysstat
where name like 'sort%'
- 避免改變索引列的型別
當比較不同資料型別的資料時, ORACLE
自動對列進行簡單的型別轉換。
/*假設EMP_TYPE是一個字元型別的索引列.*/
SELECT …
FROM EMP
WHERE EMP_TYPE = 123
/*這個語句被ORACLE轉換為:*/
SELECT …
FROM EMP
WHERE TO_NUMBER(EMP_TYPE)=123
因為內部發生的型別轉換,這個索引將不會被用到。
幾點注意:
- 當比較不同資料型別的資料時,ORACLE自動對列進行簡單的型別轉換。
- 如果在索引列上面進行了隱式型別轉換,在查詢的時候將不會用到索引。
- 注意當字元和數值比較時,ORACLE會優先轉換數值型別到字元型別。
- 為了避免ORACLE對SQL進行隱式的型別轉換,最好把型別轉換用顯式表現出來。
-
使用提示(
Hints
)FULL hint
告訴ORACLE使用全表掃描的方式訪問指定表。
ROWID hint
告訴ORACLE使用TABLE ACCESS BY ROWID的操作訪問表。
CACHE hint
來告訴優化器把查詢結果資料保留在SGA中。
INDEX Hint
告訴ORACLE使用基於索引的掃描方式。
其他的Oracle Hints
ALL_ROWS
FIRST_ROWS
RULE
USE_NL
USE_MERGE
USE_HASH 等等。
這是一個很有技巧性的工作。建議只針對特定的,少數的SQL
進行hint
的優化。
- 幾種不能使用索引的
WHERE
子句
(1)下面的例子中,‘!=
’ 將不使用索引 ,索引只能告訴你什麼存在於表中,而不能告訴你什麼不存在於表中。
不使用索引:
SELECT ACCOUNT_NAME
FROM TRANSACTION
WHERE AMOUNT !=0;
使用索引:
SELECT ACCOUNT_NAME
FROM TRANSACTION
WHERE AMOUNT > 0;
(2)下面的例子中,‘||
’是字元連線函式。就象其他函式那樣,停用了索引。
不使用索引:
SELECT ACCOUNT_NAME,AMOUNT
FROM TRANSACTION
WHERE ACCOUNT_NAME||ACCOUNT_TYPE=’AMEXA’;
使用索引:
SELECT ACCOUNT_NAME,AMOUNT
FROM TRANSACTION
WHERE ACCOUNT_NAME = ‘AMEX’
AND ACCOUNT_TYPE=’ A’;
(3)下面的例子中,‘+
’是數學函式。就象其他數學函式那樣,停用了索引。
不使用索引:
SELECT ACCOUNT_NAME,AMOUNT
FROM TRANSACTION
WHERE AMOUNT + 3000 >5000;
使用索引:
SELECT ACCOUNT_NAME,AMOUNT
FROM TRANSACTION
WHERE AMOUNT > 2000 ;
(4)下面的例子中,相同的索引列不能互相比較,這將會啟用全表掃描。
不使用索引:
SELECT ACCOUNT_NAME, AMOUNT
FROM TRANSACTION
WHERE ACCOUNT_NAME = NVL(:ACC_NAME, ACCOUNT_NAME)
使用索引:
SELECT ACCOUNT_NAME,AMOUNT
FROM TRANSACTION
WHERE ACCOUNT_NAME LIKE NVL(:ACC_NAME, ’%’)
- 連線多個掃描
如果對一個列和一組有限的值進行比較,優化器可能執行多次掃描並對結果進行合併連線。
舉例:
SELECT *
FROM LODGING
WHERE MANAGER IN (‘BILL GATES’, ’KEN MULLER’)
優化器可能將它轉換成以下形式:
SELECT *
FROM LODGING
WHERE MANAGER = ‘BILL GATES’
OR MANAGER = ’KEN MULLER’
CBO
下使用更具選擇性的索引
- 基於成本的優化器(
CBO
,Cost-Based Optimizer
)對索引的選擇性進行判斷來決定索引的使用是否能提高效率。 - 如果檢索資料量超過30%的表中記錄數,使用索引將沒有顯著的效率提高。
- 在特定情況下,使用索引也許會比全表掃描慢。而通常情況下,使用索引比全表掃描要塊幾倍乃至幾千倍!
- 避免使用耗費資源的操作
- 帶有
DISTINCT,UNION,MINUS,INTERSECT,ORDER BY
的SQL語句會啟動SQL引擎執行耗費資源的排序(SORT
)功能。DISTINCT
需要一次排序操作,而其他的至少需要執行兩次排序。 - 通常,帶有
UNION,MINUS,INTERSECT
的SQL
語句都可以用其他方式重寫。
- 優化
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
- 使用日期
當使用日期時,需要注意如果有超過5位小數加到日期上,這個日期會進到下一天!
SELECT TO_DATE(‘01-JAN-93’+.99999)
FROM DUAL
Returns:
’01-JAN-93 23:59:59’
SELECT TO_DATE(‘01-JAN-93’+.999999)
FROM DUAL
Returns:
’02-JAN-93 00:00:00’
- 使用顯示遊標(CURSORS)
使用隱式的遊標,將會執行兩次操作。第一次檢索記錄,第二次檢查TOO MANY ROWS
這個exception
。而顯式遊標不執行第二次操作。
- 分離表和索引
- 總是將你的表和索引建立在不同的表空間內(
TABLESPACES
)。 - 決不要將不屬於
ORACLE
內部系統的物件存放到SYSTEM
表空間裡。 - 確保資料表空間和索引表空間置於不同的硬碟上。
相關文章
- 雅虎網站效能優化的34條軍規!網站優化
- 網站效能優化:雅虎35條軍規及其可測的23條規則網站優化
- 雅虎軍規——前端優化的35條建議前端優化
- JS效能優化38條"軍規",2019年嘔心力作JS優化
- Oracle SQL效能優化OracleSQL優化
- 無痛 SQL Schema 的10 條軍規SQL
- Oracle效能優化-SQL優化(案例一)Oracle優化SQL
- Oracle效能優化-SQL優化(案例二)Oracle優化SQL
- Oracle效能優化-SQL優化(案例三)Oracle優化SQL
- Oracle效能優化-SQL優化(案例四)Oracle優化SQL
- ORACLE SQL效能優化系列 (一)OracleSQL優化
- Oracle SQL效能優化常用方法OracleSQL優化
- 詳解SQL效能優化十條經驗SQL優化
- Oracle SQL效能優化系列介紹OracleSQL優化
- sql 軍規SQL
- ORACLE SQL過濾條件是IS NULL or !=的優化OracleSQLNull優化
- 再談雅虎關於效能優化的 N 條規則優化
- 再談Yahoo關於效能優化的N條規則優化
- 高手詳解SQL效能優化十條經驗SQL優化
- PHP程式碼優化的40條建議PHP優化
- 首長,Redis效能最佳化十三條軍規立好了,請過目~Redis
- sql效能優化SQL優化
- sql 效能優化SQL優化
- 效能優化案例-SQL優化優化SQL
- SQL優化34條SQL優化
- oracle效能問題:sql語句優化OracleSQL優化
- ORACLE SQL 效能優化的一些建議OracleSQL優化
- 運維的 85 條軍規運維
- 運維的85 條軍規運維
- Mysql 52條SQL語句效能優化策略彙總MySql優化
- MySQL 效能優化之SQL優化MySql優化
- oracle筆記整理13——效能調優之SQL優化Oracle筆記SQL優化
- SQL優化--用各種hints優化一條SQLSQL優化
- Oracle SQL效能優化技巧大總結_水OracleSQL優化
- SQL效能優化技巧SQL優化
- Sql效能優化梳理SQL優化
- 運維85條軍規運維
- 一條sql的優化過程SQL優化