Oracle 11g Release 1 (11.1) 查询优化器的访问路径
http://docs.oracle.com/cd/B28359_01/server.111/b28274/optimops.htm#i82080
?
本文內(nèi)容
- 全表掃描(Full Table Scans)
- 物理 ID 掃描(Rowid Scans)
- 索引掃描(Index Scans)
- 聚簇訪問(Cluster Access)
- 哈希訪問(Hash Access)
- 采樣表掃描(Sample Table Scans)
- 查詢優(yōu)化器如何選擇訪問路徑
- 備注
?
訪問路徑(Access paths)是從數(shù)據(jù)庫檢索數(shù)據(jù)的方式。一般地,索引訪問路徑(index access paths)用于檢索表數(shù)據(jù)行一個小的子集語句,而當(dāng)訪問表的一個大部分時,全表掃描(full scans)更有效率。在線事務(wù)處理(Online transaction processing,OLTP)應(yīng)用程序,它是由具有高選擇性的短期運行的 SQL 語句組成,通常用索引訪問路徑。另一個方面,決策支持系統(tǒng)(Decision support systems)傾向于使用分區(qū)表,執(zhí)行相關(guān)分區(qū)的全表掃描。
?
全表掃描
全表掃描讀取表的所有行,并過濾掉那些不符合選擇條件的行。執(zhí)行全表掃描期間,表中高水位線(high water mark,HWM)以下的所有數(shù)據(jù)塊都會被掃描。高水位以下的所有數(shù)據(jù)表示已使用的空間數(shù)量(插入數(shù)據(jù)后),或收到數(shù)據(jù)已被格式化的空間(插入數(shù)據(jù)后,再刪除的空間)。檢查每個行是否滿足 WHERE 子句。
當(dāng)Oracle 執(zhí)行全表掃描時,順序地讀取塊。因為塊是相鄰的,所以 I/O 調(diào)用要比單塊大,加速了處理。讀取調(diào)用大小的范圍從 1 個塊到初始化參數(shù) DB_FILE_MULTIBLOCK_READ_COUNT 指定的塊數(shù)量。使用多塊讀取意味著,全表掃描以很高的效率執(zhí)行。每個塊只被讀取一次。
為什么全表掃描對于訪問大數(shù)據(jù)量更快?
當(dāng)訪問表中塊的很大一部分時,全表掃描要比索引范圍掃描更劃算。這是因為,全表掃描可以使用更大的 I/O 調(diào)用,而次數(shù)少卻較大的 I/O 調(diào)用要比次數(shù)多卻小的調(diào)用代價更小。
優(yōu)化器何時使用全表掃描?
優(yōu)化器在以下情況使用全表掃描:
- 沒有索引
若查詢不能使用任何現(xiàn)存的索引,則使用全表掃描。例如,如果查詢中有一個在已索引列上使用函數(shù),那么,優(yōu)化器就不能使用索引,而是使用全表掃描。
如果你需要使用索引來進行不依賴大小寫的檢索,那么,或者在檢索中不允許大小寫混合,或是在檢索列上創(chuàng)建一個基于函數(shù)的索引,如 UPPER(last_name)。參考 “使用基于函數(shù)索引的性能”。
- 大數(shù)據(jù)量
若優(yōu)化器認為,查詢會訪問表中的大多數(shù)塊,則使用全表掃描,即使有索引可用。
- 小的表
若一個表高水位線以下包含比 DB_FILE_MULTIBLOCK_READ_COUNT 參數(shù)小塊,它們可以在一個單 I/O 調(diào)用讀取,那么全表掃描比索引范圍掃描更劃算,而不管可被訪問表的其他部分,或現(xiàn)在的索引。
- 高并行度
一個表的高并行度會使優(yōu)化器傾向于全表掃描,而不是范圍掃描。檢查 ALL_TABLES 表的 DEGREE 列以確定并行程度。
全表掃描提示
使用 FULL(table alias) 來命令優(yōu)化器使用全表掃描。參考“指示訪問路徑”。
可以使用 CACHE 和 NOCACHE 指示已檢索的塊是否放在緩沖區(qū)緩存。CACHE 命令優(yōu)化器,當(dāng)執(zhí)行全表掃描時,把已檢索的塊放在緩沖區(qū)高速緩存 LRU 列表最近使用的末尾。
小的表 1 根據(jù)下表的準(zhǔn)則自動緩存。
表 1 緩存表的準(zhǔn)則
| 表大小 | 大小準(zhǔn)則 | 緩存 |
| 小 | 塊的數(shù)量大于 20 個,或已緩存的塊達到總數(shù)的 2%,不管多大 | 如果 STATISTICS_LEVEL 設(shè)置為 TYPICAL 或更高,Oracle 確定是否依賴表的掃描記錄緩存一個表。只有之后表掃描可能查找已緩存的塊,表才會被緩存。若 STATISTICS_LEVEL 設(shè)置成 BASIC,則表不被緩存。 |
| 中 | 比上面的大,并且已緩存的塊小于總數(shù)的 10% | Oracle 確定是否基于表的掃描和負載記錄緩存一個表。只有之后的掃描可能查找已緩存的塊,才會緩存表。 |
| 大 | 已緩存的塊大于總數(shù)的 10% | 不被緩存。 |
對于用 CACHE 屬性創(chuàng)建或變更的表,禁用小表的自動緩存。
并行查詢的執(zhí)行
當(dāng)需要全表掃描時,通過多并行執(zhí)行服務(wù)來掃描表已提高響應(yīng)時間。并行查詢通常用于低并發(fā)數(shù)據(jù)的數(shù)據(jù)倉庫環(huán)境。
?
物理 ID(Rowids)掃描
一個行的物理 ID 指定數(shù)據(jù)文件(datafile),以及包含行的數(shù)據(jù)塊和塊中行位置的數(shù)據(jù)塊。通過指定行的物理 ID 定位行是檢索一個單獨行的最快方式,因為在數(shù)據(jù)庫中指定了行的精確定位。為了通過物理 ID 訪問一個表,Oracle 首先獲得已選定行的物理 ID,無論是從語句的 WHERE 子句,還是通過一個或多個表索引的索引掃描。之后,Oracle 基于它們的物理 ID 在表中定位每個選擇的行。
優(yōu)化器何時使用 Rowids
一般地,這是從一個索引檢索物理 ID 后的第二步。訪問的表可能在語句中要求任何列,而這些列并不在索引中。
通過物理 ID 訪問不需要按照每個索引掃描。若索引包含語句需要的所有列,則通過物理 ID 訪問可能不會發(fā)生。
?
索引掃描
此方法中,使用語句中指定的已索引的列的值,通過遍歷索引來檢索行。索引掃描基于索引中的一個或多個值,從索引中檢索數(shù)據(jù)。要執(zhí)行一個索引掃描,Oracle 為已建立索引列的值檢索索引。若語句僅僅訪問索引列,則 Oracle 從索引直接讀取已索引的列值,而不是從表。
索引不僅包含索引值,而且也包含表中具有該值的行的物理 ID。因此,若語句訪問其他沒有索引的列,則 Oracle 通過物理 ID 或聚簇掃描查找表中的行。
以下是索引掃描類型:
- 通過塊訪問 I/O,不是行
- 索引唯一掃描(Index Unique Scans)
- 索引范圍掃描(Index Range Scans)
- 索引訪問遞減掃描(Index Range Scans Descending)
- 索引濾過掃描(Index Skip Scans)
- 全表掃描(Full Scans)
- 快速全表索引掃描(Fast Full Index Scans)
- 索引連接(Index Joins)
- Bitmap 索引(Bitmap Indexes)
?
聚簇訪問
聚簇掃描用于從存儲在已索引聚簇的表中檢索具有相同聚簇鍵值的所有行。要執(zhí)行聚簇掃描,Oracle 首先通過掃描聚簇索引,獲得已選定行的物理 ID。再基于物理 ID 定位行。
?
哈希訪問
哈希掃描用于基于哈希值在哈希聚簇中定位行。在哈希聚簇中,具有相同哈希值的所有行被存儲在相同的數(shù)據(jù)塊。要執(zhí)行哈希掃描,Oracle 首先通過把一個哈希函數(shù)應(yīng)用到一個聚簇鍵值,來獲得哈希值。再掃描包含哈希值的行所在數(shù)據(jù)塊。
?
采樣表掃描
采樣(隨機)表掃描從一個采樣表或是一個復(fù)雜的 SELECT 語句檢索隨機的采樣數(shù)據(jù)。當(dāng) FROM 語句包含 SAMPLE 子句或 SAMPLE BLOCK 子句時,使用該訪問路徑。當(dāng)用 SAMPLE 子句采樣數(shù)據(jù)時,要執(zhí)行一個采樣表掃描,Oracle 在表中讀取一個指定的行百分比。當(dāng)用 SAMPLE BLOCK 子句采樣塊時,Oracle 讀取一個指定的表塊的百分比。
?
查詢優(yōu)化器如何選擇訪問路徑
查詢優(yōu)化器基于下面因素選擇一個訪問路徑:
- 語句可用的訪問路徑
- 通過每個訪問路徑,或訪問路徑的結(jié)合,評估執(zhí)行語句的代價
要選擇一個訪問路徑,優(yōu)化器首先通過檢查 WHERE 子句和 FROM 子句的條件來確定哪個訪問路徑可用。然后,優(yōu)化器使用訪問路徑產(chǎn)生一套可能的執(zhí)行計劃,并通過索引、列和訪問表語句的統(tǒng)計信息來評估每個執(zhí)行計劃的代價。最后,優(yōu)化器選擇具有最小代價的執(zhí)行計劃。
當(dāng)選擇一個訪問路徑時,查詢優(yōu)化器受下面影響:
- 優(yōu)化器指示
可以指定優(yōu)化器使用指定的訪問路徑,除了包含 SAMPLE 或 SAMPLE BLOCK 的 FROM 子句。
- 統(tǒng)計信息
例如,若一個表自創(chuàng)建以來,沒有分析過,并且其高水位線下(HWM)的塊小于參數(shù) DB_FILE_MULTIBLOCK_READ_COUNT,則優(yōu)化器認為,這個表比較小,并使用全表掃描。查看 ALL_TABLES 表中的 LAST_ANALYZED 和 BLOCKS 列來檢查統(tǒng)計信息。
?
備注
高水位線(high water mark,HWM)
Oracle 在邏輯存儲上分為 4 個粒度——表空間、段、區(qū)和塊。
- 塊是最小的存儲單位(8K)。Oracle 的每次I/O操作也是按塊的。即當(dāng) Oracle 讀數(shù)據(jù)時,是讀取多少個塊,而不是多少行。
- 區(qū)是由一系列相鄰的塊組成,這是 Oracle 分配空間的基本單位。比如,當(dāng)創(chuàng)建一個表時,Oracle 會分配一個區(qū)的空間給該表。當(dāng)該區(qū)滿了后,Oracle 以區(qū)為單位進行擴展,而不是塊。
- 段是由一系列的區(qū)組成。一般地,當(dāng)創(chuàng)建一個對象時(表或索引),Oracle 會分配一個段給該對象。某種意義上,段是某種特定的數(shù)據(jù)。如 CREATE TABLE 時,Oracle 為表創(chuàng)建數(shù)據(jù)段,CREATE INDEX 時,Oracle 還會分配一個段,只是這個段是索引段。
- 表空間包含了段、區(qū)和塊。表空間數(shù)據(jù)物理上儲存在其所在的數(shù)據(jù)文件中。
Oracle 用高水位線(high water mark,HWM)來界定一個段中使用的塊和未使用的塊。
比如,當(dāng)創(chuàng)建一個表時,Oracle 為該對象分配一個段。即使還未插入任何記錄,也至少有一個區(qū)被分配。第一個區(qū)的第一個塊稱為段頭(SEGMENT HEADE)。段頭儲存了一些信息,如 HWM 信息。HWM 位于第 2 個塊。當(dāng)塊放不下新數(shù)據(jù),Oracle 用 HWM 之上的塊存儲,同時,HWM 向上移。當(dāng)不斷插入數(shù)據(jù)時,HWM 會不斷上移。這樣,HWM 之下表示使用過的塊,HWM 之上的就表示已分配但未使用過的塊。如圖 1 所示:
圖 1 插入數(shù)據(jù)的高水位線
其中,灰色方塊表示數(shù)據(jù)行。
HWM 在插入數(shù)據(jù)時,會向上移,但刪除數(shù)據(jù)時不會往下移。如圖 2 所示:
圖 2 刪除數(shù)據(jù)的高水位線
Oracle 高水位線,就像水庫的水位,當(dāng)漲水時,水位往上移。當(dāng)水退后,最高水位的痕跡還是清淅可見。
總結(jié)
以上是生活随笔為你收集整理的Oracle 11g Release 1 (11.1) 查询优化器的访问路径的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 读出文件中的数据
- 下一篇: linux上利用crontab定时备份p