我正在使用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
过滤器输出不同的查询?或者我的索引完全没用?
答案 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;
如果您的所有查询都与您显示的查询类似,那么它们肯定不会被使用,因为模式没有锚定。如果你想解决这个问题,你将不得不使用全文搜索,三元组或类似的东西来重新设计你的搜索。