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

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

ただいまの
回答率

90.35%

  • MySQL

    7418questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

  • CakePHP

    2607questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

CakePHPの「PRIMARY ID」とSQLの主キーが違うのですが

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,903

smnsmn

score 170

記事とコメントをそれぞれ保存しているテーブルがあります。

<記事 postsテーブル>
idオートインクリメントで振っている数字のみのID
post_idランダム英数字10文字のユニークID(以下オリジンIDとします)

◆インデックスはidにPRIMARYで付いています

<コメント commentsテーブル>
idオートインクリメントで振っている数字のみのID
post_id動画につけたオリジンID

◆インデックスはidにPRIMARYで付いています


を各々保存しています。

CakePHPで記事とコメントをアソシエーションしています。
主キーはpost_idで、このオリジンIDで記事とコメントは紐付いています。

// Model:Post
class Post extends AppModel {
    public $primaryKey = 'post_id';
:
:
}

//Model:Comment
class Comment extends AppModel {
    public $belongsTo = array(
                                'Post' => array(
                                    'className' => 'Post',
                                    'type' => 'INNER',
                                    'foreignKey' => 'post_id',
                                    'conditions' => array('status' => 0),
                                    'fields' => array(
                                                                'post',
                                                                'title',
                                                                'text',
                                                                'count',
                                                                'created'
                                                            )
                                            ));


上記を踏まえて質問です。

①まず、基本的に他の機能でもidでデータをselectしたり、updateということはなく、だいたいはpost_idでやっています。
やり始めた頃はインデックスもよく分からず、見よう見まねでDBのインデックス、主キーにidを指定していましたが、
この状態ではインデックスは全く意味がないのでは?と思いました・・・。

複合インデックスは好ましくないと見かけたのですが、post_idにもインデックスを付けることでインデックスの役割を果たしてくれるようになるのでしょうか?


②また、DBとCakePHP側で主キーが違うせいで色々ややこしくなっています。
下記のような状態はやはりよくないですよね・・・?
post_idでしか記事とコメントを紐付けられないので、アソシエーションするならprimarykeyはpost_idのままにしておくしかありません。でも下記のような問題も起きるので、
アソシエーションをやめてjoinにするのがいいのか・・・?と悩んでいます。

A.
idをプライマリキーにsave()で情報を上書きしようとすると、
CakePHP側ではpost_idが主キーになっているため、そのidは既に存在するから新しくcreateできないよ!と、
怒られて上書きができない。そのため、updateAllしか使えない。

B.
findById()ならidのほうが主キーとして扱われるが、read()だったらpost_idが主キーとして扱われる。


突っ込みどころが多いと思いますが、どのようにするのが良いか意見頂けると幸いです。
よろしくお願い致します。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

主キーについて

CakePHPを使う場合は、主キーはidにすべきです。
主キーをid以外にするための設定の手間や、規約通りならできることができなくなるデメリットは結構大きいと思います。
正直私もどこまでデメリットがあるか分かりませんが…。
それでも、CakePHPの普通の使い方以外のことをすれば、どこかでバグやコストが出る可能性が出てくることは考慮すべきです。

(ただし、データベースの容量があまりにも足りず、idを入れる容量さえ削りたいなら話は別ですが。)

インデックスについて(訂正後)

post_idは外部キーとして利用するので、MySQLの場合は自動でpost_idにインデックスが付加されます。


自動でインデックスは付加されますが、念のためpost_idを例にインデックスを作る方針を確認します。

一般的にいわれている話ですが、インデックスは基本的に次のような場合に作成します。

  1. 大規模なテーブルに作成する
  2. カーディナリティの高い列に作成する
  3. 検索条件や結合条件に使われるカラムに作成する

上記を踏まえてインデックスを作成すべきか考えます。

  1. 大規模なテーブルに作成する
    数万件程度ならインデックスを作成する必要はありません。
    この閾値は状況によって変わると思いますが、数万件程度なら処理時間の差は大してないと思います。

  2. カーディナリティの高い列に作成する
    カーディナリティとはデータの種類と偏り具合のことです。(詳細は割愛)
    post_idは恐らく種類は多く、偏りもあまり無いはずなので、この項目だけ見るならばインデックスを作成してもいいと思います。

  3. 検索条件や結合条件に使われるカラムに作成する
    post_idを条件に含むケースはあまりないのではないでしょうか。
    記事の更新やコメントの投稿くらいしかpost_idを使わない気がします。
    どちらにせよ、一度に1つしかレコードを更新しないなら、インデックスの有無による差はあまりないはずです。
    ということで、インデックスの必要性は低いと思います。

追記:結構頻繁にアクセス・更新するようですので、インデックスはあってもいいかもしれません。post_id自体は変更しないと思うので、インデックスの更新性能が下がることも少なそうですし。

以上のことから、私はインデックスは作成しなくていいと思います。
インデックスを作成してもしなくても通常は大差無いのではないでしょうか。

テーブルがあまりにも大規模なものならインデックスを作成してもいいかもしれませんが、記事とコメントの関係なら、1,000万件くらいまではインデックス無しでいいと私は考えます。
smnsmnさんのサイトに相当なアクセスがあり、データの規模も相当大きければ話は別ですが。


……このように分析しましたが、結局はpost_idを外部キーに設定するとインデックスが付加されます。
失礼しました。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/07/28 20:20

    回答ありがとうございます。
    とても参考になります。m(__)m

    テーブルに関しては、今のところは数千件なので、大規模ではないので、
    あまり考えなくても良いのかもしれません。

    カーディナリについて、post_idはユニークなので、種類は多いのでカーディナリは高いと思われます。

    post_idを検索条件に含む場合も多数あります。
    Cakeでfindしてくる場合、基本的にはpost_idでデータを引っ張ってきています。
    レコードの更新は複数の場合もあります。

    総合的に、ご教授頂いたことを踏まえるといまはインデックスがなくても耐えうる(というかあってもなくても変わらない)のかなと思いました。

    素朴な疑問ですが、データの件数とアクセスは関係してくるのでしょうか。
    例えば、データは数千だけれど、アクセスが数万〜数十万(あくまで例えばなのでこんなにアクセスはないですが)の場合、
    データは少ないですがインデックスはあったほうが速度等々変わるのでしょうか・・・・?

    データが多く、アクセスも多ければ、インデックスを付けて処理速度をあげなければいけないのは分かるのですが、
    単にアクセス量が多いだけなら、処理は早いので特にインデックスは関係ないのでしょうか。

    なんにせよ、とても勉強になりました。
    主キーについても合わせられるよう、(かなり大規模になりそうですが)修正してみたいと思います。
    ありがとうございましたm(__)m

    キャンセル

  • 2016/07/28 21:12

    すみません、訂正です。
    MySQLの場合は外部キーを設定すると、自動でインデックスが付加されます。
    今回idを主キーとした場合、post_idは外部キーとして利用するので、インデックスは自動で付加されることになります。
    嘘を言って本当にすみませんでした……。

    データの件数が数千であれば、通常はインデックスの有無によるアクセス数の影響はあまりありません。
    むしろWebサーバー(ApacheやNginx)やその他サーバーのリソースによります。
    有名どころではApacheのC10K問題です。
    クライアントが1万人を超えるとサーバーがパンクしてしまうという問題です。

    アクセス数が問題になる場合は、キャッシュを返すよにしたり、リバースプロキシでアクセスを複数台のサーバーに振り分けて負荷を分散したりします。
    データベースが処理のボトルネックになる場合は、データベースサーバーのリソースを増やしたり、複数に分けたりします。

    キャンセル

  • 2016/07/30 13:28

    >MySQLの場合は外部キーを設定すると、自動でインデックスが付加されます。
    今回idを主キーとした場合、post_idは外部キーとして利用するので、インデックスは自動で付加されることになります。

    なるほど、ありがとうございますm(__)m
    アクセスとデータ件数の関係についてもとても勉強になりました。
    サーバーの負荷分散も、SQLの扱い同様課題なので、知識を深めていきたいと思います。

    キャンセル

0

主キーをCakePHP側か実テーブル側に合わせるべきでしょうね。

ただcommentの方はpost_idを主キーにすると関連が1:1になってしまうので、
postとcommentが1:N(1:多)であるならidをそのまま主キーとするか、
post_idともう一つ連番などの識別用の列を用意して複合主キーにするとかですかね。

ただ恐らくデータが入っていると思うので、
今のテーブルをリネーム(post_bkなど)して
正しくテーブル定義し直したものに、

INSERT INTO post SELECT * FROM post_bk


とかで一括移行すると良いと思います。
主キー重複には要注意ですが。

追記①
CakePHPほとんどかじってないから見当違いなこと言ってるかも…。

①と②にも返答しておくと、
①はUNIQUE制約を張れば主キーと似たようなことはできますが、
違いとしとしてNULLが許容される点とNULLに限っては重複が認められる点があります。
まぁNOT NULL制約を合わせてつけるとNULL自体登録不可に出来るのでより主キーっぽくは出来ますが。
(UNIQUE INDEXも勝手に貼られたと思います。)

②は範疇外であまり分からないのですが、
save時にpost_idが重複してこけるのであれば、
save呼び出し前にユニークなpost_idを採番できてないだけとかありませんか?

追記②
質問にあまり関係のない蛇足ですが…
1.post_idは必ず採番される
2.post_idは必ず一意に定まる

上記の要件があるのでしたら主キー制約が張れないにしろ、
UNIQUE制約とNOT NULL制約は、
よっぽどの理由がない限りはpost_idには付与した方が良いです。
(既にしてるということであれば以下もスルーで…)

制約はビジネスルールの再現、データ整合性の保証を可能にするので。
付加的な要素として他の開発者にも意図を伝える手段にもなり得ます。

洗練されたテーブル設計は、
それだけである程度のビジネスルールを浮き彫りに出来ることを知っておいて損はないです。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/07/28 20:25

    回答ありがとうございます。

    >ただcommentの方はpost_idを主キーにすると関連が1:1になってしまうので、
    postとcommentが1:N(1:多)であるならidをそのまま主キーとするか、
    post_idともう一つ連番などの識別用の列を用意して複合主キーにするとかですかね。
    そうですね、postとcommentは1:Nになります。
    commentには、オートインクリメントのid(連番)とpost_idが付いているので、これで複合キーにしておくのがいいのでしょうか・・
    もう少し調べたいと思います。

    制約について、とても参考になりました。
    テーブル構成にもまだ慣れておらず、見よう見まねの部分があったので、
    UNIQUEとNOT NULL制約を付与したいと思います。

    >制約はビジネスルールの再現、データ整合性の保証を可能にする
    ここまで考え、洗礼されたテーブル設計ができるよう勉強していきたいと思います。
    ありがとうございましたm(__)m

    キャンセル

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

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

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

  • MySQL

    7418questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

  • CakePHP

    2607questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。