質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • SQL

    2534questions

    SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

  • Ruby on Rails 5

    2138questions

Railsでmodelの複合キーにunique制約をつける、のイメージがわかない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 591

Statham

score 59

RailsをAPIサーバーとして使えるように開発しています。

 状況

テレビ番組を例にとり、modelには番組情報が入るProgramとテレビ局の情報が入るStationがあるとします。

Program
  title:string, null: false
  detail:text
  station:references, foreign_key: true, null: false
  start_time:datetime
  end_time:datetime

Station
  name:string, null: false
  channel:integer, null: false

以上のような感じの構成で、すでにrails db:migrateされています。

番組の開始時間順に並び替えてjsonを吐くように作っておりますので、開始時間start_timeにindexを貼ろうと考えました。その際、テレビ局station_idstart_timeの関係はuniqueですので、unique制約を付けた方が良いのか迷っています。以下が実行予定のmigrationです。

  def change
    remove_index :programs, column: :station_id
    add_index :programs, [:start_time, :station_id], unique: true
  end

 質問

いまいちunique制約についてイメージが掴めていないのですが、例えば全データの中から.find_by()を使いstation_idで絞り込んで、そこからProgramsの情報を開始時間順に取り出す場合について考えます。

この時、unique制約があることで、どのような仕組みで速くデータが取り出せる(SQLの呼び出しが少なくて済む?)のかがいまいちわかりません。というかそもそも、この場合にunique制約が必要なのかもイマイチわかりません。。

また、こちらには"unique indexの順序"とありますが、これは逆にすると何かがかわるのか、どのように"使えそうな順序"を判断すればよいのかもわかりません。

どなたか、ご教授お願いします。

 解決に際し、参考になったサイト

UNIQUEインデックスとは
UNIQUE制約とは
複合インデックスとは

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

走り書きになりますが少しだけ回答しておきます。

unique制約があることで、どのような仕組みで速くデータが取り出せる(SQLの呼び出しが少なくて済む?)のかがいまいちわかりません。

unique制約
unique index(unique索引)

というのは、データベースの索引の話です。


まず整理すると

unique index(unique索引) 
これは
「検索」機能に対して働くデータベースの速度向上の仕組みです。
そしてこれを使うことで、データベースはB-tree(2分木)や
ビットマップインデックスという「速くデータが取り出せる」仕組みが使えます。
これが1つ目の疑問の回答です。

次ですがunique制約と、もう1つ別の制約があります。
unique制約と、uniqueでない制約があります。
uniqueでない制約は、「一意ではない」つまり重複を許すカラムに対して
検索のためにつける制約です。

そして一意なカラムに索引をつけて、検索向上をする場合
unique制約をつけます(定義します)。


ですので

この場合にunique制約が必要なのか
の問いには

テレビ局station_id(またはstation?)カラムは
一意な(uniqueな)カラムなので
unique制約をつけます。

また

**テレビ局station_idとstart_timeの関係はuniqueですので、unique制約を付けた方が良いのか
**

ですが、上の回答を読んでいただければ
このご自身の認識が間違いであるとわかるでしょう。
(station_idとstart_timeの関係はunique ではなく・・・)


unique indexの順序"とありますが、これは逆にすると何かがかわるのか、どのように"使えそうな順序"を判断すればよいのか

複合キーをきちんと利用するの内容は
正直、不親切だと思いました。

順序は 理論的には・。。

自然キーや複合キーがあるのであれば、それを意識し、正しく扱うことが重要であることは変わらない。
といっても基本的にはunique indexはるだけではある

のくだりなど。
もっと詳しい正しい説明があるので、サイトを探して読んでみてください。
ここでは簡単に。

 def change
    remove_index :programs, column: :station_id
    add_index :programs, [:start_time, :station_id], unique: true
  end

せっかくなので、こちらの実行メソッドを
見直してみてください。

他の方が回答だけ示すかもしれませんが、
いい感じで学習、学ばれている感じがしますので、
ここで回答をとめておきます。

結構大事だと思います、こういう思考の過程。
それでは。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/02 15:53

    なるほど、まず前提としてUNIQUEインデックスとUNIQUE制約についてごっちゃになっていました。

    とりあえずこの2つ、そしてindexがどう働くのかについて理解した上で、複合インデックスについて調べることで問題が解決しました。

    "最初の列は並べ替えの優先順位が最も高く、最初の列に同じ値が複数ある時に限り、2番目の列でも並べ替えがされます。"
    https://use-the-index-luke.com/ja/sql/where-clause/the-equals-operator/concatenated-keys

    つまり、自分の場合では :station_id が一意ですので、
    add_index :programs, [:station_id, :start_time], unique: true
    のような書き方にすることで、:station_id ごとに並び替えられたうえで :start_time順に並んだindexが作成され、自分が行いたい検索の際に有意に働くということ、ですね。
    具体的には
    station_id | start_time |
    1 | 5:00 |
    1 | 6:00 |
    1 | 7:00 |
    2 | 5:00 |
    2 | 6:00 |
    3 | 5:00 |

    のようなイメージで。

    とりあえず自分の中ではすっきりしました。RDBについて、学びが深まる良い機会になりました。
    いい感じにご回答いただき、ありがとうございました。大変たすかりました。

    キャンセル

  • 2018/05/02 21:35

    こんばんは

    ”大変たすかりました。”

    いいえどういたしまして。

    熱心ですね。
    GW連休の谷間ですが、気晴らしをしつつ
    じっくりと、しかし戸惑うことなく
    エラーやトラブルに向き合ってください。
    ここまでは理解できた、正しく作業したと
    実感しながら前に進んでください。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • SQL

    2534questions

    SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

  • Ruby on Rails 5

    2138questions