iT邦幫忙

0

關於 資料表規劃 觀念,向大神們請益!

任何寶貴意見,都感恩於心!
設我有一 Laravel game.test 項目,而因為 game 有很多種類,用戶可以自己選擇種類 新增 game ,建好的 games 可以讓所有用戶去玩。

我目前正在考慮如何建立 games 的資料表:每個 game 其實內容都大同小異(所需資料表欄位只有一些些差異)

我有 A、B 種想法
其A、建立一個 games 總表 所有的 game 都放在 1 張表中
A擔心:1、勢必有些欄位空著沒用形成浪費2、表資料量若過大時效能降低。

其B、依照不同 game 分別建立 不同 game 的表
B擔心:在 index 頁面顯示時,排列會受到牽制。
(ex:我要不管 game 種類,依照時間排序,加上我對 mysql 聯合查詢 不熟悉)
類似這需求:我在 controller 中,能把 $game_A、 $game_B、 $game_C、...整合成 1 個 $gmaes ,然後 compact() 到blade.php 使用嗎?)

期望大神們多多指教,謝謝!

看更多先前的討論...收起先前的討論...
從資料庫的角度出發,我會規畫幾個表
1. USER
2. GAME
3. GAME 分類清單
4. GAME 分類
5. 興趣清單
6. USER 興趣
如果你的遊戲數據也是資料庫,每個遊戲最好有一個資料庫,裡面有遊戲的初始值跟每個user的數據,當user執行遊戲,就可以把數據載入進行遊戲
興趣可以當user對某些新推出的遊戲有興趣時可以進行推撥
可以適度推廣新遊戲,當然上面這些是很基本的架構,實際上會複雜得多
個人經驗給樓主參考
?!但如果這樣,我在首頁排序games的時候,能不能混合不同類的game 一起按時間順序排列
?!但如果這樣,我在首頁排序games的時候,能不能混合不同類的game 一起按時間順序排列
一般來說使用者的首頁顯示的應該是曾經玩過跟有興趣的項目
尤其是一旦遊戲開了副本之後,這點很重要,同一個遊戲也許使用者在不同的副本建立了腳色,你顯示全部的遊戲沒有任何意義,你顯示USER不愛的遊戲分類也沒有意義,遊戲清單用時間排列那是查詢語法就能做到,跟架構沒什麼關係
3
I code so I am
iT邦研究生 2 級 ‧ 2021-04-22 10:45:19
最佳解答

這是一個很典型的問題,要考慮幾點:

  1. 若每個Game的營運(log)資料量很大時,應該考慮分開資料表儲存。
  2. 若有合併分析的需求,則應合為一資料表,否則,分析時要join多個大表,影響效能。
  3. 合併時有些欄位空著沒用形成浪費 ==> 可以將共同欄位合併為一資料表,獨有的欄位以單獨資料表儲存。不過現在記憶體/硬碟很便宜,可以揮霍一點。
  4. 如果分開資料表儲存,也可以利用ETL工具,轉成Data Mart/Data Warehouse分析,如果$與人力不是問題的話。

總之,我認為『資料量』及『分析需求』會是schema design 的重要考量。

謝謝 I code so I am 熱心回應。
內容 分析精闢、中肯、有理,小弟獲益了謝謝!

0
topcattw
iT邦新手 5 級 ‧ 2021-04-21 09:19:00

小喵選擇的話,會選擇A

其A、建立一個 games 總表 所有的 game 都放在 1 張表中
A擔心:1、勢必有些欄位空著沒用形成浪費2、表資料量若過大時效能降低。
文字欄位設定為varchar不定長度,

效能的影響,查詢時有沒有善用index才是最大的關鍵
欄位空著沒用應該還好

個人的想法提供參考
^.^a

謝謝您!如果能的話我倒是很希望不要有無意義的欄位

2

給你的建議如下

1.設定值多表處理:利用一下Laravel的ORM中的「多態1對1」處理。可以將不同遊戲的設定相關值分表出來。
不過如果變動的欄位並不是很多的話。且遊戲種類太多的情況下。我倒是不建議這招。

2.設定值JSON欄位化:將不同遊戲的設定值,採用JSON欄位來做儲存。這樣就可以一表處理。且也不會有所謂的無效欄位的產生。

原則上,因為不太了解你的情況。如果遊戲分類的情況比較多的話。一般我會建議你用第2種方式。
另外可以多多學習 Laravel 中的 ORM 操作。
你的問題很多都可以利用它來處理掉。

看更多先前的回應...收起先前的回應...

謝謝?!
遊戲種類大約最多也只有十多種,我是有設一個game Type做分類,但不太會使用Jain欄位化

謝謝!怎麼變成問號❓我打的字是謝謝?!

可以在 migrations 內的欄位宣告中。
先做

$table->json('setData')->comment('設定資料JSON');

基本來說,會幫你將欄位設定text類型。(MYSQL8則真的會是JSON類)
然後再其對應的 model 內。
做如下的宣告

protected $casts = [
        "setData" => "array",      
    ];

這樣當你用ORM取資料時。就會幫你將setData這個欄位中的JSON資料直接化成陣列給你用了。
很方便

至於如果要多態處理的話。這在宣告上會比較麻煩點。
如想要學再跟你說。

Laravel 的 ORM 如果學的好。可以說幾乎不需要用到JOIN。
就可以辦到很多你想不到的事。

嗯嗯!謝謝您!
我不足的地方還是要繼續加油?!
我會來先練習一下的

我能不能這樣做:
設置 1 個 games 總table 已經包含所有共有屬性,然後根據各種 game 不同屬性的欄位 設置分表 與 模型,然後定義 各種 game 關聯主表 games

    public function games()
    {
        return $this->hasMany(Game::class);
    }
    
        public function game()
    {
        return $this->belongsTo(Games::class);
    }

然後就可以得到我的主要目的:在控制器以及首頁的模板中,自由地使用

控制器中
$games = Games::all();
return view('myIndex', compact('games', $games));

模板中
@foreach({{ $ganes as $game }})

$game->公有地any屬性
也可以
$game->diffGame()->各個不同 game 的 私有屬性

@endforeach

請教這樣合理嗎?

不合理,你搞錯了ORM的應用方式了。
你想要的,其實是多態一對一的處理

你在 games 的 migrations 。多一個如下的宣告

$table->morphs('gamesetable');

然後重跑 migrations

然後再其 games 的 model 內。加入

public function gamesetable()
{
    return $this->morphTo();
}

其它對應的子表model加入
(這段可加可不加,但不加的話,沒辦法在拉子資料時,對應回來主表。基本還是建議加一下)

public function games() {
        return $this->morphOne("App\Models\games","gamesetable");
    }

在PHP內就可以用如下的方式拿到你的子表

....foreach...(懶的寫程式,看得懂就好)
$game->gamesetable
....

以上是多態1對1的關聯方式

其它的關聯新增同步的寫法,就麻煩你研究一下官方的文件去學一下。
我可以提示一下

$gameOrm = new games();
$gameOrm->gamesetable()->associate($gamesetableOrm);

昨天因為回應數達上限所以遲至現在回應星空大大

我可能是描述不夠清楚又說明犯了些錯誤,因為我自己感覺我上面所提的解決方法不是多態一對一,我應該再補充說明一下:
我目前的作法是:想要採取A方案但又不想留一些用不到無意義的空欄位,於是我將每種 game_a、game_b... 的獨有屬性都分別各自建立 1 張表,表中會有的字段只有類似:
ex:games_a

id,
games_id,
self1,
self2

如此之後,模型關係我將之定義(我上面寫的關係定義錯了):
主表 Games 的模型

    public function game_a()
    {
        return $this->hasOne(Game_a::class);
    }

各種不同類別的 game_as 表 的模型

        public function game()
    {
        return $this->belongsTo(Games::class);
    }

以上補充說明,謝謝大大們指教!

1
海綿寶寶
iT邦大神 1 級 ‧ 2021-04-21 09:49:08

A擔心:1、勢必有些欄位空著沒用形成浪費2、表資料量若過大時效能降低。

都已經 2021 年了,請不必擔心什麼浪費、什麼效能問題

看更多先前的回應...收起先前的回應...

謝謝您,其實我也有這樣的想法,但可能是自己鑽牛角尖

如果可以做到首頁排序也很方便的話,我比較傾向第二種,因為資料管理時感覺很直觀

正解只有一個,就是一個 games 資料表

如果你這個心裡的坎過不去
我可以大膽預測
之後你還會碰到其他類似的問題

「會員資料」要用一個資料表
還是
也是內容都大同小異(所需資料表欄位只有一些些差異)?

恩!謝謝您的直言相告

昨天因為回應數達上限所以遲至現在回應海棉寶寶大大:
我真的有點兒強迫症,以前問過的問題如今又重複,但您的這句讓我感到很受用:
正解只有一個,就是一個 games 資料表
謝謝您

0
froce
iT邦大師 1 級 ‧ 2021-04-21 11:44:19

我會這樣做:
建:

  • game總表(相同必有欄位的放在一起)
  • game類別(tag)總表
  • game總表多對多對應game類別

ORM應該會有相關的對應關係。

昨天因為回應數達上限所以遲至現在回應froce大大:
謝謝您熱心回復。
ORM 我真的還需要再深入學習學習!

0
犬千賀
iT邦新手 4 級 ‧ 2021-04-22 15:11:35

我傾向一個主表,除非差異欄位很多又很少用才會分
Games( id, name, type, ...大同小異的共用欄位 )

  1. 可以依game_type(A/B/C)差異欄位作小表,需要時再JOIN
    Game_A( game_id, ...A欄位 ), Game_B( game_id, ...B欄位 ), Game_C(...)...

  2. 把上面小表合併,因為game_type會動態產生的話(A/B/C/D/E/...)很恐怖>"<
    Game_data( game_id, game_data_type, data ) // 每個差異欄位都會有1筆
    Game_data_type( id, game_type, type_name ) // 欄位參數表

  3. 直接存成一筆JSON,較常用資料再慢慢獨立成固定欄位index
    Game_data( game_id, data(JSON) )

以上都是平常會用到的,但如果只是一點點差異也是不建議分表喔

非常感謝您的意見喔!

我要發表回答

立即登入回答