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

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

ただいまの
回答率

90.49%

  • Ruby on Rails

    7472questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

  • データベース

    717questions

    データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

  • データベース設計

    149questions

    データベース設計はデータベースの論理的や物理的な部分を特定する工程です。

カラム数が多すぎるテーブルの1対1関連での分割方法

受付中

回答 2

投稿

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

yamasho

score 6

お世話になります。

カラム数が200を超えるテーブルを複数扱う案件を受け持ちました。
実際のテーブル情報などは載せれないので似た例としてゲームの情報を扱うテーブルがあったとします。
今回は簡単ですが、このgenreについてもそれぞれたくさんの情報があると50を超えるカラムがあると考えてください。
元のテーブル

私が考える構成は以下のようなものです。
分割後
game_information_genres、game_information_makersそれぞれにも50を超えるカラムがあるとします。

以下のようにgame_informationsテーブルでまとめなくても良いとは思うのですが、game_information_genres、game_information_makersのデータを一度にまとめて取得したいと言った時に簡単に取得できるので中間テーブル?としてgame_informationsテーブルも設置しました。
イメージ説明

この構成(2つ目の画像)は良い設計と言えるでしょうか?

私はこの構成だと以下の問題を持つと考えています。

  • テーブル名が長くなりすぎる
  • それに伴って、関連キーのカラム名が長くなりすぎる
  • SQL実行1回のコストが高くなる

しかし、メリットとして

  • 情報が視覚的に分かりやすくなる
  • 情報取得コードがシンプルになる(ActiveRecord)
  • 構成の変更がしやすい

もあげれるのではないかと考えています。

非常にカラム数が多くカオスで、今後の保守・開発がスムーズに進むようにもっとも望ましい形にしたいと考えています。
皆様のお力を貸していただきたいです。
どうぞよろしくお願い致します。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

+1

良い設計ではないです。

200を超えるカラム数というのは確かに分割する要素はあるのかもしれませんね。
テーブル設計の変更に対しては、正規化の観点でよりよい設計とならないか検討してみてください。
この時、求められる処理と正規化のレベルに注意してください。それが正しい設計につながります。

良い設計ではないとした理由は、保守・開発がスムーズに進むことを目的としているからです。
yamashoさんにとっては求めている回答と少しずれた回答かもしれませんね。
説明します。

テーブル設計として良否を決定するものは"性能"です。テーブル設計としてカラム数が設計の良否を決定づけるものではありません。システムの利用者にとって性能は絶対的評価基準で、処理が遅いシステムはそれだけで悪とみなされます。データベースはシステムの性能の核になります。テーブル設計は最も性能が出るよう努力されたものであることが求められます。

yamashoさんも「SQL実行1回のコストが高くなる」と性能に悪影響があることは想定されています。これは正しいです。「今後の保守・開発がスムーズに進む」この気持ちすごくわかります。ですが、メリットに書かれた内容に利用者にとってのメリットはあるでしょうか。私には我々開発者がよくやる開発側の論理にに見えました。やってしまった結果性能が落ちトータルで悪い結果につながるオチがつくパターンです。

正規化に取り組んでみてください。もしかしたら結果として200カラムを超えるテーブルが出来上がるかもしれません。もしそうなったら、200カラムを超えるテーブルは正しいテーブル設計であったと言えます。

Railsで実装するにあたって200カラムのレコードなんてと思う気持ちわかります。
が、ORマッピング分野においてこの手の話は最適解がない課題なんですよね。。。
極論的には"この部分だけは"フレームワークのORマッピング(RailsのActiveRecord)は使わず自前のORマッピングを用意して捌くと思います。
yamashoさんの構成イメージにある genre と maker を 200カラムレコードの該当カラム使ってObjectにMappingするORマップ処理を自前で作るイメージです。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

カラム数が200を超えるテーブルを複数扱う案件

既に”動いている”という事でしょうか。
であれば、「そのまま」にして、修正は必要最低限に抑えます。
それと、「ゲーム」「ジャンル」「メーカー」を別テーブルに持つか?については、
断片化を考慮した更新頻度、画面設計、性能設計など、様々な要因で決めます。

今回はゲーム名・ジャンル・メーカーが例えなので、
更新(削除)頻度はそこまでないと考えると、
1:1のカラムについて、動いているものをわざわざ分けたりはしない。
カラム名に工夫をしてあげれば、見やすくはなるかと思いますが、カラム名の変更もしない。
テーブル仕様が存在しない場合、カラム名に対するコメントの付与が限界です。

適切なINDEXが貼ってない事が原因で性能劣化があるのであれば
適切なINDEXを付与するだけで、200カラム以上のままの設計にしますね。

ただし、ゲーム名が毎月のように全データが削除・登録されるような要件で、かつ、
ある程度の件数があれば、数か月後には性能劣化する事が明らかなので、
テーブルを分けて、断片化するテーブルとしないテーブルを分けたりするかもしれませんが。
緊急性がない限り、動いているままにする方が良いと思います。

この構成(2つ目の画像)は良い設計と言えるでしょうか?

今回の例(ゲームの例え、かつ、1つのテーブルを1:1に分ける場合)では、
どちらも良い設計ではないかな。

「game_information」テーブルがある方の設計は初期段階であれば、まだ良いですが、gamesとgames_informationを分ける必要性が見当たりません。

「game_information」テーブルがない方の設計はgenre VARCHAR(45)で紐づけするようですが、
VARCHAR(45)もの長さで紐づけするのはあまり良くない設計です。

せめてgenre_id int、maker_id intによる紐づけが良いですが、これは、マスター化する場合の設計なので、今回の"分割"とは違うような。

なお、純粋に分割がありかなしか、を問うのであれば、
games テーブルにある内容を以下の3つに分けて、
game_idで紐づけられるようにするのはありか?となると思います。

games(id,name…)
games_genres(game_id,genre…)
games_makers(game_id,maker…)

この設計がアリかナシかは「…」の中身と全体の仕様次第です。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

関連した質問

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

  • Ruby on Rails

    7472questions

    Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

  • データベース

    717questions

    データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

  • データベース設計

    149questions

    データベース設計はデータベースの論理的や物理的な部分を特定する工程です。