Почему мой индекс массива 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
1 ответ
Для работы с индексом GIN используйте <@
("содержится") вместо оператора ANY
построить.
Здесь говорится, что индексы GIN по умолчанию в настоящее время поддерживают только эти операторы (дополнительные функции поставляются с расширениями):
<@
@>
=
&&
Так что попробуйте этот запрос:
Document.where("'{divisible by 5}' <@ tags").explain
Обратите внимание, что левая сторона должна быть в array notation
Тоже, даже если это один элемент. Оператор <@
работает для массивов. следовательно '{divisible by 5}'
,