Почему мой индекс массива PostgreSQL не используется (Rails 4)?

У меня есть массив строк 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

person mohith    schedule 07.03.2014    source источник
comment
Сколько строк в таблице products?   -  person Ihor Romanchenko    schedule 07.03.2014
comment
Какова мощность этого столбца? Сколько уникальных записей соответствует количеству строк?   -  person Mihai    schedule 07.03.2014
comment
@IgorRomanchenko В таблице чуть более 100 000 строк.   -  person mohith    schedule 07.03.2014
comment
@Mihai Более 100 000 уникальных строк. Рассматриваемый столбец содержит более 18 000 уникальных значений.   -  person mohith    schedule 07.03.2014
comment
Вероятно, это ЛЮБОЕ ключевое слово заставляет оптимизатор выбрать последовательное сканирование как наилучший вариант. Сколько строк возвращает этот запрос?   -  person Mihai    schedule 07.03.2014
comment
@Mihai Это выше. 3500 строк.   -  person mohith    schedule 08.03.2014
comment
Я изменил пример кода выше, чтобы сделать его еще проще. Любая помощь будет принята с благодарностью.   -  person mohith    schedule 08.03.2014
comment
Я бы форсировал индекс, используя enable_indexscan, а затем измерял производительность по сравнению с последовательным сканированием. Это докажет, нужен ли вам индекс или нет для этого варианта использования, поскольку Postgresql правильно выбрал наиболее оптимизированный путь (сканирование индекса или последовательности).   -  person Rots    schedule 08.03.2014


Ответы (1)


Для работы с индексом GIN используйте <@ ( "содержится") вместо ANY построить.

Здесь в руководстве указано, что индексы GIN по умолчанию в настоящее время поддерживают только эти операторы. (дополнительный функционал поставляется с расширениями):

<@
@>
=
&&

Итак, попробуйте этот запрос:

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

Обратите внимание, что левая сторона тоже должна быть в array notation, даже если это один элемент. Оператор <@ работает с массивами. Отсюда '{divisible by 5}'.

person Erwin Brandstetter    schedule 08.03.2014