使用 gin() 創建全文索引后,雖然有走索引,但是當結果集很大時,查詢效率還是很底下,
SELECT keyword,avg_mon_search,competition,impressions,ctr,position,suggest_bid,click,update_time
FROM keyword
WHERE
update_time is not null and plainto_tsquery('driver') @@ keyword_participle
ORDER BY avg_mon_search DESC
LIMIT 500 OFFSET 0;
背景: keyword 表中有八千萬行數據,建立了 gin( keyword_participle ) 索引,以及其他排序字段的 BTREE 索引
分析:當查詢當個單詞時,雖然有走全文索引,但是由於返回的結果集很大,有二十多萬行數據,而且返回后需要再次進行排序,導致性能嚴重下降,
處理方法:限制全文索引返回的結果集行數,結果集變小了,也就減少了排序消耗的時間,況且全文索引分詞返回的這么多數據,用戶只是查看前面一部分,通過這種方式讓用戶完善搜索詞,知道找到自己想要的結果。
SELECT keyword,avg_mon_search,competition,impressions,ctr,position,suggest_bid,click,update_time, count(*) over() as res_count FROM (SELECT keyword,avg_mon_search,competition,impressions,ctr,position,suggest_bid,click,update_time
FROM keyword WHERE update_time is not null AND avg_mon_search > 0 AND plainto_tsquery('english_nostop', 'driver') @@ keyword_participle limit 20000
) AS tmp ORDER BY avg_mon_search DESC LIMIT 500 OFFSET 0;
如何優化索引效率
有很多方法告訴你應該如何選擇索引,但是沒有提索引本身的優化,實際上數據分布會影響索引的效率。
根據索引的掃描特點,對數據進行重分布,可以大幅度優化索引查詢的效率。
例如bitmap index scan(按BLOCK ID順序讀取)就是PostgreSQL用於減少離散IO的手段。
1、btree數據分布優化
線性相關越好,掃描或返回多條數據的效率越高。
2、hash數據分布優化
線性相關越好,掃描或返回多條數據的效率越高。
3、gin數據分布優化
如果是普通類型,則線性相關越好,掃描或返回多條數據的效率越高。
如果是多值類型(如數組、全文檢索、TOKENs),則元素越集中(元素聚類分析,橫坐標為行號,縱坐標為元素值,數據分布越集中),效率越高。
元素集中通常不好實現,但是我們可以有集中方法來聚集數據,1. 根據元素的出現頻率進行排序重組,當用戶搜索高頻詞時,掃描的塊更少,減少IO放大。2. 根據(被搜索元素的次數*命中條數)的值進行排序,按排在最前的元素進行聚集,逐級聚集。
(以上方法可能比較燒腦,下次發一篇文檔專門講GIN的數據重組優化)
《索引掃描優化之 - GIN數據重組優化(按元素聚合) 想象在玩多階魔方》
4、gist數據分布優化
如果是普通類型,則線性相關越好,掃描或返回多條數據的效率越高。
如果是空間類型,則元素越集中(例如數據按geohash連續分布),效率越高。
5、brin數據分布優化
線性相關越好,掃描或返回多條數據的效率越高。
6、多列復合索引數據分布優化
對於多列符合索引,則看索引的類型,要求與前面一樣。
增加一個,多個列的線性相關性越好,性能越好。
多列線性相關性計算方法如下
《PostgreSQL 計算 任意類型 字段之間的線性相關性》
數據分布還有一個好處,對於列存儲,可以大幅提升壓縮比
《一個簡單算法可以幫助物聯網,金融 用戶 節約98%的數據存儲成本 (PostgreSQL,Greenplum幫你做到)》