B-TREE索引是最常用的索引,適合等值查詢、范圍查詢、索引排序、多列條件、條件包含表達式等等場景。

操作符

操作符 示例
< select * from test where id <1
<= select * from test where id <=1
= select * from test where id =1
>= select * from test where id >=1
> select * from test where id >1
between and select * from test where id between 1 and 10
in select * from test where id in (1,2,3)
like select * from test where id like ‘abc%’

多列索引

多列索引用于定義在表的多個列上的索引,最多可以指定32個列。

  • 表結構
    create table test(id int,name varchar(10));
  • 查詢語句
    select * from test where id=1 and name='a1’;         
  • 創建多列索引
    create index ON test(id,name);
  • 查看執行計劃
    postgres=# explain select * from test where id=1 and name='a1';
                                       QUERY PLAN
    --------------------------------------------------------------------------------
     Index Only Scan using a_id_name_idx on test  (cost=0.42..8.44 rows=1 width=10)
       Index Cond: ((id = 1) AND (name = 'a1'::text))
    (2 rows)

以上示例中在條件沒有包含ID的情況下不會走索引,示例如下。

postgres=# explain select * from test where name='a1';
                       QUERY PLAN
--------------------------------------------------------
 Seq Scan on test  (cost=0.00..1791.00 rows=1 width=10)
   Filter: ((name)::text = 'a1'::text)
(2 rows)

表達式索引

表達式索引用于索引的列不是物理表的一個列,是對表的一個列或者多列進行計算的函數或者表達式。

  • 表結構
    create table test(id int,name varchar(10));
  • 查詢語句
    select * from test where lower(name)='a1’;
  • 創建表達式索引
    create index ON test (lower(name));
  • 查看執行計劃
    postgres=# explain select * from test where lower(name)='a1';
                                       QUERY PLAN
    --------------------------------------------------------------------------------
     Bitmap Heap Scan on test  (cost=12.17..571.91 rows=500 width=10)
       Recheck Cond: (lower((name)::text) = 'a1'::text)
       ->  Bitmap Index Scan on test_lower_idx  (cost=0.00..12.04 rows=500 width=0)
             Index Cond: (lower((name)::text) = 'a1'::text)
    (4 rows)

索引表達式的維護代價較為昂貴,在每一行被插入或更新時都得為它重新計算相應的表達式。

部分索引

當一個部分索引是建立在表的一個子集上,而該子集由一個條件表達式定義,索引中只包含符合謂詞的表行的項,則可以使用部分索引。

  • 表結構
    create table test(id int,name varchar(10));
  • 查詢語句
    select * from test where name='a1';
    select * from test where name='a2';
  • 創建部分索引
    create index ON test(name) where name='a1';
  • 執行計劃
    postgres=# explain select * from test where name='a1';
                                    QUERY PLAN
    ---------------------------------------------------------------------------
     Index Scan using test_name_idx on test  (cost=0.12..8.14 rows=1 width=10)
    (1 row)
    
    postgres=# explain select * from test where name='a2';
                           QUERY PLAN
    --------------------------------------------------------
     Seq Scan on test  (cost=0.00..1791.00 rows=1 width=10)
       Filter: ((name)::text = 'a2'::text)
    (2 rows)

索引排序

索引除了簡單查找返回行之外,還可以按照指定順序返回不需要獨立的排序步驟。

  • 表結構
    create table test(id int,name varchar(10));
  • 查詢語句
    select * from test order by name desc;
  • 創建索引前計劃
    postgres=# explain select * from test order by name desc;
                                QUERY PLAN
    -------------------------------------------------------------------
     Sort  (cost=9845.82..10095.82 rows=100000 width=10)
       Sort Key: name DESC
       ->  Seq Scan on test  (cost=0.00..1541.00 rows=100000 width=10)
    (3 rows)
  • 創建索引
    create index ON test (name desc);
  • 查看執行計劃
    postgres=# explain select * from test order by name desc;
                                        QUERY PLAN
    -----------------------------------------------------------------------------------
     Index Scan using test_name_idx on test  (cost=0.29..3666.46 rows=100000 width=10)
    (1 row)

默認情況下,B-TREE索引將它的項以升序方式存儲,并將空值放在最后。您可以在創建B-TREE索引時通過ASC、DESC、NULLS FIRST和NULLS LAST選項來改變索引的排序。

只使用索引掃描和覆蓋索引

只查詢索引相關字段,可以通過索引直接返回數據,無需訪問具體的數據文件。

  • 示例一
    • 表結構
      create table test(id int,name varchar(10));
    • 查詢語句
      select name from test where name=‘a1’;
    • 沒有索引時的執行計劃
      postgres=# explain select name from test where name='a1';
                            QUERY PLAN
      -------------------------------------------------------
       Seq Scan on test  (cost=0.00..1791.00 rows=1 width=6)
         Filter: ((name)::text = 'a1'::text)
      (3 rows)
    • 創建索引
      create index ON test (name);
    • 有索引時的執行計劃
      postgres=# explain select name from test where name='a1';
                                        QUERY PLAN
      -------------------------------------------------------------------------------
       Index Only Scan using test_name_idx on test  (cost=0.29..8.31 rows=1 width=6)
         Index Cond: (name = 'a1'::text)
      (2 rows)
  • 示例二
    • 表結構(與示例一相同)
      create table test(id int,name varchar(10));
    • 查詢語句
      select * from test where name='a1’;
    • 沒有索引時的執行計劃
      postgres=# explain select * from test where name='a1';
                             QUERY PLAN
      --------------------------------------------------------
       Seq Scan on test  (cost=0.00..1791.00 rows=1 width=10)
         Filter: ((name)::text = 'a1'::text)
      (2 rows)
    • 創建覆蓋索引
      create index ON test (name) include(id);
    • 有索引時的執行計劃
      postgres=# explain select * from test where name='a1';
                                          QUERY PLAN
      -----------------------------------------------------------------------------------
       Index Only Scan using test_name_id_idx on test  (cost=0.42..8.44 rows=1 width=10)
         Index Cond: (name = 'a1'::text)
      (2 rows)

查詢語句必須只引用存儲在該索引中的列,才能使用覆蓋索引,即只需要掃描索引,不需要去掃描表中數據就可以得到相應的結果。

索引頁面類型

索引頁面將簡單介紹索引的內部架構,上述的索引功能都是基于內部架構實現。PolarDB的B-TREE索引頁面分幾個類型:

  • meta page
  • root page
  • branch page
  • leaf page

其中meta page類型和root page類型是必須有的,meta page需要一頁來存儲,表示指向root page的page id。隨著記錄數的增加,一個root page可能存不下所有的heap item,就會需要leaf page類型、branch page類型或多層的branch page類型。

BTREE索引