Oracle經過長時間的發展,很多用戶都很了解Oracle全表掃描了,這裡我發表一下個人理解,和大家討論討論。優化器在形成執行計劃時需要做的一個重要選擇是如何從數據庫查詢出需要的數據。對於SQL語句存取的任何表中的任何行,可能存在許多存取路徑(存取方法),通過它們可以定位和查詢出需要的數據。優化器選擇其中自認為是最優化的路徑。
在物理層,Oracle讀取數據,一次讀取的最小單位為數據庫塊(由多個連續的操作系統塊組成),一次讀取的最大值由操作系統一次I/O的最大值與multiblock參數共同決定,所以即使只需要一行數據,也是將該行所在的數據庫塊讀入內存。邏輯上,Oracle用如下存取方法訪問數據:
Oracle全表掃描(Full Table Scans, FTS)
為實現Oracle全表掃描,Oracle讀取表中所有的行,並檢查每一行是否滿足語句的WHERE限制條件。Oracle順序地讀取分配給表的每個數據塊,直到讀到表的最高水線處(high water mark, HWM,標識表的最後一個數據塊)。一個多塊讀操作可以使一次I/O能讀取多塊數據塊(db_block_multiblock_read_count參數設定),而不是只讀取一個數據塊,這極大的減少了I/O總次數,提高了系統的吞吐量,所以利用多塊讀的方法可以十分高效地實現Oracle全表掃描,而且只有在Oracle全表掃描的情況下才能使用多塊讀操作。在這種訪問模式下,每個數據塊只被讀一次。由於HWM標識最後一塊被讀入的數據,而delete操作不影響HWM值,所以一個表的所有數據被delete後,其Oracle全表掃描的時間不會有改善,一般我們需要使用truncate命令來使HWM值歸為0。幸運的是Oracle 10G後,可以人工收縮HWM的值。
由FTS模式讀入的數據被放到高速緩存的Least Recently Used (LRU)列表的尾部,這樣可以使其快速交換出內存,從而不使內存重要的數據被交換出內存。
使用FTS的前提條件:在較大的表上不建議使用Oracle全表掃描,除非取出數據的比較多,超過總量的5% -- 10%,或你想使用並行查詢功能時。
使用Oracle全表掃描的例子:
- explain plan for select * from dual;
- Query Plan
- SELECT STATEMENT [CHOOSE] Cost=
- TABLE Access FULL DUAL
行的ROWID指出了該行所在的數據文件、數據塊以及行在該塊中的位置,所以通過ROWID來存取數據可以快速定位到目標數據上,是Oracle存取單行數據的最快方法。
為了通過ROWID存取表,Oracle 首先要獲取被選擇行的ROWID,或者從語句的WHERE子句中得到,或者通過表的一個或多個索引的索引掃描得到。Oracle然後以得到的ROWID為依據定位每個被選擇的行。
這種存取方法不會用到多塊讀操作,一次I/O只能讀取一個數據塊。我們會經常在執行計劃中看到該存取方法,如通過索引查詢數據。
使用ROWID存取的方法:
- explain plan for select * from dept where rowid = 'AAAAyGAADAAAAATAAF';
- Query Plan
- SELECT STATEMENT [CHOOSE] Cost=1
- TABLE Access BY ROWID DEPT [ANALYZED]