索引是對數據庫中一列或幾列的數據按照特定的數據結構進行排序保存的一種方式。使用索引可以加快數據庫查詢或排序時的速度。如果不使用索引那么查詢數據時就會進行全表掃描也就是每條數據讀取一遍看是不是要找的值,而使用索引可以快速找到要找的數據,不用掃描所有數據。
PostgreSQL 擁有眾多開放特性,例如 :
1、開放的數據類型接口,使得PG支持超級豐富的數據類型,除了傳統數據庫支持的類型,還支持GIS,JSON,RANGE,IP,ISBN,圖像特征值,化學,DNA等等擴展的類型,用戶還可以根據實際業務擴展更多的類型。
2、開放的操作符接口,使得PG不僅僅支持常見的類型操作符,還支持擴展的操作符,例如 距離符,邏輯並、交、差符號,圖像相似符號,幾何計算符號等等擴展的符號,用戶還可以根據實際業務擴展更多的操作符。
3、開放的外部數據源接口,使得PG支持豐富的外部數據源,例如可以通過FDW讀寫MySQL, redis, mongo, oracle, sqlserver, hive, www, hbase, ldap, 等等只要你能想到的數據源都可以通過FDW接口讀寫。
4、開放的語言接口,使得PG支持幾乎地球上所有的編程語言作為數據庫的函數、存儲過程語言,例如plpython , plperl , pljava , plR , plCUDA , plshell等等。用戶可以通過language handler擴展PG的語言支持。
5、開放的索引接口,使得PG支持非常豐富的索引方法,例如btree , hash , gin , gist , sp-gist , brin , bloom , rum , zombodb , bitmap (greenplum extend),用戶可以根據不同的數據類型,以及查詢的場景,選擇不同的索引。
6、PG內部還支持BitmapAnd, BitmapOr的優化方法,可以合並多個索引的掃描操作,從而提升多個索引數據訪問的效率。
- 索引的優點:
可以大大提高數據查詢的速度
在實現數據的參考完整性方面,可以加快表和表之間的連接
在分組和排序時,可以減少分組和排序的時間
當然,索引也有缺點,所以我們不能在表中隨意的創建索引
-
索引的缺點
創建和維護索引需要耗費時間,數據量越大耗費時間也越長
索引需要占用額外的磁盤空間,如果數據量很大又有大量索引,那么索引文件大小增加很快
對表中數據改動的時候,索引需要動態維護,降低了數據操作的速度 -
索引類型
PostgreSQL提供的索引類型有: B-tree、Hash、GiST和GIN。大多數情況下,我們使用比較常用的B-tree索引。
- B-tree索引適合處理那么些能夠按照順序存儲的數據,它適合用於比較操作時經常用到的字段。
- Hash索引只能處理簡單的等於比較。當一個字段涉及到使用“=”操作符進行比較時查詢規划器會考慮使用Hash索引。
- GiST索引不只是一種索引,還是一種架構,可以實現很多不同的索引策略。所以,GiST索引可以使用的特定操作符類型高度依賴於索引策略(操作符類)。
- GIN索引是反轉索引,它可以處理包含多個鍵的值(比如數組)。和GiST索引類似,GIN支持用戶定義的索引策略,GIN索引可以使用的特定操作符類型根據索引策略不同而不同。
- 創建、刪除索引
create index idx_name on table_name(column_name); #創建B-tree索引
create index idx_name on table_name using hash (column_name); #創建Hash索引
drop index idx_name; #刪除索引
- 索引的設計原則
1、索引並不是越多越好,索引太多會影響insert,delete,update的性能。 2、對於經常查詢的字段應該建立索引 3、避免對經常更新的表進行過多的索引 4、數據量很小的表最好不要使用索引,由於數據量少,掃描表的時間可能比查詢索引時間要短,索引沒有效果 5、不要在不同值少的列上建立索引,例如 表示性別的字段一般只有 ‘男’和‘女’兩個不同值,如果建立索引會嚴重降低更新速度。 6、在頻繁進行排序或分組的列上建立索引時,如果待排序的列有多個,可在這些列上建立聯合索引。
btree
postgres=# create table t_btree(id int, info text); CREATE TABLE postgres=# insert into t_btree select generate_series(1,10000), md5(random()::text) ; INSERT 0 10000 postgres=# create index idx_t_btree_1 on t_btree using btree (id); CREATE INDEX postgres=# explain (analyze,verbose,timing,costs,buffers) select * from t_btree where id=1; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- Index Scan using idx_t_btree_1 on public.t_btree (cost=0.29..3.30 rows=1 width=37) (actual time=0.027..0.027 rows=1 loops=1) Output: id, info Index Cond: (t_btree.id = 1) Buffers: shared hit=1 read=2 Planning time: 0.292 ms Execution time: 0.050 ms (6 rows)
hash
postgres=# create table t_hash (id int, info text); CREATE TABLE postgres=# insert into t_hash select generate_series(1,100), repeat(md5(random()::text),10000); INSERT 0 100 -- 使用b-tree索引會報錯,因為長度超過了1/3的索引頁大小 postgres=# create index idx_t_hash_1 on t_hash using btree (info); ERROR: index row size 3720 exceeds maximum 2712 for index "idx_t_hash_1" HINT: Values larger than 1/3 of a buffer page cannot be indexed. Consider a function index of an MD5 hash of the value, or use full text indexing. postgres=# create index idx_t_hash_1 on t_hash using hash (info); CREATE INDEX postgres=# set enable_hashjoin=off; SET postgres=# explain (analyze,verbose,timing,costs,buffers) select * from t_hash where info in (select info from t_hash limit 1); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- Nested Loop (cost=0.03..3.07 rows=1 width=22) (actual time=0.859..0.861 rows=1 loops=1) Output: t_hash.id, t_hash.info Buffers: shared hit=11 -> HashAggregate (cost=0.03..0.04 rows=1 width=18) (actual time=0.281..0.281 rows=1 loops=1) Output: t_hash_1.info Group Key: t_hash_1.info Buffers: shared hit=3 -> Limit (cost=0.00..0.02 rows=1 width=18) (actual time=0.012..0.012 rows=1 loops=1) Output: t_hash_1.info Buffers: shared hit=1 -> Seq Scan on public.t_hash t_hash_1 (cost=0.00..2.00 rows=100 width=18) (actual time=0.011..0.011 rows=1 loops=1) Output: t_hash_1.info Buffers: shared hit=1 -> Index Scan using idx_t_hash_1 on public.t_hash (cost=0.00..3.02 rows=1 width=22) (actual time=0.526..0.527 rows=1 loops=1) Output: t_hash.id, t_hash.info Index Cond: (t_hash.info = t_hash_1.info) Buffers: shared hit=6 Planning time: 0.159 ms Execution time: 0.898 ms (19 rows)