0

У меня есть приложение на основе RubyOnRails 4.0. У меня две модели: магазины и продукты. В системе около 1,5 миллионов продуктов, что делает его довольно медленным, если я не использую индексы должным образом.Создать индекс postgres для таблицы с внутренним соединением в RubyOnRails

Некоторые основные сведения

  • магазин has_many Продукты
  • Store.affiliate_type_id используется где 1 = Дочернее 2 = Не аффилированные
  • продукты имеют атрибуты, такие как "category_connection_id" (целое число) и «is_available "(boolean)

В модели FeededProduct:

scope :affiliated, -> { joins(:store).where("stores.affiliate_type_id = 1") } 

Этот запрос занимает около 500 мс, который в основном прерывает сайт:

FeededProduct.where(:is_available => true).affiliated.where(:category_connection_id => @feeded_product.category_connection_id) 

корреспондент PostGreSQL:

FeededProduct Load (481.4ms) SELECT "feeded_products".* FROM "feeded_products" INNER JOIN "stores" ON "stores"."id" = "feeded_products"."store_id" WHERE "feeded_products"."is_available" = 't' AND "feeded_products"."category_connection_id" = 345 AND (stores.affiliate_type_id = 1) 

Update. Postgresql EXPLAIN:

          QUERY PLAN 
------------------------------------------------------------------------------------------------- 
Hash Join (cost=477.63..49176.17 rows=21240 width=1084) 
    Hash Cond: (feeded_products.store_id = stores.id) 
    -> Bitmap Heap Scan on feeded_products (cost=377.17..48983.06 rows=38580 width=1084) 
     Recheck Cond: (category_connection_id = 5923) 
     Filter: is_available 
     -> Bitmap Index Scan on cc_w_store_index_on_fp (cost=0.00..375.25 rows=38580 width=0) 
       Index Cond: ((category_connection_id = 5923) AND (is_available = true)) 
    -> Hash (cost=98.87..98.87 rows=452 width=4) 
     -> Seq Scan on stores (cost=0.00..98.87 rows=452 width=4) 
       Filter: (affiliate_type_id = 1) 
(10 rows) 

Вопрос: Как я могу создать индекс, который будет принимать внутреннее соединение во внимание и сделать это быстрее?

+0

'EXPLAIN ANALYZE' возвращает более полезные сведения. –

+0

Спасибо, но я не смог найти хороший способ сделать это в RubyOnRails. Любой совет здесь? – Christoffer

+0

В PostgreSQL используйте 'explain analysis' вместо' explain'. –

ответ

1

Это зависит от алгоритма соединения, который выбирает PostgreSQL. Используйте EXPLAIN по запросу, чтобы посмотреть, как PostgreSQL обрабатывает запрос.

Этих ответы в зависимости от присоединения алгоритма:

  1. вложенного цикл

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

  2. хеширования

    Вот это помогает иметь индексы на обеих таблицах на этих столбцах WHERE, где условия фильтруют большую часть строк в таблице.

  3. слияние

    Здесь нужен индексы на столбцах в состоянии слияния, чтобы позволить PostgreSQL использовать сканирование индекса для сортировки. Кроме того, вы можете добавлять столбцы, которые отображаются в предложении WHERE.

Всегда проверяйте с помощью EXPLAIN, если ваши индексы будут использоваться. Если нет, то вероятность того, что они не могут быть использованы или что их использование сделает запрос медленнее, чем последовательное сканирование, например. потому что они не фильтруют достаточно строк.

+0

Спасибо Laurenz, я никогда не использовал объяснение, поэтому я не думал об этом. Я добавил вывод к моему вопросу, но, честно говоря, он не говорит много, потому что я действительно не знаю, как его интерпретировать. Могли бы вы дать мне руку? – Christoffer

+0

Вам нужен вывод EXPLAIN из производственной системы. В тестовой системе все выглядит нормально (всего 453 строки во внутренней таблице, индекс используется для внешней таблицы). –

+0

Я повторно сделал это для производственной системы. Обратите внимание, что FeededProducts имеет около 1,5 млн., Тогда как в магазинах имеется около 1 200 предметов (с фильтром филиала, возможно, 453). Загрузка FeededProducts - это тот, который требует времени. – Christoffer

Смежные вопросы