Question

I am currently writing my truly first PHP Application and i would like to know how to project/design/implement MySQL Views properly;

In my particular case User data is spread across several tables (as a consequence of Database Normalization) and i was thinking to use a View to group data into one large table:

CREATE VIEW `Users_Merged` (
name,
surname,
email,
phone,
role
) AS (
SELECT name, surname, email, phone, 'Customer'
FROM `Customer`
)
UNION (

SELECT name, surname, email, tel, 'Admin'
FROM `Administrator`
)
UNION (

SELECT name, surname, email, tel, 'Manager'
FROM `manager`
);

This way i can use the View's data from the PHP app easily but i don't really know how much this can affect performance.

For example:

SELECT * from `Users_Merged` WHERE role = 'Admin';

Is the right way to filter view's data or should i filter BEFORE creating the view itself? (I need this to have a list of users and the functionality to filter them by role).

EDIT

Specifically what i'm trying to obtain is Denormalization of three tables into one. Is my solution correct? See Denormalization on wikipedia

Was it helpful?

Solution

In general, the database engine will perform the optimization for you. That means that the engine is going to figure out that the users table needs to be filtered before being joined to the other tables.

So, go ahead and use your view and let the database worry about it.

If you detect poor performance later, use MySQL EXPLAIN to get MySQL to tell you what it's doing.

PS: Your data design allows for only one role per user, is that what you wanted? If so, and if the example query you gave is one you intend to run frequently, make sure to index the role column in users.

OTHER TIPS

If you have <1000 users (which seems likely), it doesn't really matter how you do it. If the user list is unlikely to change for long periods of time, the best you can probably do in terms of performance is to load the user list into memory and not go to the database at all. Even if user data were to change in the meantime, you could update the in-memory structure as well as the database and, again, not have to read user information from the DB.

You would probably be much better off normalizing the Administrators, Users, Managers and what-have-you into one uniform table with a discriminator column "Role" that would save a lot of duplication, which is essentially the reason to do normalization in the first place. You can then add the role specific details to distinct tables that you use with the User table in a join.

Your query could then look as simple as:

SELECT
   `Name`, `Surname`, `Email`, `Phone`, `Role`
FROM `User`
WHERE 
    `User`.`Role` IN('Administrator','Manager','Customer', ...)

Which is also easier for the database to process than a set of unions

If you go a step further you could add a UserRoleCoupling table (instead of the Role column in User) that holds all the roles a User has per user:

CREATE TABLE `UserRoleCoupling` (
    UserID INT NOT NULL,  -- assuming your User table has and ID column of INT
    RoleID INT NOT NULL,
    PRIMARY KEY(UserID, RoleID)
);

And put the actual role information into a separate table as well:

CREATE TABLE `Role` (
    ID INT NOT NULL UNIQUE AUTO_INCREMENT,
    Name VARCHAR(64) NOT NULL
    PRIMARY KEY (Name)
)

Now you can have multiple roles per User and use queries like

SELECT
    `U`.`Name`
   ,`U`.`Surname`
   ,`U`.`Email`
   ,`U`.`Phone`
   ,GROUP_CONCAT(`R`.`Name`) `Roles`
FROM `User`
INNER JOIN `UserGroupCoupling` `UGC` ON `UGC`.`UserID` = `User`.`ID`
INNER JOIN `Role` `R` ON `R`.`ID` = `UGC`.`RoleID`
GROUP BY
    `U`.`Name`, `U`.`Surname`, `U`.`Email`, `U`.`Phone`

Which would give you the basic User details and a comma seperated list of all assigned Role names.

In general, the best way to normalize a database structure is to make the tables as generic as possible without being redundant, so don't add administrator or customer specific details to the user table, but use a relationship between User and Administrator to find the specific administrator details. The way you're doing it now isn't really normalized.

I'll see if i can find my favorite book on database normalization and post the ISBN when I have time later.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top