Many of my employers applications share a similar internal permission structure for restricting data to a specific set of users or groups. Groups can also be nested.
The problem we're currently facing with this approach is that enumerating the permissions is incredibly slow. The current method uses a stored procedure with many cursors and temporary tables. This has worked fine for smaller applications, but we now have one particular system which is growing quickly, and it's starting to slow down.
The basic table structure is as follows;
tblUser { UserID, Username, WindowsLogonName }
tblGroup { GroupID, Name, Description, SystemFlag }
tblGroupGroup { GroupGroupID, Name, }
tblGroupUser { GroupUserID, Name, }
and to tie it all together;
tblPermission { PermissionID, SecurityObjectID, SecuredID, TableName, AllowFlag }
which contains rows like..
'5255-5152-1234-5678', '{ID of a Group}', '{ID for something in tblJob}', 'tblJob', 1
'4240-7678-5435-8774', '{ID of a User}', '{ID for something in tblJob}', 'tblJob', 1
'5434-2424-5244-5678', '{ID of a Group}', '{ID for something in tblTask}', 'tblTask', 0
Surely there must be a more efficient approach to enumerating all the groups, and getting the ID's of the secured rows?
To complicate things further; if a user is explicitly denied access to a row then this overrules any group permissions. This is all in MSSQL.
I'm guessing it would be useful to break apart tblPermission into a couple of tables: one for groups and one for users. By having both groups and users in there, it seems to add complexity to the design (and maybe that's why you need the stored procedures).
If you want to break down the tblPermission table (into something like tblUserPermission and tblGroupPermission) but still want a representation of the tables that looks like tblPermission, you can make a view that union's the data from the two tables.
Hope this helps. Do you have examples of what the stored procedures do?
I think you could use a Recursive Common Table Expressions (CTE) hierarchical query. You can find many examples if you search for it. This is one of them.
Perhaps your design is OK, but the implementation/code is wrong.
Some thoughts:
Are all your ID columns GUID? Not recommended Kimberley L Tripp article
Indexes on all foreign keys, perhaps with other columns in key or INCLUDE
Regular maintenance? eg fragmented indexes, stats ot of date etc
Are all datatypes matching (assumes no FKs): datatype precedence and implicit conversion errors may creep in
Some more schema info and examples of poorly performing code may help
Related
I have to implement a testing platform. My database needs the following tables: Students, Teachers, Admins, Personnel and others. I would like to know if it's more efficient to have the FirstName and LastName in each of these tables, or to have another table, Persons, and each of the other table to be linked to this one with PersonID.
Personally, I like it this way, although trickier to implement, because I think it's cleaner, especially if you look at it from the object-oriented point of view. Would this add an unnecessary overhead to the database?
Don't know if it helps to mention I would like to use SQL Server and ADO.NET Entity Framework.
As you've explicitly mentioned OO and that you're using EntityFramework, perhaps its worth approaching the problem instead from how the framework is intended to work - rather than just building a database structure and then trying to model it?
Entity Framework Code First Inheritance : Table Per Hierarchy and Table Per Type is a nice introduction to the various strategies that you could pick from.
As for the note on adding unnecessary overhead to the database - I wouldn't worry about it just yet. EF is generally about getting a product built more rapidly and as it has to cope with a more general case, doesn't always produce the most efficient SQL. If the performance is a problem after your application is built, working and correct you can revisit and fix up the most inefficient stuff then.
If there is a person overlap between the mentioned tables, then yes, you should separate them out into a Persons table.
If you are only tracking what role each Person has (i.e. Student vs. Teacher etc) then you might consider just having the following three tables: Persons, Roles, and a bridge table PersonRoles.
On the other hand, if each role has it's own unique fields, then you should carry on as you are and leave each of these tables separate with a foreign key of PersonID.
If the attributes (i.e. First Name, Last Name, Gender etc) of these entities (i.e. Students, Teachers, Admins and Personnel) are exactly the same then you could just make a single table for all the entities with PersonType or Role attribute added to distinguish each person's role. However, if the entities has a lot of different attributes then it would be better that you create separate tables otherwise you will have normalization problem.
Yes that is a very bad way of structuring a DB. The DB structure should be designed based on the Normalizations.
Please check the normalization forms.
U should avoid the duplicate data as much as possible, else the queries will become slower.
And the main problem is when u r trying to get data that is associated with more than one or two tables.
I need to have a lot of user data in the database. Now, I've been thinking about having two tables, users that would have only the id, username and password and another table userData that would have everything else like name, lastname etc.
Is this a prefered method?
The simplest design would put all the fields in one table. From that point, though, there are a bunch of reasons you might want to consider splitting that information up into multiple tables. From your description, I cant' tell whether there are any valid reasons to do so.
If you start with one table, you might find it advantageous to split the data for reasons such as:
Normalization.
Reducing contention (different parts of the app update different information)
Truly huge column lists (look into the limit for your DB)
Other?? (how you're going to maintain your app, maybe?)
In short, I'd try to start simple and have a reason to pick the more complex design if you go that route.
There is nothing wrong with that design IMHO. You can have a users table and link it to a users_custom table that has additional information. Just be consistant with your design. Just remember that in order to get any additional user information you will always have to JOIN to that data.
To me this is a matter of preference, if you feel that this table will grow over time, consider your design, if not just keep it all in one table and properly index columns that you deem necessary.
You can go further by having a UserLog table to build a historical view of values as they change.
Yes it is :) In theory there are this so called "normal forms" (3NF BCnF, etc...). Using them, means seperating table into smaller ones :)
I think it might be better for you to keep it all in one table. Assuming you will be enforcing unique usernames, all the fields (password, first_name, and last_name) have a functional dependency on username. Therefore, you can put them all in the same table and still have a normalized database.
Although you can certainly separate first_name and last_name into their own table, queries will get a lot easier (fewer JOINs) if you keep all those fields in one table.
So I have a table of user accounts (Users). There needs to be functionality in place for subaccounts.
So for instance, a company named Dunder Mifflin might have an account. The company will have subaccounts, Accounting and Sales. The Accounting account would have subaccounts for Kevin, Angela, and Oscar. And there's no limit on the number of levels.
My initial idea was to create a table like this:
CREATE TABLE Users
(
UserID INTEGER,
ParentUserID INTEGER,
...
)
Where a primary account's ParentUserID would just be null, but a subaccount would contain the UserID of its parent.
Is this a good design for this? I don't know of any other way.
it is a good design for it. An alternative is to use the HIERARCHID data type to mape the hierarchy, but support for that is limited (reporting, ORM tools etc.).
Actually I use EXACTLY this in a number of setups. There simply is not too many alternatives that are not obviously dump (like having X fields for the hierarchy). I acutally know of no single alternative.
That is a good design and you really have little other choice. Read up on CTEs (Common Table Expressions) which will help you query this hierarchical relationships (recursively.)
Recursive querying of hierarchical structures was possible in Sql Server 2000 but is much simplified with CTEs since 2005.
A table that joins to itself will look something like this in your designer:
This is called a self-join and, yes, it is the standard way of representing hierarchical data. You're probably going to need to query like this to get something like all of the users associated with Dunder Mifflin.
What are subaccounts are used for? Database design is a serious matter.
Earlier answers claim that the design you demonstrate is good by definition. When you have hierarchical data, yes, you always have parent ID. However, very often you have some sort of group account to which accounts belong. That would be a more proper place to setup a hierarchy.
I have a table that has a bunch of fields. The fields can be broken into logical groups - like a job's project manager info. The groupings themselves aren't really entity candidates as they don't and shouldn't have their own PKs.
For now, to group them, the fields have prefixes (PmFirstName for example) but I'm considering breaking them out into multiple tables with 1:1 relations on the main table.
Is there anything I should watch out for when I do this? Is this just a poor choice?
I can see that maybe my queries will get more complicated with all the extra joins but that can be mitigated with views right? If we're talking about a table with less than 100k records is this going to have a noticeable effect on performance?
Edit: I'll justify the non-entity candidate thoughts a little further. This information is entered by our user base. They don't know/care about each other. So its possible that the same user will submit the same "projectManager name" or whatever which, at this point, wouldn't be violating any constraint. Its for us to determine later on down the pipeline if we wanna correlate entries from separate users. If I were to give these things their own key they would grow at the same rate the main table grows - since they are essentially part of the same entity. At no pt is a user picking from a list of available "project managers".
So, given the above, I don't think they are entities. But maybe not - if you have further thoughts please post.
I don't usually use 1 to 1 relations unless there is a specific performance reason for it. For example storing an infrequently used large text or BLOB type field in a separate table.
I would suspect that there is something else going on here though. In the example you give - PmFirstName - it seems like maybe there should be a single pm_id relating to a "ProjectManagers" or "Employees" table. Are you sure none of those groupings are really entity candidates?
To me, they smell unless for some rows or queries you won't be interested in the extra columns. e.g. if for a large portion of your queries you are not selecting the PmFirstName columns, or if for a large subset of rows those columns are NULL.
I like the smells tag.
I use 1 to 1 relationships for inheritance-like constructs.
For example, all bonds have some basic information like CUSIP, Coupon, DatedDate, and MaturityDate. This all goes in the main table.
Now each type of bond (Treasury, Corporate, Muni, Agency, etc.) also has its own set of columns unique to it.
In the past we would just have one incredibly wide table with all that information. Now we break out the type-specific info into separate tables, which gives us much better performance.
For now, to group them, the fields have prefixes (PmFirstName for example) but I'm considering breaking them out into multiple tables with 1:1 relations on the main table.
Create a person table, every database needs this. Then in your project table have a column called PMKey which points to the person table.
Why do you feel that the group of fields are not an entity candidates? If they are not then why try to identify them with a prefix?
Either drop the prefixes or extract them into their own table.
It is valuable splitting them up into separate tables if they are separate logical entities that could be used elsewhere.
So a "Project Manager" could be 1:1 with all the projects currently, but it makes sense that later you might want to be able to have a Project Manager have more than one project.
So having the extra table is good.
If you have a PrimaryFirstName,PrimaryLastName,PrimaryPhone, SecondaryFirstName,SecondaryLastName,SEcondaryPhone
You could just have a "Person" table with FirstName, LastName, Phone
Then your original Table only needs "PrimaryId" and "SecondaryId" columns to replace the 6 columns you previously had.
Also, using SQL you can split up filegroups and tables across physical locations.
So you could have a POST table, and a COMMENT Table, that have a 1:1 relationship, but the COMMENT table is located on a different filegroup, and on a different physical drive with more memory.
1:1 does not always smell. Unless it has no purpose.
I've done many web apps where the first thing you do is make a user table with usernames, passwords, names, e-mails and all of the other usual flotsam. My current project presents a situation where non-users records need to function similarly to users, but do not need to the ability to be a first order user.
Is it reasonable to create a second table, people_tb, that is the main relational table and data store, and only use the users_tb for authentication? Does separating user_tb from people_tb present any problems? If this is commonly done, what are some strategies and solutions as well as drawbacks?
This is certainly a good idea, as you are normalizing the database. I have done a similar design in an app that I am writing, where I have an employee table and a user table. Users may a from an external company or an employee, so I have separate tables because an employee is always a user, but a user may not be an employee.
The issues that you'll run into is that whenever you use the user table, you'll nearly always want the person table to get the name or other common attributes you would want to show up.
From a coding standpoint, if you're using straight SQL, it will take a little more effort to mentally parse the select statement. It may be a little more complicated if you're using an ORM library. I don't have enough experience with those.
In my application, I'm writing it in Ruby on Rails, so I'm constantly doing things like employee.user.name, where if I kept them together, it would be just employee.name or user.name.
From a performance standpoint, you are hitting two tables instead of one, but given proper indexes, it should be negligible. If you had an index that contained the primary key and the person name, for instance, the database would hit the user table, then the index for the person table (with a nearly direct hit), so the performance would be nearly the same as having one table.
You could also create a view in the database to keep both tables joined together to give you additional performance enhancements. I know in the later versions of Oracle you can even put an index on a view if needed to increase performance.
I routinely do that because for me the concept of "user" (username, password, create date, last login date) is different from "person" (name, address, phone, email). One of the drawbacks that you may find is that your queries will often require more joins to get the info you're looking for. If all you have is a login name, you'll need to join the "people" table to get the first and last name for example. If you base everything around the user id primary key, this is mitigated a bit, but still pops up.
If user_tb has auth info, I would very much keep it separate from people_tb. I would however keep a relationship between the two, and most of users' info would be stored in people_tb except all of the info needed for auth (which i guess will not be used for much else) Its a nice tradeoff between design and efficiency i think.
That is definitely what we do as we have millions of people records and only thousands of users. We also separate address, phones and emails into relational tables as many people have more than one of each of these things. Critial is to not rely on name as the identifier as name is not unique. Make sure the tables are joined through some type of surrogate key (an integer or a GUID is preferable) not name.
I always try to avoid as much data repetition as possible. If not all people need to login, you can have a generic people table with the information that applies to both people and users (eg. firstname, lastname, etc).
Then for people that login, you can have a users table that has a 1~1 relationship with people. This table can store the username and password.
I'd say go for the normalized design (two tables) and only denormalize (go down to one user/person table) if it will really make your life easier down the line. If however practically all people are also users it may be simpler to denormalize up front. Its up to you; I have used the normalized approach without problems.
Very reasonable.
As an example, take a look at the aspnet_* services tables here.
Their built in schema has a aspnet_Users and aspnet_Membership with the later table having more extended information about a given user (hashed passwords, etc) but the aspnet_User.UserID is used in the other portions of the schema for referential integrity etc.
Bottom line, it's very common, and good design, to have attributes in a separate table if they are different entities, as in your case.