Oracle系列之 -------- oracle的索引

1、優化器

爲SQL選擇一個最優的執行計劃的工具分爲RBO和CBO。兩種優化器的區別在於:RBO不會計算cost,但是CBO會計算cost。

2、統計信息

表中的數據量與數據分佈等信息。查看統計信息,是在sys下的視圖中查看。

                               |-- num_rows
        table -> user_tables --|-- blocks
                               |-- last_analyzed

                               |-- num_rows
        index -> user_indexs --|-- leaf_blocks
                               |-- distinct_keys
                               |-- last_analyzed

                               |-- num_rows
        row -> user_columns ---|-- low_values
                               |-- hight_values
                               |-- last_analyzed

如果沒有統計信息,CBO會動態採樣,取一定比例的數據分析得到一個統計信息。

3、表連接

實際上應該用row source來代替表。表連接並不是整張表連接。典型的表連接包括:嵌套循環(nested loop)、哈希連接(hash join)、排序合併連接(sort merge join)。驅動表(在表連接中先存取的表)。表連接一次只能連接兩個表,即使有多個表的連接,也只能兩個兩個地連接,所以,兩個表的連接很重要,表的連接順序也很重要。

4、nested loops(嵌套循環)

    eg:
        select /*+ use_nl(ab) full(a) full(b) leading(b)*/ *
        from t_userinfo a,t_userserviceinfo b
        where a.phonenumber = b.phonenumber
        leading(b)以b爲驅動表

    (1)分析該查詢語句的索引:
        這種查詢就會採用nested loops(嵌套循環),就像java中的a.forEach(ele -> b.forEach())
        執行計劃中的第一個表爲驅動表,既:外層循環。
        /*+ use_nl(ab) full(a) full(b) leading(b)*/ 是查詢語句中的提示。
        注意:在選擇驅動表的時候,以小表爲驅動表,小表不是真的小表,而是row source小的表。並且,大表上要有索引。
    
    (2)提示:
            “提示”是用來提示優化器採用什麼樣的執行計劃。
            當出現以下情況的時候,就需要使用提示了:
                a、沒有統計信息
                b、臨時表上不能收集統計信息
                c、CBO選擇的執行計劃不好

    (3)提示的分類:
        a、指定連接順序:
                leading -> 指定驅動表:no_unnest(以主查詢爲驅動)、unnest(以子查詢爲驅動)
                ordered -> 指定順序
        b、指定連接方式:
                use_nl -> 嵌套循環
                use_hash -> 哈希連接
        c、指定訪問路徑:
                full -> 全表掃描
                index -> 索引掃描
        d、nl_sj,nl_aj,hash_sj,hash_aj
                用於子查詢,sj->in/exists
                           aj->not in/not exists

    (4)如何選擇驅動表:
        a、當兩個表都是全表掃描時,以小表爲驅動表
        b、內表的查詢列一定要能命中索引
        c、當b表上有固定查詢條件,可以縮小b表與a表的連接的row source時,以b表爲驅動表。
           所以,應該以參與連接的row source比較小的表爲驅動表

    (5)帶子查詢的nested loops:
        nl-sj -> 以主查詢爲驅動
        in/exist -> 以主查詢爲驅動
        no_unnest -> 與nl_sj一樣,但是當10G以後,需要使用no_unnest

    (6)多表 nested loops:
        a、在多表連接的時候,實際上是兩個表兩個表地連接。當使用多表連接的時候,可以使用order(a b c)來指定連接順序,
            兩個表連接以後的row source越少,就應該越靠前。
        b、帶外連接的nested loop都是以左表爲驅動表。
        c、多表連接默認情況下,是根據from後面的表的順序從右向左開始連接,但是,如果RBO認爲有更好的
           執行計劃,也會改變。

5、hash join

    (1)nested loop 與 hash join的比較:
        a、nested loop之適合小數據量
        b、hash join適合大數據量
    
    (2)hash join的連接過程:
        a、生產hash表,以驅動表數據生成。爲了使hash表小一點,要以小表爲驅動表。
        b、生成hash表以後,掃描探測表(探測表是另外一張表),與hash表匹配,匹配上就將數據存入結果集。
        c、hash連接結束,就可以得到結果
    
    (3)默認優化器會使用 index fast full scan 而不是table full scan

    (4)update技巧
        sql語句:
            update t_useinfo a
            set a.username = (select b.oprinitinfo from t_userservice_info b where a.phone=b.phone);
            分析sql語句:
                a、這裏會使用nested loop(嵌套循環)
                b、視圖update
                    update(
                            select a.username,b.opinfo from a,b where a.phone=b.phone
                            )
                    set username=opinfo;
                c、PL/SQL更新
                    begin
                        for item in(
                                    select a.rowid,b.opinfo from a,b where a.phone=b.phone
                                    )
                        loop
                            update a set username=item.opinfo where rowid=item.rowid;
                        end loop;
                    end;

    (5)hash join總結
        a、適用於大數據,連接條件必須是等值連接
        b、選擇小表爲驅動表
        c、設置較大的GPA,可以加快hash join
        d、注意順序,中間結果集儘量小
        e、hash join與nested loop比較,實際上是用空間換時間,當內存不足的時候,就會報錯

    (6)分區表
        physical上分離,logical上一體。這樣可以加速查詢
                

6、oracle 索引

    (1)B+樹索引
        B+樹索引的數據結果是一個樹,樹的葉子節點是表中的數據行,葉子節點的父節點叫“索引葉子節點塊”,在索引葉子節點塊中會保留相鄰的索引葉子節點的地址。
        在B+樹中,索引節點是有序的,而這種有序是針對每一層而言的。B+樹中,每一層可以有200個節點塊,每一個節點塊中,可以對應400個下一級節點塊。但是,葉子節點塊是無序的(葉子節點塊中存的是數據行)。

    (2)查看錶的統計信息
        可以分析表的一些基本數據。注意:數據被delete,數據佔用的塊不會被釋放,但是,新insert的數據會優先佔用這些空間。
        
    (3)查看錶索引的統計信息
        可以分析表的索引的一些信息。

    (4)關於索引的一些注意點
        a、空字段值是不會被加入索引的,因此,查某個字段爲空是不能在索引中查到的
        b、不要在長字段上創建索引,這會導致B+樹層高太大,影響索引掃描,使索引掃描時間增加。
            分析:
                1)爲什麼在長字段上創建索引會導致B+樹層高太大:因爲每一個索引葉子節點塊能夠存的數
                   據量是有限的。索引字段越長,索引葉子節點塊中的索引數量越少,葉子節點塊的數量就
                   越多,B+樹層高就越大。
                2)爲什麼B+樹層高越大,索引掃描越慢:因爲B+樹層高越大,需要掃描的葉子節點塊的數量
                   就越多,所以,掃描時間越大。
        c、分配索引空間和表空間時,兩者因該是差不多的。
        d、索引鍵是可以重複的,也是可以不重複的(設置索引爲unique),但是不能爲空。
        e、索引的重複度越高,查詢越慢:
            B+樹的高度決定了從根節點到葉子節點查詢的節點數量。重複度決定了在葉子節點中查詢的節點數
            量。所以,B+樹高度越高,查詢的節點樹越多。重複度越高,查詢的節點數越多。

    (5)索引的查詢
        索引掃描的數度是由以下兩個參數決定的:層高、索引重複度
        層高:層高由“索引塊數”、“索引字段長度”這兩個參數決定。因爲塊的大小是固定的,所以,索引字段    
              的長度可以決定索引的塊數。因爲每一層索引塊數固定,所以,索引塊數可以決定層高。
        索引重複度:索引重複度描述了同一個索引佔用的索引塊的數量。索引重複度越高,在同一層掃描的索
              引塊樹越多,索引掃描的效率越低。

7、數據庫性能調優

    (1)數據庫性能的影響因子:
        IO、CPU、網絡。如果數據庫做的計算越多,則,CPU使用率越高,網絡使用率越低。如果數據庫做的計
        算越少,則,CPU使用率越低,網絡使用率越高。
        所以,要合理地安排數據庫的計算,儘量使IO、CPU、網絡的使用率相當。
    (2)減少數據塊的讀取
    (3)數據塊是數據行存儲的位置,一個數據塊可以存多少行的數據,由行大小來決定。數據塊大小由磁盤文
        件系統決定,也可以設置。磁盤格式化時,會將磁盤劃分爲指定大小的塊。

8、數據的訪問路徑

    (1)執行計劃的三個方面:
        a、訪問路徑:全表掃描、各種索引掃描
        b、連接方式:單表查詢不考慮
        c、連接順序:單表查詢不考慮
    (2)autotrace工具
        查看執行計劃、訪問量多少數據塊
    (3)delete不會降低表的高水位
        即使數據塊是空塊,全表掃描也會掃描
    (4)執行計劃是從下向上看的
    (5)select /*+full(a)*/ count(*) from user a;
        /*+full(a)*/ : 是告訴優化器對a表執行全表掃描,a爲表user的別名
    (6)index unique scan
        因爲是唯一索引,所以,查詢的索引塊數量爲層高。
        table access by index rowid,通過行號(rowid)訪問表
        主要分析:consistent gets 和 physical reads的數量
        select /*+index(a indexName)*/ field1 from table a where field2='a' and field3='b';
        /*+index(a indexName)*/:指定命中索引a爲table別名,index爲field2與field3的複合索引

9、index range scan

    索引範圍掃描:對於組合索引,key爲多個字段的拼接。索引重複度高或範圍查詢
    
    注意:不能命中 index range scan
    
    (1)全模糊查詢
        username like '%abc%' / '%abc%'不能比對,因爲不知道'abc'是第幾位
    (2)沒有使用索引中的第一個字段(前導列)
    (3)使用“不等號”或“not in”
    (4)查詢列上有表達式或函數
    (5)index range scan的性能分析:
        通過分析該查詢訪問的塊來衡量性能,塊越少,性能越好。查詢的塊 = 索引塊 + 數據塊
    
    注意:查詢條件可以分爲:定位條件、過濾條件
        如果定位條件先起作用,則,訪問的塊數就會很少,然後用過濾條件過濾

10、如何確定哪個索引好

    標準:訪問的數據塊越少越好,訪問的數據塊 = 索引塊 + 表塊
    
    (1)葉子節點的訪問量對性能影響巨大。查詢條件和索引的重複率對該因素影響巨大

    (2)因爲表數據是不連續的,所以,通過葉子節點來訪問表是需要來回地從葉子節點獲得rowid。這也是爲
        什麼,當命中不了索引時,全表掃描比強制使用index快。自增字段在入表時是相對接近的,因爲數據
        入表時間是相近的。
    (3)索引“聚集因子”:它描述了數據在表中的聚集情況。但是,聚集因子的計算因爲出現物理讀的可能性很
        大,所以,開銷也很大。
    (4)一般,如果索引命中超過5%,就不用index range scan

11、index full scan

    索引全掃描:掃描所有的葉子節點
    特點:
        (1)有序,葉子節點是有序的
        (2)只能單塊讀(全表掃描可以多塊讀),葉子節點之間是指針相連,只能沿指針遍歷
        (3)效率比全表掃描低

    使用場景:
        (1)排序取Top N
            全表掃描排序因爲需要將數據讀入內存,所以,非常消耗性能。但是,index full scan(索引全
            掃描)只能掃描Top N就返回

12、index fast full scan

    索引快速全掃描:根據索引在磁盤的物理序掃描,不會順着葉子節點指針掃描
    
    特點:
        並行、無序、可多塊讀、只適用於CBO(CBO是一種優化器)

13、index skip scan

    定義:跳過索引前導列的索引掃描

14、索引設計原則

    (1)分區表不創建全局索引,否則,當delete分區時,索引會失效
    
    (2)不要創建無用的索引,否則,會降低DML的性能
        
    (3)t_1_r_1 與 t_1 是一樣功能的索引

    (4)key不要太長,否則,B+樹會很高

    (5)重複度低的應該靠前

    (6)索引和表要建在不同的表空間中,可以提高IO性能

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章