PostgreSQL – “多态表”vs 3表
我正在使用PostgreSQL 9.5(但升级可以说是9.6).
我有权限表: CREATE TABLE public.permissions ( id integer NOT NULL DEFAULT nextval('permissions_id_seq'::regclass),item_id integer NOT NULL,item_type character varying NOT NULL,created_at timestamp without time zone NOT NULL,updated_at timestamp without time zone NOT NULL,CONSTRAINT permissions_pkey PRIMARY KEY (id) ) -- skipping indices declaration,but they would be present -- on item_id,item_type 以及3对多对多关联的表 -companies_permissions(索引声明) CREATE TABLE public.companies_permissions ( id integer NOT NULL DEFAULT nextval('companies_permissions_id_seq'::regclass),company_id integer,permission_id integer,CONSTRAINT companies_permissions_pkey PRIMARY KEY (id),CONSTRAINT fk_rails_462a923fa2 FOREIGN KEY (company_id) REFERENCES public.companies (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION,CONSTRAINT fk_rails_9dd0d015b9 FOREIGN KEY (permission_id) REFERENCES public.permissions (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE INDEX index_companies_permissions_on_company_id ON public.companies_permissions USING btree (company_id); CREATE INDEX index_companies_permissions_on_permission_id ON public.companies_permissions USING btree (permission_id); CREATE UNIQUE INDEX index_companies_permissions_on_permission_id_and_company_id ON public.companies_permissions USING btree (permission_id,company_id); -permissions_user_groups(索引声明) CREATE TABLE public.permissions_user_groups ( id integer NOT NULL DEFAULT nextval('permissions_user_groups_id_seq'::regclass),user_group_id integer,CONSTRAINT permissions_user_groups_pkey PRIMARY KEY (id),CONSTRAINT fk_rails_c1743245ea FOREIGN KEY (permission_id) REFERENCES public.permissions (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION,CONSTRAINT fk_rails_e966751863 FOREIGN KEY (user_group_id) REFERENCES public.user_groups (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE UNIQUE INDEX index_permissions_user_groups_on_permission_and_user_group ON public.permissions_user_groups USING btree (permission_id,user_group_id); CREATE INDEX index_permissions_user_groups_on_permission_id ON public.permissions_user_groups USING btree (permission_id); CREATE INDEX index_permissions_user_groups_on_user_group_id ON public.permissions_user_groups USING btree (user_group_id); -permissions_users(索引声明) CREATE TABLE public.permissions_users ( id integer NOT NULL DEFAULT nextval('permissions_users_id_seq'::regclass),user_id integer,CONSTRAINT permissions_users_pkey PRIMARY KEY (id),CONSTRAINT fk_rails_26289d56f4 FOREIGN KEY (user_id) REFERENCES public.users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION,CONSTRAINT fk_rails_7ac7e9f5ad FOREIGN KEY (permission_id) REFERENCES public.permissions (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION ) CREATE INDEX index_permissions_users_on_permission_id ON public.permissions_users USING btree (permission_id); CREATE UNIQUE INDEX index_permissions_users_on_permission_id_and_user_id ON public.permissions_users USING btree (permission_id,user_id); CREATE INDEX index_permissions_users_on_user_id ON public.permissions_users USING btree (user_id); 我将不得不像这样运行SQL查询很多次: SELECT "permissions".*,"permissions_users".*,"companies_permissions".*,"permissions_user_groups".* FROM "permissions" LEFT OUTER JOIN "permissions_users" ON "permissions_users"."permission_id" = "permissions"."id" LEFT OUTER JOIN "companies_permissions" ON "companies_permissions"."permission_id" = "permissions"."id" LEFT OUTER JOIN "permissions_user_groups" ON "permissions_user_groups"."permission_id" = "permissions"."id" WHERE (companies_permissions.company_id = <company_id> OR permissions_users.user_id in (<user_ids> OR NULL) OR permissions_user_groups.user_group_id IN (<user_group_ids> OR NULL)) AND permissions.item_type = 'Topic' 假设我们在其他表中有大约10000个权限和类似数量的记录. 我需要担心性能吗? 我的意思是…我有4个外部连接,它应该返回结果相当快(说< 200ms). 我正在考虑声明1个“多态”表,类似于: CREATE TABLE public.permissables ( id integer NOT NULL DEFAULT nextval('permissables_id_seq'::regclass),resource_id integer NOT NULL,resource_type character varying NOT NULL,CONSTRAINT permissables_pkey PRIMARY KEY (id) ) -- skipping indices declaration,but they would be present 然后我可以运行这样的查询: SELECT permissions.*,permissables.* FROM permissions LEFT OUTER JOIN permissables ON permissables.permission_id = permissions.id WHERE permissions.item_type = 'Topic' AND (permissables.owner_id IN (<user_ids>) AND permissables.owner_type = 'User') OR (permissables.owner_id = <company_id> AND permissables.owner_type = 'Company') OR (permissables.owner_id IN (<user_groups_ids>) AND permissables.owner_type = 'UserGroup') 问题: 哪些选项更好/更快?也许有更好的办法呢? a)4个表(permissions,companies_permissions,user_groups_permissions,users_permissions) >我需要声明不同的索引比btree在permissions.item_type? EDIT1: SQLFiddle示例: > wildplasser建议(来自评论),不工作:http://sqlfiddle.com/#!15/9723f8/1 {我也删除了错误的地方谢谢@wildplasser}
我建议将对您的权限系统的所有访问抽象到几个模型类.不幸的是,我发现这样的权限系统有时最终会成为性能瓶颈,而且我发现有时需要对数据表示进行重构.
所以,我的建议是尝试将权限相关的查询隔离在几个类中,并尝试保持与这些类的接口,而不依赖于系统的其余部分. 这里的好方法的例子就是你以上所说的.你实际上并不参与主题表;当您构建权限时,您已经拥有您关心的主题ID. 不良接口的示例将是类接口,可以轻松将权限表连接到任意其他SQL. 我明白你使用SQL而不是SQL上的特定框架提出了这个问题,但是从rails约束名称看来,您正在使用这样的框架,我认为利用它将对您未来的代码有用可维护性. 在10,000行的情况下,我认为这两种方法都可以正常工作. 多态方法确实给你一个更多的控制,如果你遇到性能问题,你可能想检查是否移动它将有所帮助. 如果您开始遇到性能问题,以下是您将来可能需要做的各种事情: >在应用程序中创建一个缓存,将对象(如主题)映射到这些对象的一组权限. 在我的经验中,真正杀死许可系统性能的事情是当你添加一些东西,如允许一个组成为另一个组的成员.在这一点上,您很快就能到达需要缓存或物化视图的位置. 不幸的是,很难给出更具体的建议,而不用实际掌握数据并查看真正的查询计划和实际的性能.我认为,如果你为将来的改变做好准备,那么你会很好. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |