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類型。