5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[自分用メモ] Rails DBのインデックスの考察

5
Posted at

インデックスがよくわからなかったので以下の記事を読んで考えた。

Rails: 闇雲にインデックスを付けてはいけない(翻訳)

インデックスとは、ソートしたカラムを別にコピーして作るようだが、
イマイチ理解できなかったので考察する。

未経験で間違っている前提で書いているので参考にはしないでいただきたい。

上記記事で、例で以下のモデルがあった。

class ShoppingCart < ActiveRecord::Base
  has_many :shopping_cart_products
  has_many :products, through: :shopping_cart_products
end

class ShoppingCartProduct < ActiveRecord::Base
  belongs_to :shopping_cart
  belongs_to :product
end

class Product < ActiveRecord::Base
end

ShoppingCart(カート)
ShoppingCartProduct(カートの商品)
Product(商品)

三つのモデルを作成しているが、ここからつまずいた。

ShoppingCartProductをあえて中間する必要性はなんだろうか、と。
ShoppingCartとProductを直接関連付けない理由は何か、と。

ShoppingCartとProductを仮に関連付けた場合、
カートに入っている商品をクエリすることになるということだろう。

直接商品をクエリすると何がダメなのか。
ここではあえてカートの商品を使っていることと、DBはクエリの速度を出来るだけ上げたいことから言って
カートの商品を間に介入させて法が効率性が良い結果になることはほぼ間違い無いだろう。
その仮定からすると商品を直接クエリすると単純に遅くなると言うことである。

なぜ遅くなるのか。
具体的なカラムやデータが全て参照記事でで書かれていないので憶測になるが
カートモデルが商品と直接関連付いたとすると、カートに複数の商品が存在することになる。
そして商品を閲覧するために商品モデルからカートIDと関連する商品を抽出する必要がある。

例えば、インデックスをここで貼るとする。
商品をカートID順にソートするのである。
それを商品モデルで別のカラムを作成し、商品IDと連動できるようにする。
インデックスは別にカラムを余計に作ることになるので書き込みが遅くなるようである。
まず1つ考えたのは、単に商品モデルを呼び出したい時にいちいちインデックスを含めて
検索するのでは無いか?と考えた。
2つ目に、商品を追加するごとにインデックスを貼ることになるので書き込みが遅くなるのでは無いか。
3つ目にカートから関連する商品を検索した時に膨大な商品リストからカートの商品を検索しないといけないこと。
カートというのは、頻繁に中身が変わるものだし、何回も参照する。
いくら商品モデルでカートのIDの関連をしているからと言って、
カートを見て、都度商品モデルにクエリするのは大変では無いか。
おそらく3つ目が正しい遅くなる理由で、カートの商品モデルを入れる理由なのだろうと推測している。

ここで、カートの商品モデルを中間として位置付けることにより、
カートに入れるボタンを押した時にカートと商品の関連を付ける。
カートに入れるボタンを押した時に中間がないとだめなのでは?とも考えたが
カートと商品に直接関連性を持たせてもおそらく大丈夫だろう。

カートのボタンを押した時に、自分のカートIDと商品IDを元にカートの商品モデルを作成し、
仲介するという理解である。

class CreateShoppingCartProducts < ActiveRecord::Migration
  def change
    create_table :shopping_cart_products do |t|
      t.integer :quantity, limit: 1, null: false
      t.belongs_to :shopping_cart, index: true, foreign_key: true
      t.belongs_to :product, index: true, foreign_key: true

      t.timestamps null: false
    end
  end
end

インデックスの話であるが、
カートの一覧を見た時に、カートの商品を検索する。
直接商品を検索することもできるが、インデックスをいちいち商品に貼りたく無いのでは無いかと考えている。
そうなるとカートIDのインデックスをカートの商品に貼り、商品IDから商品を検索したいのかなと考察している。

上の記事の例は、インデックスをカートとカートの商品間、とカートの商品と商品間に貼っているのは間違いで、
カートの商品と商品間にインデックスは貼るなと言っている。
理由としては、カートから商品は検索するが、逆は無いからである。
これは、ふに落ちるので、カートの商品と商品間のインデックスは削除することとなる。
記事では以下のようにインデックスを追加削除するように言っている。

class RemoveIndexShoppingCartProductsOnProductId < ActiveRecord::Migration
  def up
    remove_index(:shopping_cart_products, :product_id)
  end

  def down
    add_index(:shopping_cart_products, :product_id)
  end
end

インデックスの付け方については少し理解できたが、
DBの設計はまだまだ理解が追いついてないなと感じたため、
簡単なDB設計例で考察してみることとする。

一般的なDB構成例をただ無意識に使うのではなく、
一度立ち止まってなぜこのような設計なのか考える時間も必要である。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?