mysql - 黑名单/白名单表设计
问题描述
我们有一组用户
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(254) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED
每个用户可以有一个或多个域,例如
CREATE TABLE `domains` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` varchar(11) NOT NULL,
`domain` varchar(254) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `domain` (`domain`),
CONSTRAINT `domains_user_id_fk` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED
我们有一个包含某种数据的表,对于这个例子,它包含什么并不重要
CREATE TABLE `some_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` TEXT NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED
我们希望某些元素some_data
只能被某些users
或仅某些domains
(白名单情况)访问。some_data
在其他情况下,我们希望每个人都可以访问元素,但某些users
或某些domains
(黑名单情况)。理想情况下,我们希望some_data
在单个查询中检索给定元素可访问的域列表,理想情况下执行相反的操作(列出给定域可以访问的所有数据)
到目前为止,我们的方法是单个表
CREATE TABLE `access_rules` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rule_type` enum('blacklist','whitelist')
`some_data_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`domain_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `access_rules_some_data_id_fk` FOREIGN KEY (`some_data_id`) REFERENCES `some_data` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED
然而问题是我们需要查询数据库两次(以确定给定的数据条目是在操作黑名单还是白名单[白名单具有更高的优先级])。(编辑:可以在单个查询中完成)此外,由于 domain_id 可以为空(以允许将整个用户列入黑名单/白名单)加入并不容易
将使用此模式的 API 目前每秒达到 4-5k 次,因此性能很重要。该users
表相对较小(50k+ 行),domains
表大约有 150 万个条目。some_data
也相对较小(低于 100k 行)
编辑:问题更多的是围绕语义和最佳实践。有了上面的结构,我相信我们可以让它工作,但是模式“感觉不对”,我想知道是否有更好的方法
解决方案
有两个问题需要考虑,规范化和管理。要按照传统方式进行标准化,您需要 4 个表。
设置 3 个主表 USER、DOMAIN、OtherDATA。
使用 User_Id、Domain_Id、OtherDATA_Id、PermissionLevel 设置子表
这提供了最少数量的重复数据。它还使用户域级别的管理变得更加容易。您还可以在用户和域表中添加默认的白名单/黑名单字段。这样,脚本可以自动填充子表,然后经理可以进入并调整所需的一个值。
如果您有两张不同的表,一张用于白名单,一张用于黑名单,您可能会意外地在两个列表中获得用户或域。实际上它将是 4 个表,2 个用于用户,2 个用于域。管理会更复杂。
推荐阅读
- ruby-on-rails - Rails Sitemap_generator 使用 aws_fog 配置
- javascript - 使用位置和滑动进行水平滚动
- python - 如何将对象添加到 Sphinx 的全局索引,或通过别名进行交叉引用?
- encryption - 如何使 AesEncrypterHandler 以与 Aes 相同的方式加密
- azure - 从本地 SSIS 包中读取 Azure Key Vault 机密
- python - 通过 DispatchedMiddleWare 和 ReverseProxy 的 Dash 和 Flask 集成不起作用
- html - 将父文本复制到子文本并删除部分字符串
- sass - SASS - 单击时保持按钮颜色(焦点,活动)
- postgresql - Postgres - 如何使用变量调用函数并从 DBeaver/pgAdmin 返回表/行集
- python - 为什么 PIL 的 Image.fromarray() 会扭曲我的图像颜色?