所以,我希望创建一个具有许多玩家的闲置在线游戏。
到目前为止,我已经设计了5张桌子,但是我不确定它们的优化程度。尤其是user_equipment
表中充满了外键。 inventory
表也感觉很快就会填满。
这对于小型RPG来说似乎是一个不错的开始。这里有一些建议。
users.user_id
应为整数。名称会更改,但ID不会更改。添加一个名称列。通常,数据表的主键(与联接表不同)应为简单的整数。
考虑user_equipment
。一堆相同的列是一个红旗。
虽然您有固定数量的库存位置,但请考虑如何搜索玩家是否装备了给定的物品。
select 1
from user_equipment
where user_id = :user_id
and :item_id in (head_id, body_id, hand_id, feet_id, main_hand_id, off_hand_id)
[当您需要添加或删除新插槽时,必须更改(越来越大的)表,并且所有查询也必须更改。您需要六个索引。
而是有一个表来存储插槽的类型以及所需的其他信息。然后是一个表,用于存储每个用户在每个插槽中的内容。这简化了索引编制和搜索。
create slots (
-- You can also use an integer.
-- I chose char(2) because it is easier to know what it is without a join.
slot_id char(2) primary key,
name text not null
);
insert into slots values
('H', 'Head'), ('B', 'Body'), ('MH', 'Main Hand'),
('OH', 'Off Hand'), ('F', 'Feet');
create user_slots (
user_id integer not null references users(id),
item_id integer not null references items(id),
slot_id char(2) not null references slots(slot_id),
-- Enforce only one item per user slot
unique(user_id, slot_id)
)
现在查询用户是否配备了一件物品很容易。
select 1
from user_slots
where user_id = :user_id
and item_id = :item_id
或用户的所有设备,及其插入的插槽。
select slots.name, item_id
from user_slots us
join slots on us.slot_id = slots.slot_id
where user_id = :user_id
或者您可以找到谁装备了什么物品以及在哪个插槽中。
select user_id, item_id, slots.name
from user_slots us
join slots on us.slot_id = slots.slot_id
where item_id = :item_id
索引很重要,可以使性能与表增长保持一致。例如,所有外键都已建立索引。如果您按user_id
或item_id
搜索,SQLite不必搜索整个表。但是,如果您通过没有索引的items.name
搜索,则必须搜索整个项目表。
索引是一个很大的话题。您必须考虑表将如何增长以及如何搜索它们。例如,users
将无限增长。 items
可能只会变得太大。 user_equipped
将随着用户的增长而增长,但是单个用户将只有这么多的项目;由于已将user_id和item_id编入索引,因此您可能会没事的。
例如,由于所有外键均已编入索引,因此检查用户是否装备有物品将表现良好。
select user_id, item_id, slots.name
from user_slots us
join slots on us.slot_id = slots.slot_id
where item_id = :item_id
但是要查找在一段时间内未被检查的用户,除非索引了users.last_checked,否则必须搜索整个表。
select user_id
from users
where last_checked < :time
类似地,索引也用于排序。除非为users.last_checked
编制索引,否则此查询的性能将很差。
select user_id
from users
order by last_checked desc
(并考虑last_checked是否应为
除非有充分的理由将其分开,否则user_stats
应该合并到用户中。
users
user_id TEXT NOT NULL,
attack INTEGER DEFAULT 100,
defense INTEGER DEFAULT 100,
perception INTEGER DEFAULT 5,
spirit_stones INTEGER DEFAULT 0,
cultivation_val INTEGER DEFAULT 0,
last_checked DATE NOT NULL,
PRIMARY KEY(user_id)
如果有充分的理由将其分开,请将所有用户统计信息放在同一位置。
user_stats
user_id TEXT NOT NULL,
attack INTEGER DEFAULT 100,
defense INTEGER DEFAULT 100,
perception INTEGER DEFAULT 5,
spirit_stones INTEGER DEFAULT 0,
cultivation_val INTEGER DEFAULT 0,
FOREIGN KEY(user_id) REFERENCES users(user_id),
PRIMARY KEY(user_id)
users - Stores all users.
user_id TEXT NOT NULL,
last_checked DATE NOT NULL,
PRIMARY KEY(user_id)
分隔user_stats
的一个原因是,您将大量更新统计信息。这可能涉及行锁定。将统计信息放在单独的表中可以避免锁定重要的users
表。