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