地理猜谜游戏中SQL条目可变属性的存储与统计方案咨询
嘿,看起来你这个地理猜谜游戏的设计挺有意思的!针对你纠结的存储方案问题,结合你需要做统计功能的核心需求,我给你梳理几个靠谱的方向:
核心需求拆解
首先得明确你现在的核心痛点:
- 条目属性异构:不同类型(国旗、美国州、法国省份)的属性差异大,有的有大洲/次区域,有的只有最大城市这类字段
- 需要高效统计:按地区、条目类型计算胜率、游戏次数,这类聚合查询需要快速响应
不推荐纯JSON文件存储的原因
虽然JSON能轻松存异构数据,但完全用JSON文件的话,做统计会非常麻烦:
- 每次统计都要遍历所有JSON文件解析数据,数据量一大就卡成狗
- 没法做索引,按地区筛选、聚合的效率极低
- 版本控制和并发写入容易出问题(比如多个玩家同时玩的时候,修改统计数据可能冲突)
推荐的存储方案:关系型数据库扩展设计
既然你本来就把条目当成SQL行,那直接基于关系型数据库扩展是最顺的路子,给你两种可行的模式:
模式1:主表+类型专属扩展表(推荐)
这种模式结构清晰,查询效率高,完美适配你的异构属性需求:
- 主条目表:存所有类型条目的通用属性
CREATE TABLE entries ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, entry_type VARCHAR(50) NOT NULL, -- 比如"flag", "us_state", "french_department" created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );
- 类型专属扩展表:针对每种条目类型建单独的表,存专属属性
-- 国旗专属表 CREATE TABLE entry_flags ( entry_id INT PRIMARY KEY, former_name VARCHAR(255), country_code VARCHAR(5), continent VARCHAR(50), subregion VARCHAR(50), capital VARCHAR(255), FOREIGN KEY (entry_id) REFERENCES entries(id) ); -- 美国州专属表 CREATE TABLE entry_us_states ( entry_id INT PRIMARY KEY, capital VARCHAR(255), largest_city VARCHAR(255), FOREIGN KEY (entry_id) REFERENCES entries(id) );
- 统计数据表:单独存游戏记录,方便后续统计
CREATE TABLE game_stats ( id INT PRIMARY KEY AUTO_INCREMENT, entry_id INT NOT NULL, player_id VARCHAR(255) NOT NULL, -- 玩家标识,比如用户名/ID is_won BOOLEAN NOT NULL, played_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (entry_id) REFERENCES entries(id) );
优势:
- 每个类型的属性结构清晰,不会有冗余字段
- 查询条目信息时,用
JOIN就能把主表和扩展表的数据拼起来,给信息标签页用 - 统计胜率/次数超级方便,比如按大洲统计国旗的胜率:
SELECT ef.continent, COUNT(gs.id) AS total_games, SUM(CASE WHEN gs.is_won THEN 1 ELSE 0 END) AS won_games, (SUM(CASE WHEN gs.is_won THEN 1 ELSE 0 END)/COUNT(gs.id))*100 AS win_rate FROM game_stats gs JOIN entry_flags ef ON gs.entry_id = ef.entry_id GROUP BY ef.continent;
模式2:EAV(实体-属性-值)模型
如果条目类型特别多,不想建太多扩展表,可以用EAV模式:
CREATE TABLE entries ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL, entry_type VARCHAR(50) NOT NULL ); CREATE TABLE entry_attributes ( entry_id INT NOT NULL, attribute_key VARCHAR(50) NOT NULL, attribute_value VARCHAR(255) NOT NULL, PRIMARY KEY (entry_id, attribute_key), FOREIGN KEY (entry_id) REFERENCES entries(id) );
比如国旗条目ID=1的属性就存成:
| entry_id | attribute_key | attribute_value |
|---|---|---|
| 1 | former_name | United Kingdom of Great Britain and Northern Ireland |
| 1 | country_code | GB |
| 1 | continent | Europe |
注意点:
- 优点是灵活,新增条目类型不用改表结构
- 缺点是查询多条属性时需要多次
JOIN或者用聚合函数,性能比模式1差,统计的时候写法也更复杂,适合条目类型极多但查询频率不高的场景
总结
结合你需要做按地区统计胜率这类核心功能,主表+类型专属扩展表的方案是最优解:既解决了异构属性的存储问题,又能高效支持各种统计查询,完全适配你的游戏需求。
内容的提问来源于stack exchange,提问作者x dd
相关产品推荐
相关产品推荐

