在 MySQL 中存储用户设置的最佳方式?
Posted
技术标签:
【中文标题】在 MySQL 中存储用户设置的最佳方式?【英文标题】:Best way of storing user settings in MySQL? 【发布时间】:2013-01-02 16:03:35 【问题描述】:我只是想知道为我的 Web 应用程序存储用户特定设置的最佳方式是什么?只是用户可能有的偏好。我想到了两个选择:
用户表 - 我将为我的用户准备一个表。创建一个名为“preferences”的列并将序列化数据存储在 key => value 对中
设置表 - 有一个名为 settings 的单独表,其中包含 user_id 列。以同样的方式保存设置
任何意见将不胜感激。谢谢:)!
--
编辑:只是补充一点,如果我没有序列化/json 或任何要放入数据的数据,我必须为每个设置都有一个列。
【问题讨论】:
在我看来是 cookie 的一个很好的替代品,因为您的选项列表不够大(类似 blob),并且如果您使用 json 或序列化,应该可以正常工作 @cristi_b 除非它必须在不同的浏览器之间持久存在,或者由与 HTTP 响应不直接相关的函数(例如 CRON)访问。 @Matthew 确切地说,cookie 不会持久 【参考方案1】:对于始终为每个用户设置的任何内容,您应该按照通常的规范化将其保存在Users
表中。至于可选配置,我倾向于喜欢下面的表结构:
TABLE Users:
id INT AI
name VARCHAR
...
TABLE User_Settings
user_id INT PK,FK
name VARCHAR PK
type BOOL
value_int INT NULL
value_str VARCHAR NULL
User_Settings.type
指定是否应引用整数或字符串字段。
即:
INSERT INTO Users (id, name) VALUES (1, 'Sammitch');
INSERT INTO User_Settings (user_id, name, type, value_int) VALUES (1, 'level', 1, 75);
INSERT INTO User_Settings (user_id, name, type, value_str) VALUES (1, 'lang', 0, 'en');
对于插入/更新问题:
INSERT INTO User_Settings (user_id, name, type, value_str) VALUES (1, 'lang', 0, 'fr')
ON DUPLICATE KEY UPDATE value_str='fr';
此外,正如大多数其他人所说,序列化和存储首选项并不是一个特别好的主意,因为:
-
您无法通过查询检索单个值,您必须检索整个序列化字符串,对其进行反序列化,并丢弃不必要的数据。
它很容易被破坏,并且难以恢复。
编写原始查询是一件很痛苦的事,即:全局修复某个设置。
您将本质上是表格数据的内容存储在单个表字段中。
2016 年 9 月回顾编辑:
在此期间,我与人们就如何最好地存储可选设置以及上面定义的通用表结构发生了一些争论。
虽然该表结构并非完全糟糕,但也并非完全良好。它试图充分利用糟糕的情况。只要您可以适应这些设置,可选设置的序列化就可以工作:
-
一次性加载所有内容,无需挑选或选择。
不可索引、不可搜索或易于修改大量。
然后您可能会考虑在Users
表中添加一个类似optional_settings
的字段,其中包含设置的序列化[例如:JSON] 形式。您确实需要权衡上述内容,但这是一种更直接的方法,您可以存储更复杂的设置。
此外,如果您使用像 TEXT
这样的 LOB 类型进行存储,则至少在 mysql 中,数据不一定存储在“行中”。
无论如何,由您决定您的应用程序的要求和约束是什么,并根据这些信息做出最佳选择。
【讨论】:
@Prash 是的。不过,比每个设置的额外列更易于管理。 +1 这个解决方案非常好,因为您可以为一个用户编写 5 个设置,为另一个用户编写 20 个设置,这是一个灵活的解决方案。为了提高性能,给 user_id 添加一个索引就完成了 @cristi_b 复合主键user_id,name
是最好的,我相信。
@Prash 这就是键和 mySQL 的 ON DUPLICATE KEY UPDATE
语法的用途。
顺便说一句,如果您的设置值是不同的类型(int、float、string、boolean 等),那么使用一个(字符串/枚举)列可能会更好用于类型,另一个(字符串)用于值。那么你就不需要多列了——每个值类型都有一个列……例如:INSERT [...] VALUE (1, 'level', 'int', '75');
INSERT [...] VALUE (1, 'singer', 'string', 'freddie');
【参考方案2】:
这完全取决于您的数据库的设置和架构。无论您做什么,我都建议您不要按照您的建议 1 序列化数据,如果您序列化数据,您将无法再针对它编写查询,并且您需要使用与序列化它的语言相同的语言来反序列化它(或编写类似的东西)那种语言)。
我推荐的选项是将设置放在 users 表中,每列 1 个设置。这样做的缺点是当您向应用程序添加新设置时,您必须编写一些 DDL 脚本来添加新列。这样做的一个(非常好的)优点是每个设置都可以有自己的数据类型。如果此设置是可选的,这也会产生存储损失。
另一个选项可能是使用设置表,如您所建议的,主键为 (user_id, setting_name),第三列设置值。此解决方案假定所有设置都具有相同的数据类型。您无需编写 DDL 脚本来添加新设置,只需使用新的键名即可。
【讨论】:
每个设置都有一个列的设置表怎么样? 我不建议这样做,因为主键只是user_id
(1 个用户记录,1 个设置记录)。这将是我提出的两种解决方案的缺点。
我明白了。我会考虑的。谢谢!
“每列 1 个设置”。我认为这是一个非常糟糕的主意。不希望用户表中包含系统可能支持的所有设置。【参考方案3】:
这始终是同一个问题:您需要多久更改一次这些数据?在我看来,有一个单独的表总是一个很好的解决方案,因为它分隔了应用程序的不同方面。
拥有preferences
columns 这不是一个好主意,恕我直言,因为每当您的用户更改其设置时,您都必须序列化他的所有数据以将它们存储在users
表中,无论它只是一个update
与一个单独的。如果您真的想将所有内容存储在users
中,您应该将您的设置分成不同的列。
【讨论】:
【参考方案4】:第二个选项,但通过单独存储设置进行了修改。不要在字段中存储序列化数据,因为在这种情况下是不好的做法。
想一想:您拥有这样的信息,并在那里存储用户所在的国家/地区,或者它是否已注册到您的时事通讯中。稍后..您需要知道有多少人来自俄罗斯。你做什么工作?把它们一一解码并增加一个计数器? (或者使用您的第二种方法并运行一个简单的 SELECT COUNT(id) 查询?)
【讨论】:
你能扩展第一点吗?我将如何构建表格? 只需为您拥有的每个设置添加一个表格列。【参考方案5】:我会使用设置表,因为它可以让以后更容易访问。当您尝试在单个列中创建名称值对等操作时,您可能会在稍后尝试设计查询以访问数据时遇到问题。
【讨论】:
【参考方案6】:这可能不适合您当前的情况,但 NoSQL 数据库(如 Mongo)非常适合此情况。例如,这是一个 mongo 数据库,每个用户对象实际上可以有不同的属性,您仍然可以搜索它们。
也就是说,对于您所处的情况,过去我一直遵循此处其他答案的建议,并有一个单独的表格。这可以通过两种方式完成,有一个单独的表,您可以更轻松地修改其中的列,然后加入它。或者,一个更简单的解决方案,有一个单独的表,例如,
用户、参数、值。
那么每个用户可以有不同的额外价值。
最佳方法取决于您所需的性能等。
【讨论】:
以上是关于在 MySQL 中存储用户设置的最佳方式?的主要内容,如果未能解决你的问题,请参考以下文章