任何寶貴意見,都感恩於心!
設我有一 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 使用嗎?)
期望大神們多多指教,謝謝!
這是一個很典型的問題,要考慮幾點:
總之,我認為『資料量』及『分析需求』會是schema design 的重要考量。
小喵選擇的話,會選擇A
其A、建立一個 games 總表 所有的 game 都放在 1 張表中
A擔心:1、勢必有些欄位空著沒用形成浪費2、表資料量若過大時效能降低。
文字欄位設定為varchar不定長度,
效能的影響,查詢時有沒有善用index才是最大的關鍵
欄位空著沒用應該還好
個人的想法提供參考
^.^a
給你的建議如下
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);
}
以上補充說明,謝謝大大們指教!
A擔心:1、勢必有些欄位空著沒用形成浪費2、表資料量若過大時效能降低。
都已經 2021 年了,請不必擔心什麼浪費、什麼效能問題了
我會這樣做:
建:
ORM應該會有相關的對應關係。
我傾向一個主表,除非差異欄位很多又很少用才會分
Games( id, name, type, ...大同小異的共用欄位 )
可以依game_type(A/B/C)差異欄位作小表,需要時再JOIN
Game_A( game_id, ...A欄位 ), Game_B( game_id, ...B欄位 ), Game_C(...)...
把上面小表合併,因為game_type會動態產生的話(A/B/C/D/E/...)很恐怖>"<
Game_data( game_id, game_data_type, data ) // 每個差異欄位都會有1筆
Game_data_type( id, game_type, type_name ) // 欄位參數表
直接存成一筆JSON,較常用資料再慢慢獨立成固定欄位index
Game_data( game_id, data(JSON) )
以上都是平常會用到的,但如果只是一點點差異也是不建議分表喔