为啥我的 PostgreSQL 数组索引没有被使用(Rails 4)?

Posted

技术标签:

【中文标题】为啥我的 PostgreSQL 数组索引没有被使用(Rails 4)?【英文标题】:Why isn't my PostgreSQL array index getting used (Rails 4)?为什么我的 PostgreSQL 数组索引没有被使用(Rails 4)? 【发布时间】:2014-03-07 16:30:04 【问题描述】:

我有一个 PostgreSQL 字符串数组作为表中的一列。我使用 GIN 方法创建了一个索引。但是任何查询都不会使用索引(相反,它们使用过滤器对整个表进行顺序扫描)。我错过了什么?

这是我的迁移:

class CreateDocuments < ActiveRecord::Migration
  def up
    create_table :documents do |t|
      t.string :title
      t.string :tags, array: true, default: []
      t.timestamps
    end

    add_index :documents, :tags, using: 'gin'

    (1..100000).each do |i|
      tags = []
      tags << 'even' if (i % 2) == 0
      tags << 'odd' if (i % 2) == 1
      tags << 'divisible by 3' if (i % 3) == 0
      tags << 'divisible by 4' if (i % 4) == 0
      tags << 'divisible by 5' if (i % 5) == 0

      Document.create(
        title: i,
        tags: tags
      )
    end
  end

  def down
    drop_table :documents
  end
end

这是我的查询,结果行数。

Document.where("'divisible by 5' = ANY (tags)").explain
    Document Load (249.8ms)  SELECT "documents".* FROM "documents" WHERE ('divisible by 5' = ANY (tags))
    D, [2014-03-07T17:09:49.689709 #41937] DEBUG -- :   Document Load (249.8ms)  SELECT "documents".* FROM "documents" WHERE ('divisible by 5' = ANY (tags))
    => EXPLAIN for: SELECT "documents".* FROM "documents"  WHERE ('divisible by 5' = ANY (tags))
                       QUERY PLAN
    -----------------------------------------------------------------
    Seq Scan on documents  (cost=0.00..3500.00 rows=20057 width=69)
      Filter: ('divisible by 5'::text = ANY ((tags)::text[]))
    (2 rows)

Document.where("'divisible by 5' = ANY (tags)").length
    Document Load (258.0ms)  SELECT "documents".* FROM "documents" WHERE ('divisible by 5' = ANY (tags))
    D, [2014-03-07T17:09:55.536517 #41937] DEBUG -- :   Document Load (258.0ms)  SELECT "documents".* FROM "documents" WHERE ('divisible by 5' = ANY (tags))
    => 20000

【问题讨论】:

products有多少行? 该列的基数是多少?报告的行数有多少唯一记录? @IgorRomanchenko 该表刚刚超过 100,000 行 @Mihai 有超过 100,000 个唯一行。有问题的列有超过 18,000 个唯一值 可能是 ANY 关键字使优化器选择顺序扫描作为最佳选项。该查询返回多少行? 【参考方案1】:

要使用 GIN 索引,请使用 &lt;@ ("is contained by") operator 而不是 ANY construct。

The manual states here 默认 GIN 索引目前仅支持这些运算符(附加功能随扩展提供):

<@
@>
=
&&

所以试试这个查询:

Document.where("'divisible by 5' <@ tags").explain

请注意,左侧也需要在array notation 中,即使它是单个元素。运算符&lt;@ 适用于数组。因此'divisible by 5'

【讨论】:

以上是关于为啥我的 PostgreSQL 数组索引没有被使用(Rails 4)?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Postgresql 使用过滤器而不是索引?

为啥在由数组实现的堆中,索引 0 未被使用?

为啥我在 postgresql 中的视图不使用索引?

为啥此查询在 PostgreSQL 中不使用仅索引扫描?

为啥 PostgreSQL 选择这个索引?

为啥我的输入被插入到两个具有相同索引的 diff 数组中? (js)