Когда добавлять какие индексы в таблицу в Rails

131

У меня вопрос по базе данных Rails.

  • Должен ли я добавить «индекс» ко всем внешним ключам, например «xxx_id»?
  • Должен ли я добавить «индекс» в автоматически созданный столбец «id»?
  • Должен ли я добавить «индекс (уникальный)» в автоматически созданный столбец «id»?

  • Если я добавлю индекс сразу к двум внешним ключам ( add_index (:users, [:category, :state_id])что произойдет? Чем это отличается от добавления индекса для каждого ключа?

    class CreateUsers < ActiveRecord::Migration
      def self.up
        create_table :users do |t|
          t.string :name
          t.integer :category_id 
          t.integer :state_id
          t.string :email
          t.boolean :activated
          t.timestamps
        end
      # Do I need this? Is it meaningless to add the index to the primary key?
      # If so, do I need :unique => true ?
      add_index :users, :id 
      # I don't think I need ":unique => true here", right?
      add_index :users, :category_id # Should I need this?
      add_index :users, :state_id # Should I need this?
      # Are the above the same as the following?
      add_index (:users, [:category, :state_id])
      end
    end

Пока что отличный ответ. Дополнительный вопрос

  • Я должен добавить «индекс с уникальным» для xxx_id, верно?
ТЗ.
источник

Ответы:

175

Должен ли я добавить «индекс» ко всем внешним ключам, например «xxx_id»?

Лучше бы, потому что это ускоряет поиск при сортировке в этом столбце. И внешние ключи очень часто ищут.

Начиная с версии 5 rails индекс будет создан автоматически, дополнительную информацию см. Здесь .

Должен ли я добавить «индекс» в автоматически созданный столбец «id»?

Нет, это уже сделано по рельсам

Должен ли я добавить «индекс (уникальный)» в автоматически созданный столбец «id»?

Нет, как указано выше

Если я добавлю индекс сразу к двум внешним ключам ( add_index (:users, [:category_id, :state_id])что произойдет? Чем это отличается от добавления индекса для каждого ключа?

Тогда индекс - это комбинированный индекс двух столбцов. Это не имеет никакого смысла, если вы не хотите , чтобы все записи для одного category_id И один state_id(он должен быть category_idне category) одновременно.

Такой индекс ускорит выполнение следующего запроса:

# rails 2
User.find(:all, :conditions => { :state_id => some_id, :category_id => some_other_id })

# rails 3
User.where(:state_id => some_id, :category_id => some_other_id)

куда

add_index :users, :category_id
add_index :users, :state_id

ускорит эти запросы:

# rails 2+3
User.find_by_category_id(some_id)
User.find_by_state_id(some_other_id)

# or
# rails 2
User.find(:all, :conditions => {:category_id => some_id})
User.find(:all, :conditions => {:state_id => some_other_id})

# rails 3
User.where(:category_id => some_id)
User.where(:state_id => some_other_id)

Я должен добавить «индекс с уникальным» для xxx_id, верно?

Нет, потому что если вы сделаете это, только один пользователь может быть в одной категории, но смысл категории является то , что вы можете поместить больше многих пользователей в одну категорию. В вашей Userмодели у вас есть что-то подобное, belongs_to :categoryа в вашей модели категории что-то вроде has_many :users. Если у вас есть has_manyотношения, foreign_keyполе не должно быть уникальным!

Для получения более подробной информации по этому поводу вы должны взглянуть на отличный ответ tadman .

jigfox
источник
3
Отличный ответ. Дополнительный вопрос. Я должен добавить «индекс с уникальным» для xxx_id, верно?
ТЗ.
Вопрос, вы бы индексировали внешний ключ, если это поле очень редко просматривается явно?
Noz
@Cyle Я не могу ответить на этот вопрос однозначно, это зависит от вашей машины, размера базы данных и характера вашего запроса. Если запрос поступает из Интернета, я бы, вероятно, сказал ДА, потому что всегда лучше получать быстрые ответы, если это для фоновой работы и вам нужно сэкономить дисковое пространство, вам не нужно его устанавливать, но если дисковое пространство это не проблема, я бы все равно добавил индекс.
jigfox 08
111

Индексирование может быть сложной и тонкой задачей, но существуют общие правила, которые могут значительно упростить определение того, что использовать.

Первое, что следует помнить, это то, что индексы могут работать более чем одним способом. Индекс для A, B, C также работает для A, B и просто для A, поэтому вы можете разработать свои индексы, чтобы они были более универсальными, если вы упорядочите их правильно. Телефонная книга проиндексирована по фамилии, имени, поэтому вы можете легко искать людей по фамилии или комбинации фамилии и имени. Однако вы не можете искать их напрямую по имени. Для этого вам понадобится отдельный индекс. То же самое и с номером телефона, который вам также придется проиндексировать.

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

  • Если у вас есть пара отношений belongs_to- has_many, вам нужен индекс для используемого внешнего ключа.
  • Если вы упорядочиваете свои записи, и их большое количество будет разбито на страницы, вам следует добавить этот столбец порядка в конец индекса.
  • Если у вас есть has_many :throughсвязь, ваша таблица соединения должна иметь уникальный индекс для обоих свойств, участвующих в объединении, в качестве составного ключа.
  • Если вы извлекаете запись напрямую, используя уникальный идентификатор, такой как имя пользователя или адрес электронной почты, это должен быть уникальный индекс.
  • Если вы выбираете наборы записей из has_manyотношения с использованием области, убедитесь, что существует индекс, который включает has_manyвнешний ключ и столбец области в этом порядке.

Целью индексов является устранение ужасных операций «сканирования таблиц» или «сортировки файлов», которые происходят, когда ваши данные не индексируются должным образом.

Проще говоря, смотреть на запросах, вырабатываемый вашего приложение и убедиться , что столбцы , указанные в WHEREили HAVINGусловиях и ORDER BYположениях представлены в таком порядке.

Тадман
источник
1
Мне любопытно, почему Rails не подразумевает индексы, если вы всегда хотите использовать их для каждого внешнего ключа. Есть ли ситуация, когда его индексировать не рекомендуется?
Поездка
1
@trip Довольно легко добавить index: trueв определение столбца для простых случаев, но иногда вам может понадобиться больше контроля над ним. Наличие по умолчанию индексов для внешних ключей - это не ужасно, но это может застать людей врасплох.
tadman
13
  • Всегда индексируйте внешние ключи
  • Всегда индексируйте столбцы, по которым вы будете заказывать
  • Все уникальные поля (для обеспечения уникальности на уровне базы данных Пример миграции:. add_index :users, :email, unique: true)
  • Если вы заказываете по двум параметрам или выполняете поиск по двум параметрам, например: order by [a, b]или find where( a and b ), то вам нужен двойной индекс:

Конкретный пример:

Если у вас есть:

default_scope :order => 'photos.created_at DESC, photos.version DESC'

Вы должны добавить:

add_index :photos, [:created_at, :version]

Примечание. Индекс занимает дополнительное место на диске и замедляет создание и обновление каждой записи, так как он должен перестраивать каждый индекс.

Кредит:

https://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexes , rails - created_at, когда пользователь для заказа, следует ли добавлять индекс в таблицу? , и ответы выше.

Уилл Тейлор
источник