由於屬於老項目,postgresql使用版本9.6,主要解決‘%name%"查詢無法使用索引問題。pg_trgm模塊提供函數和操作符測定字母,數字,文本基於三元模型匹配的相似性, 還有支持快速搜索相似字符串的索引操作符類。
1. 增加pg_trgm拓展
CREATE EXTENSION pg_trgm;
2. 采用pg_trgm 建立gin索引
CREATE INDEX trgm_idx_users_username ON users USING gin (username gin_trgm_ops);
3. 第二步采用gin_trgm_ops建立索引完成,但對於聯合索引,gin_trgm_ops將合並成一個字符串查詢, 例如
CREATE INDEX trgm_idx_users_username ON users USING gin ((user_name|| ' ' || last_name) gin_trgm_ops);
4. 有時候需要建立聯合索引,但同時不同的列不願意合成一個字段,這個時候可以gin建立聯合索引, 先修改默認pg_opclass
UPDATE pg_opclass SET opcdefault = TRUE WHERE opcname = 'gin_trgm_ops';
5. 建立gin索引, 示例使用"UPPER" 建立索引,主要是針對django 1.11不支持ilike搜索,全轉為大寫之后再建立索引,之后版本可取消“UPPER”
CREATE INDEX index_name ON table_name USING gin ( UPPER ( first_name ), UPPER ( last_name ), UPPER ( email ), UPPER(username));
6. 注意
gin聯合索引占用空間比btree大,索引數量與列數有關,執行過程中會鎖表,為不影響插入,修改等操作,可以使用CONCURRENTLY不鎖表建立索引。
CREATE INDEX CONCURRENTLY index_name ON table_name USING gin ( UPPER ( first_name ), UPPER ( last_name ), UPPER ( email ), UPPER(username));
7. 使用一段時間后,發現gin索引存在無法命中的情況
1. 搜索字段少於3個字符時,不會命中索引,這是gin自身機制導致。
2. 當搜索字段過長時,比如email檢索,可能也不會命中索引,造成原因暫時未知。
本文參考
gin 索引建立 : https://razeencheng.com/post/pg-like-index-optimize
安全操作postgresql: https://www.braintreepayments.com/blog/safe-operations-for-high-volume-postgresql/