Kiedy dodawać indeksy w tabeli w Railsach

134

Mam pytanie dotyczące bazy danych Railsów.

  • Czy powinienem dodać „index” do wszystkich kluczy obcych, takich jak „xxx_id”?
  • Czy powinienem dodać „indeks” do automatycznie utworzonej kolumny „identyfikator”?
  • Czy powinienem dodać „indeks (unikalny)” do automatycznie utworzonej kolumny „identyfikator”?

  • Jeśli dodam indeks do dwóch kluczy obcych naraz ( add_index (:users, [:category, :state_id])co się stanie? Czym to się różni od dodawania indeksu dla każdego klucza?

    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
    

Jak dotąd świetna odpowiedź. Dodatkowe pytanie.

  • Powinienem dodać „indeks z unikatowym” dla xxx_id, prawda?
TK.
źródło

Odpowiedzi:

176

Czy powinienem dodać „index” do wszystkich kluczy obcych, takich jak „xxx_id”?

Byłoby lepiej, ponieważ przyspiesza wyszukiwanie w sortowaniu w tej kolumnie. A klucze obce są często poszukiwane.

Od wersji 5 railsów indeks będzie tworzony automatycznie, więcej informacji znajdziesz tutaj .

Czy powinienem dodać „indeks” do automatycznie utworzonej kolumny „identyfikator”?

Nie, jest to już zrobione przez szyny

Czy powinienem dodać „indeks (unikalny)” do automatycznie utworzonej kolumny „identyfikator”?

Nie, tak samo jak powyżej

Jeśli dodam indeks do dwóch kluczy obcych naraz ( add_index (:users, [:category_id, :state_id])co się stanie? Czym to się różni od dodawania indeksu dla każdego klucza?

Następnie indeks jest połączonym indeksem dwóch kolumn. To nie ma żadnego sensu, chyba że chcesz mieć wszystkie wpisy dla jednego category_id ORAZ jednego state_id( category_idnie powinno być category) w tym samym czasie.

Taki indeks przyspieszyłby następujące żądanie:

# 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)

Gdzie

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

przyspieszy te żądania:

# 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)

Powinienem dodać „indeks z unikatowym” dla xxx_id, prawda?

Nie, ponieważ jeśli to zrobisz, tylko jeden użytkownik może znajdować się w jednej kategorii, ale znaczenie kategorii polega na tym, że możesz umieścić wielu użytkowników w jednej kategorii. W swoim Usermodelu masz coś takiego, belongs_to :categoryaw modelu kategorii coś takiego has_many :users. Jeśli masz has_manyzwiązek, foreign_keypole nie może być unikalne!

Aby uzyskać bardziej szczegółowe informacje na ten temat, zapoznaj się ze świetną odpowiedzią Tadmana .

jigfox
źródło
3
Świetna odpowiedź. Dodatkowe pytanie. Powinienem dodać „indeks z unikatowym” dla xxx_id, prawda?
TK.
Pytanie, czy zindeksowałbyś klucz obcy, jeśli to pole jest bardzo rzadko przeszukiwane jawnie?
Noz
@Cyle Nie mogę odpowiedzieć na to zdecydowanie, zależy to od twojego komputera, rozmiaru bazy danych i charakteru twojego zapytania. Jeśli zapytanie pochodzi z sieci, prawdopodobnie powiedziałbym TAK, ponieważ zawsze lepiej jest uzyskać szybkie odpowiedzi, jeśli jest to praca w tle i potrzebujesz zaoszczędzić miejsce na dysku, nie musisz go ustawiać, ale jeśli miejsce na dysku to nie jest problem, i tak dodałbym indeks.
jigfox
113

Indeksowanie może być trudną i subtelną rzeczą, ale istnieją ogólne zasady, które mogą znacznie ułatwić określenie, którego użyć.

Pierwszą rzeczą do zapamiętania jest to, że indeksy mogą działać na więcej niż jeden sposób. Indeks na A, B, C działa również dla A, B i po prostu A, więc możesz zaprojektować swoje indeksy tak, aby były bardziej wszechstronne, jeśli uporządkujesz je poprawnie. Książka telefoniczna jest indeksowana według nazwiska, imienia, dzięki czemu można łatwo wyszukiwać osoby według ich nazwiska lub kombinacji nazwiska i imienia. Nie możesz jednak wyszukać ich bezpośrednio po imieniu. Do tego potrzebny byłby oddzielny indeks. To samo dotyczy numeru telefonu, który również musiałbyś zindeksować.

Mając to na uwadze, istnieje wiele rzeczy, które będą decydować o sposobie tworzenia indeksów:

  • Jeśli masz parowanie w relacji belongs_to- has_many, musisz mieć indeks używanego klucza obcego.
  • Jeśli zamówisz swoje rekordy, a jest ich duża liczba, które zostaną podzielone na strony, powinieneś dodać tę kolumnę zamówienia na końcu indeksu.
  • Jeśli masz has_many :throughrelację, twoja tabela łączenia powinna mieć unikalny indeks dla obu właściwości związanych z łączeniem jako klucz złożony.
  • Jeśli pobierasz rekord bezpośrednio za pomocą unikalnego identyfikatora, takiego jak nazwa użytkownika lub adres e-mail, powinien to być unikalny indeks.
  • Jeśli pobierasz zestawy rekordów z has_manyrelacji przy użyciu zakresu, upewnij się, że istnieje indeks zawierający has_manyklucz obcy i kolumnę zakresu w tej kolejności.

Celem indeksów jest wyeliminowanie przerażających operacji „skanowania tabeli” lub „sortowania plików”, które występują, gdy dane nie są prawidłowo indeksowane.

Upraszczając, spójrz na zapytania generowane przez aplikację i upewnij się, że kolumny, do których odwołuje się WHERElub HAVINGwarunki i ORDER BYklauzule, są reprezentowane w tej kolejności.

tadman
źródło
1
Ciekaw jestem, dlaczego Railsy nie zakładają indeksów, skoro zawsze chcesz ich używać dla każdego klucza obcego. Czy jest sytuacja, w której indeksowanie go nie jest dobrym pomysłem?
Wycieczka
1
@trip W index: trueprzypadku prostych przypadków dodanie definicji kolumny jest dość łatwe , ale czasami możesz chcieć mieć nad nią większą kontrolę. Posiadanie domyślnych indeksów kluczy obcych nie jest strasznym domyślnym posiadaniem, ale może zaskoczyć ludzi.
tadman
13
  • Zawsze indeksuj klucze obce
  • Zawsze indeksuj kolumny, według których będziesz zamawiać
  • Wszystkie unikalne pola (w celu zapewnienia niepowtarzalności na poziomie bazy danych Przykład migracji. add_index :users, :email, unique: true)
  • Jeśli zamawiasz według dwóch rzeczy lub wyszukujesz według dwóch rzeczy, na przykład: order by [a, b]lub find where( a and b ), potrzebujesz podwójnego indeksu:

Konkretny przykład:

Jeśli masz:

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

Należy dodać:

add_index :photos, [:created_at, :version]

Uwaga: indeks zajmuje dodatkowe miejsce na dysku i spowalnia tworzenie i aktualizowanie każdego rekordu, ponieważ musi on odbudowywać każdy indeks.

Kredyt:

https://tomafro.net/2009/08/using-indexes-in-rails-choosing-additional-indexes , rails - created_at, gdy użytkownik zamawia, czy należy dodać indeks do tabeli? i odpowiedzi powyżej.

Will Taylor
źródło