1

我正在使用 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是一个字符字段,因为一些数字包含字母和一些特殊字符。

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

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

4

3 回答 3

1

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

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

PS您可能会考虑另一种方法:使用基于函数的索引,可能在subscriberno的最后四个字符上连接到subscribername的前三个字符,并使用starts-with或equals而不是LIKE与search-以通配符结尾的术语。

于 2011-07-26T10:13:35.613 回答
1

您不能在未锚定的 like 语句上使用索引。

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 贡献。

于 2011-07-26T10:18:48.440 回答
1

检查您的索引是否被使用的一种简单方法是查看

SELECT * FROM pg_stat_user_indexes;

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

于 2011-07-26T21:37:13.327 回答