1

我使用Django,和我所有的疑問都被Django的產生,所以我沒有手寫查詢...全文索引VS pattern_ops指標

我有BillRecords,其中有一個領域subscriberno的表。在我的Django的過濾器,我使用的是過濾查詢,如:

BillRecords.objects.filter(subscriberno__icontains='123456') 

由於subscriberno客戶說可能是相當短的實數的版本...

該過濾器輸出像查詢:

SELECT "subscriberno" FROM "BillRecords" WHERE UPPER("subscriberno"::text) LIKE UPPER(E'%123456%'); 

subscriberno是一個char字段,因爲某些數字包含alpha和一些特殊字符。

在我的數據庫中,我有兩個由我的同事創建的索引。

"BillRecords_subscriberno" btree (subscriberno) 
"BillRecords_fsubscriberno_like" btree (subscriberno varchar_pattern_ops) 

我想知道使用兩個指標對這樣的查詢是合乎邏輯的。由於我們所有的Django過濾器都使用icontains,而且這應該是創建像我上面寫的查詢。

Postgres的分析查詢如下:

Seq Scan on BillRecords (cost=0.00..159782.40 rows=370 width=15) (actual time=579.637..3705.079 rows=10 loops=1) 
Filter: (upper((subscriberno)::text) ~~ '%123456%'::text) 
Total runtime: 3705.106 ms 
(3 rows) 

所以,據我看到的,沒有使用索引。由於索引usega在數據插入和更新中有成本,因此有兩個沒有用法的索引(就我從這個分析中可以看到的)來看,我似乎不合邏輯。

是否有任何django輸出不同查詢類似icontanis過濾器?或者我的索引完全沒用?

回答

1

您不能在未錨定的類似語句上使用索引。

upper(foo) like 'bar%' -- index on upper(foo) 
upper(foo) like '%bar' -- no index 
reverse(upper(foo)) like 'rab%' -- index on reverse(upper(foo)) 
upper(foo) like '%bar%' -- no index 

但是,你可能會發現使用的trigram contrib,如果你想減少搜索窗口。

1

包含(子串)查詢無權訪問索引(除非操作員鏈接到全文模塊)。開始 - 另一方面查詢可以從索引中受益。如果基數不太低,並且插入通常不是大批量生產,而是在OLTP方案中,則索引開銷可以忽略不計。

我是否正確讀取統計數據:幾乎4秒鐘才能掃描370行?

P.S.您可以考慮一種替代方法:使用基於函數的索引,可能在subscriberno的最後四個字符連接到(例如)subscribername的前三個字符,並且使用starts-with或equals來代替搜索項LIKE用通配符保存。

+0

事實上,PostgreSQL 9.1將能夠使用'like'%foo%''來查找「包含」查詢的索引。請參閱:http://www.depesz.com/index.php/2011/02/19/waiting-for-9-1-faster-likeilike/ –

+0

@a_horse_with_no_name:Right-o。我應該添加(除非...鏈接到全文模塊'或其他類型的字符串標記器')。 – Tim

+0

我不能使用訂閱者姓名):我手邊的所有內容都是__subscriberno__,這是一種「保存不同訂閱類型信息的系統」,所以我有各種不同的訂閱格式,某些格式適用於少數他們... – FallenAngel

1

一個簡單的方法來檢查,如果你的指數是在全部採用的是看

SELECT * FROM pg_stat_user_indexes; 

如果您所有的疑問都像你展示一個,那麼他們肯定不會被使用,因爲該模式沒有固定。如果你想解決這個問題,你將不得不重新設計你的搜索,使用全文搜索,trigrams或類似的東西。