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

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

新規登録して質問してみよう
ただいま回答率
85.50%
MySQL

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

CakePHP

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

Q&A

解決済

2回答

4887閲覧

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

smnsmn

総合スコア175

MySQL

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

CakePHP

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

0グッド

0クリップ

投稿2016/07/22 08:47

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

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

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

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

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

を各々保存しています。

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

PHP

1// Model:Post 2class Post extends AppModel { 3 public $primaryKey = 'post_id'; 4: 5: 6} 7 8//Model:Comment 9class Comment extends AppModel { 10 public $belongsTo = array( 11 'Post' => array( 12 'className' => 'Post', 13 'type' => 'INNER', 14 'foreignKey' => 'post_id', 15 'conditions' => array('status' => 0), 16 'fields' => array( 17 'post', 18 'title', 19 'text', 20 'count', 21 'created' 22 ) 23 )); 24

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

①まず、基本的に他の機能でも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が主キーとして扱われる。

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

主キーについて

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

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

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

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


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

一般的にいわれている話ですが、インデックスは基本的に次のような場合に作成します。
0. 大規模なテーブルに作成する
0. カーディナリティの高い列に作成する
0. 検索条件や結合条件に使われるカラムに作成する

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

  1. 大規模なテーブルに作成する

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

  1. カーディナリティの高い列に作成する

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

  1. 検索条件や結合条件に使われるカラムに作成する

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

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

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

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


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

投稿2016/07/22 10:26

編集2016/07/28 12:32
coba-coba

総合スコア1409

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

smnsmn

2016/07/28 11:20

回答ありがとうございます。 とても参考になります。m(__)m テーブルに関しては、今のところは数千件なので、大規模ではないので、 あまり考えなくても良いのかもしれません。 カーディナリについて、post_idはユニークなので、種類は多いのでカーディナリは高いと思われます。 post_idを検索条件に含む場合も多数あります。 Cakeでfindしてくる場合、基本的にはpost_idでデータを引っ張ってきています。 レコードの更新は複数の場合もあります。 総合的に、ご教授頂いたことを踏まえるといまはインデックスがなくても耐えうる(というかあってもなくても変わらない)のかなと思いました。 素朴な疑問ですが、データの件数とアクセスは関係してくるのでしょうか。 例えば、データは数千だけれど、アクセスが数万〜数十万(あくまで例えばなのでこんなにアクセスはないですが)の場合、 データは少ないですがインデックスはあったほうが速度等々変わるのでしょうか・・・・? データが多く、アクセスも多ければ、インデックスを付けて処理速度をあげなければいけないのは分かるのですが、 単にアクセス量が多いだけなら、処理は早いので特にインデックスは関係ないのでしょうか。 なんにせよ、とても勉強になりました。 主キーについても合わせられるよう、(かなり大規模になりそうですが)修正してみたいと思います。 ありがとうございましたm(__)m
coba-coba

2016/07/28 12:12

すみません、訂正です。 MySQLの場合は外部キーを設定すると、自動でインデックスが付加されます。 今回idを主キーとした場合、post_idは外部キーとして利用するので、インデックスは自動で付加されることになります。 嘘を言って本当にすみませんでした……。 データの件数が数千であれば、通常はインデックスの有無によるアクセス数の影響はあまりありません。 むしろWebサーバー(ApacheやNginx)やその他サーバーのリソースによります。 有名どころではApacheのC10K問題です。 クライアントが1万人を超えるとサーバーがパンクしてしまうという問題です。 アクセス数が問題になる場合は、キャッシュを返すよにしたり、リバースプロキシでアクセスを複数台のサーバーに振り分けて負荷を分散したりします。 データベースが処理のボトルネックになる場合は、データベースサーバーのリソースを増やしたり、複数に分けたりします。
smnsmn

2016/07/30 04:28

>MySQLの場合は外部キーを設定すると、自動でインデックスが付加されます。 今回idを主キーとした場合、post_idは外部キーとして利用するので、インデックスは自動で付加されることになります。 なるほど、ありがとうございますm(__)m アクセスとデータ件数の関係についてもとても勉強になりました。 サーバーの負荷分散も、SQLの扱い同様課題なので、知識を深めていきたいと思います。
guest

0

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

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

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

SQL

1INSERT 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/22 09:48

編集2016/07/22 12:11
Panzer_vor

総合スコア1636

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

smnsmn

2016/07/28 11: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
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問