【问题标题】:Fulltext indexes vs pattern_ops indexes全文索引与 pattern_ops 索引
【发布时间】:2011-10-13 06:47:07
【问题描述】:

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

【问题讨论】:

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


    【解决方案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 contrib 的使用。

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 实际上 PostgreSQL 9.1 将能够使用like '%foo%' 的“包含”查询的索引。见这里:depesz.com/index.php/2011/02/19/…
      • @a_horse_with_no_name:对。我应该添加(除非...链接到全文模块or some other kind of string tokenizer)。
      • 我不能使用订阅者名称):我手头只有 subscriberno,这是一种“保存不同订阅类型信息的系统”,所以我有多种不同的订阅格式,其中一些格式适用于其中的一些...
      【解决方案3】:

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

      SELECT * FROM pg_stat_user_indexes;
      

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

      【讨论】:

        猜你喜欢
        • 2016-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多