2010-03-15 39 views
4

我目前正在编写我真正的第一个PHP应用程序,我想知道如何正确地项目/设计/实现MySQL视图;在MySQL中反观性能非规范化

在我的特殊情况下的用户数据分布在多台分散(如数据库规范化的结果),我想使用视图对数据进行分组到一个大表:

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` 
); 

这样我可以使用PHP应用程序中的视图数据很容易,但我不知道这会影响性能。

例如:

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

是过滤视图的数据以正确的方式或者我应该过滤器之前创建视图本身? (我需要这个用户列表以及按角色过滤它们的功能)。

编辑

具体是什么我想要考取的是三个表的非规范化为一体。我的解决方案正确吗? See Denormalization on wikipedia

回答

3

通常,数据库引擎会为您执行优化。这意味着引擎会发现用户表在加入其他表之前需要进行过滤。

因此,请继续使用您的视图并让数据库担心它。

如果您稍后发现性能差,请使用MySQL EXPLAIN来让MySQL告诉您它在做什么。

PS:您的数据设计只允许每个用户使用一个角色,那是您想要的吗?如果是这样,并且您提供的示例查询是您打算频繁运行的示例查询,请确保在用户中索引角色列。

+0

是的,用户角色是由设计脱节;事实是角色列只存在于这个视图中(我需要这个列进行过滤),我该如何索引它?我不确定这一点,但可以在MySQL中的视图有索引? – 2010-03-15 16:16:43

+0

MySQL将使用TABLE上的索引来进行选择。一般来说,尝试去思考你的DBMS是一个错误。这些东西在引擎盖下非常复杂,所有简单的情况都已经过优化。只需索引可能的列,然后不必担心性能,除非你看到糟糕的表现。 – 2010-03-15 16:49:41

+0

MySQL不优化视图,简单明了。您应该担心自己的观点,就像担心常规查询一样 - 不多也不少。 – 2010-03-15 17:45:53

1

如果你有< 1000个用户(这看起来很可能),那你怎么做并不重要。如果用户列表不可能长时间改变,那么就性能而言,最好的做法是将用户列表加载到内存中,而不是进入数据库。即使用户数据在此期间发生变化,您也可以更新内存中的结构以及数据库,而且不必从数据库中读取用户信息。

+0

感谢您的回答,但我正在寻找一个更具有普遍性的方法。 – 2010-03-15 18:04:24

+1

对于更通用的方法,使用对象关系映射器并获得好处:声明性性能调优,各种保护(sql注入是一个明显的例子),读写支持(与只读模式相反,正在讨论这里),数据库独立性(一件很好的事情!)等等。 – 2010-03-15 19:01:42

+0

确实很有意思!我会尝试搜索关于这个主题的东西! – 2010-03-15 20:02:09

0

你可能会更好地将管理员,用户,管理员和你拥有的东西放到一个统一的表中,并带有一个可以节省大量重复的鉴别器列“角色”,这基本上是做这件事的理由正常化首先。然后,您可以将特定于角色的详细信息添加到您在联接中与用户表一起使用的不同表格中。

然后将查询可能看起来那样简单:

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

这也更容易为数据库比一套union小号

的过程,如果你走一步,你可以添加一个UserRoleCoupling表(而不是在UserRole列)保存所有用户每一个用户具有角色:

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) 
); 

并把实际的角色信息到一个单独的表,以及:

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

现在你可以为每个用户指定多个角色,并使用查询,如

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` 

这将使你的基本User细节和所有已分配Role名称的逗号分隔列表。

一般来说,规范化数据库结构的最佳方法是尽量使表尽可能通用而不是冗余的,因此不要将管理员或客户特定的详细信息添加到用户表中,而是使用UserAdministrator找到具体的管理员详细信息。你现在做的方式并没有真正规范。

我会看看我是否可以找到我最喜欢的数据库标准化书籍,并在稍后有时间发布ISBN。

+0

规范化确实可以删除重复项,但也倾向于按照您的说明创建额外的表,无论如何,我的目的是为了安全目的将不同类型的用户保留在不同的表中(SQL注入)。 – 2010-03-15 19:55:04

+0

在基于用户输入访问数据时,SQL注入的风险是使用诸如存储过程,准备好的语句和常识之类的东西的好理由。我不明白它是如何将分割成多个表格的相同数据表格分开的。如果你在所有这些表中有几百万用户,它可能会更快,但也更难维护。 – Kris 2010-03-15 20:13:25

+0

我忘了告诉你,这些表共享的只是值的一个子集(姓名,电子邮件,电话),其他列是完全不同的(不是相同数据的分区)。关于安全性,例如,如果恶意攻击者从数据库中的特定表中获取数据,至少他没有得到整个事情,即使我确信有更好的方法来完成这项任务。 – 2010-03-15 20:29:48