Tôi đang sử dụng PostgreSQL 9.5 (nhưng nâng cấp có thể nói 9.6).PostgreSQL - "bảng đa hình" so với 3 bảng
Tôi có quyền bàn:
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
Và 3 bảng cho nhiều-nhiều hiệp hội
-companies_permissions (+ chỉ số khai)
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 (+ tuyên bố chỉ số)
CREATE TABLE public.permissions_user_groups
(
id integer NOT NULL DEFAULT nextval('permissions_user_groups_id_seq'::regclass),
permission_id integer,
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 (chỉ số + Tờ khai)
CREATE TABLE public.permissions_users
(
id integer NOT NULL DEFAULT nextval('permissions_users_id_seq'::regclass),
permission_id integer,
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);
tôi sẽ phải chạy truy vấn SQL như thế này rất nhiều lần:
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'
Hãy nói rằng chúng tôi có khoảng 10000 cho phép và số tiền tương tự các bản ghi bên trong các bảng khác.
Tôi có cần phải lo lắng về hiệu suất không?
Ý tôi là ... Tôi có 4 LEFT OUTER JOIN
s và nó sẽ trả lại kết quả khá nhanh (ví dụ: < 200ms).
Tôi đã suy nghĩ về tuyên bố 1 "đa hình" bảng, một cái gì đó như:
CREATE TABLE public.permissables
(
id integer NOT NULL DEFAULT nextval('permissables_id_seq'::regclass),
permission_id integer,
resource_id integer NOT NULL,
resource_type character varying NOT NULL,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL,
CONSTRAINT permissables_pkey PRIMARY KEY (id)
)
-- skipping indices declaration, but they would be present
Sau đó, tôi có thể chạy truy vấn như thế này:
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')
CÂU HỎI:
- Tùy chọn nào tốt hơn/nhanh hơn? Có lẽ có cách nào tốt hơn để làm điều này?
a) 4 bảng (permissions, companies_permissions, user_groups_permissions, users_permissions
) b) 2 bảng (permissions, permissables
)
Tôi có cần phải khai báo các chỉ số khác biệt so với
btree
trênpermissions.item_type
?Tôi có cần chạy vài lần mỗi ngày
vacuum analyze
cho các bảng để làm cho chỉ mục hoạt động (cả hai tùy chọn)?
EDIT1:
ví dụ SQLFiddle:
- wildplasser đề nghị (từ bình luận), không làm việc: http://sqlfiddle.com/#!15/9723f8/1
- Original truy vấn (4 bảng): http://sqlfiddle.com/#!15/9723f8/2
{Tôi cũng đã xóa các dấu backticks ở địa điểm sai nhờ @wildplasser}
Cố gắng di chuyển các điều kiện đề cập đến các bảng LEFT JOINed sang phần ON .... Điều này sẽ tránh tất cả các 'OR NULL' xấu xí trong mệnh đề WHERE. Và không sử dụng backticks cho literals. – wildplasser
@wildplasser cảm ơn bạn đã trả lời. vâng tôi biết về backtips (OS X thêm chúng thay vì dấu nháy đơn) ... Tôi đã thử giải pháp của bạn - nhưng tôi nhận được kết quả kết hợp. SQLfiddle -> http://sqlfiddle.com/#!15/9723f8/1 –
Trong khi phiên bản 'cũ' hoạt động - http://sqlfiddle.com/#!15/9723f8/2. C 'NG 'INNER JOIN' sẽ không hoạt động ở đây. Tôi cần phải nhận được một cái gì đó giống như trong phiên bản gốc đó là '(điều kiện OR condition2 HOẶC condition3)'. –