全文索引与pattern_ops索引

时间:2011-07-26 09:51:50

标签: django postgresql indexing django-queryset full-text-indexing

我正在使用django,我的所有查询都是由django创建的,所以我没有手写查询......

我有一张BillRecords表,其中有一个字段subscriberno。在我的django过滤器中,我使用过滤查询,如:

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

由于客户所说的subscriberno可能是实际数字的缩短版本......

该过滤器输出如下的查询:

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

subscriberno是一个char字段,因为有些数字包含alphas和一些特殊字符。

在我的数据库中,我的同事创建了该列的两个索引。

"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过滤器输出不同的查询?或者我的索引完全没用?

3 个答案:

答案 0 :(得分:1)

包含(子字符串)查询无法访问索引(除非操作符链接到全文模块)。另一方面,启动查询可以从索引中受益。如果基数不是太低而且插入通常不是大批量生成,而是在OLTP场景中,则索引开销可以忽略不计。

我是否正确阅读统计数据:扫描370行几乎需要4秒钟?

P.S。您可以考虑另一种方法:使用基于函数的索引,也许在订户的最后四个字符串联,例如,订阅者名称的前三个字符,并使用start-with或equals而不是LIKE与搜索项用通配符书。

答案 1 :(得分: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的使用。

答案 2 :(得分:1)

检查索引是否完全使用的简单方法是查看

SELECT * FROM pg_stat_user_indexes;

如果您的所有查询都与您显示的查询类似,那么它们肯定不会被使用,因为模式没有锚定。如果你想解决这个问题,你将不得不使用全文搜索,三元组或类似的东西来重新设计你的搜索。