优化表

问题描述 投票:0回答:1

所以,我希望创建一个具有许多玩家的闲置在线游戏。

到目前为止,我已经设计了5张桌子,但是我不确定它们的优化程度。尤其是user_equipment表中充满了外键。 inventory表也感觉很快就会填满。

node.js sqlite optimization normalization
1个回答
0
投票

这对于小型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_iditem_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表。

© www.soinside.com 2019 - 2024. All rights reserved.