Коли додати, які індекси до таблиці в 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 версії, індекс буде створений автоматично, докладнішу інформацію див. Тут .

Чи слід додати "індекс" до автоматично створеного стовпця "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поле не повинно бути унікальним!

Для отримання більш детальної інформації про це вам слід поглянути на чудову відповідь тадмана .


3
Чудова відповідь. Додаткове запитання. Я повинен додати "індекс унікальним" для xxx_id, правда?
ТЗ.

Питання, чи індексуєте ви іноземний ключ, якщо це поле дуже рідко шукається явно?
Noz

@Cyle Я не можу відповісти на це однозначно, це залежить від вашої машини, розміру бази даних та характеру вашого запиту. Якщо запит надходить з Інтернету, я б, напевно, сказав ТАК, тому що завжди краще отримувати швидкі відповіді, якщо це для фонових завдань і вам потрібно зекономити місце на диску, вам не потрібно його встановлювати, але якщо місце на диску це не проблема, я б все одно додав індекс.
джигфокс

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до визначення колонки для простих випадків досить просто, але іноді вам може знадобитися більше контролю над ним. Наявність індексів за замовчуванням на зовнішніх ключах не є страшним за замовчуванням, але це може застати людей зненацька.
тадман

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 , рейки - створено_at при користуванні для замовлення, чи слід додати індекс до таблиці? , і відповіді вище.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.