Sorry for a big question, but I can’t explain my situation with less information.
I designed a database system that is like this:
CREATE TABLE servers(
ID bigint primary key not null
/* other fields of the server */
);
CREATE TABLE producers(
ID bigint not null,
ServerID bigint not null,
/* other field of the producer */
constraint "PK_producers"
primary key (ID, ServerID),
constraint "FK_producer_servers"
foreign key("ServerID") references "servers"
);
CREATE TABLE records(
ID bigint primary key,
ServerID bigint not null,
ProducerID bigint not null
/* other fields of record */
constraint "FK_records_servers"
foreign key("ServerID") references "servers"
constraint "FK_records_producers"
foreign key("ServerID", "ProducerID") references "producers"
);
CREATE TABLE groups(
ID bigint not null primary key,
GroupName nvarchar(50) not null,
Permissions int not null
/* other fields of the group */
);
CREATE TABLE users(
ID bigint not null primary key,
UserName nvarchar(50) not null unique,
Permissions int not null
/* other fields of user */
);
CREATE TABLE users_in_groups(
UserID bigint not null,
GroupID bigint not null,
constraint "PK_users_in_groups" primary key (UserID, GroupID),
constraint "FK_uig_users" foreign key("UserID") references "users",
constraint "FK_uig_groups" foreign key("GroupID") references "groups"
);
Data will be added to records from producers and each producer may provide 500~2000 records per day and each server usually have 2~4 producer and it is completely normal to have 3~6 server. As you see records table is growing really fast(I periodically archive some data and shrink database but records table usually have > 100000 record).
Now my question is:
As you see users have different permissions, based on which group they currently belong and which permissions applied to them by administrators, now I have to advance this system in a way that each user may have different permissions to different items(server, producer and record) in a way that if a user have explicit permission to an item use that permission otherwise use permission from parent and at least global permissions of the user. For example user permissions to a record will be indicated from permissions that applied to that record, its producer, its server or permissions that defined for the user.
As first workaround I think I will implement relation tables that provide relation between user and various objects as follow:
CREATE TABLE user_server_permissions(
UserID bigint not null,
ServerID bigint not null,
Permissions int not null,
constraint "PK_usp" primary key ("UserID", "ServerID"),
constraint "FK_usp_users" foreign key ("UserID") references "users",
constraint "FK_usp_server" foreign key ("ServerID") references "servers"
);
CREATE TABLE user_producer_permissions(
UserID bigint not null,
ServerID bigint not null,
ProducerID bigint not null,
Permissions int not null,
constraint "PK_upp" primary key ("UserID", "ServerID", "ProducerID"),
constraint "FK_upp_users" foreign key ("UserID") references "users",
constraint "FK_upp_server" foreign key ("ServerID") references "servers"
constraint "FK_upp_producer" foreign key ("ServerID", "ProducerID") references "producers"
);
CREATE TABLE user_record_permissions(
UserID bigint not null,
RecordID bigint not null,
Permissions int not null,
constraint "PK_urp" primary key ("UserID", "ServerID"),
constraint "FK_urp_users" foreign key ("UserID") references "users",
constraint "FK_urp_record" foreign key ("RecordID") references "records"
);
But using this approach really decrease performance, because main table that I work with it is records and it is a rare condition that an administrator set special permission for a record and most records should use permissions from their producer but using this technique I should check multiple tables for each access to records table. For example a simple query like:
SELECT * FROM "records" WHERE /* Some condition */ AND record_is_accessible( "ID" )
Will kill my server that should be able to respond to multiple clients!
Most my clients use MSSQL as DBMS but there are few cases where they use MySQL or ORACLE.
Now can anyone direct me in a way to accomplish the task!?
At first glance, a quick solution would be
to not have 3 separate tables for permissions. Instead you would have this one
Now you want to shape your Third Fk constraint accordingly (if needed)
For example lets say you give Servers an EntityType = 1, Producer –> 2, Record –> 3
Then EntityId and EntityType = 1 references to servers and so on…
This way you can also sort the priority of your permissions by using EntityType (e.g. 1 first, then 2, then 3)