【问题标题】:Views performance in MySQL for denormalization查看 MySQL 中的非规范化性能
【发布时间】:2011-01-27 17:56:18
【问题描述】:

我目前正在编写我真正的第一个 PHP 应用程序,我想知道如何正确地项目/设计/实施 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

【问题讨论】:

    标签: mysql performance database-design denormalization


    【解决方案1】:

    一般情况下,数据库引擎会为您执行优化。这意味着引擎将确定 users 表在连接到其他表之前需要进行过滤。

    所以,继续使用你的视图,让数据库为它担心。

    如果您稍后检测到性能不佳,请使用 MySQL EXPLAIN 让 MySQL 告诉您它在做什么。

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

    【讨论】:

    • 是的,用户角色在设计上是脱节的;事实是角色列只存在于这个视图中(我需要这个列进行过滤),我怎样才能索引它?我不确定,但是mysql中的视图可以有索引吗?
    • MySQL 将使用 TABLE 上的索引来进行选择。一般来说,试图超越你的 DBMS 是错误的。这些事情在幕后非常复杂,所有简单的案例都已经过优化。只需为可能的列编制索引,然后除非您发现性能不佳,否则不必担心性能。
    • MySQL 不优化视图,简单明了。您应该像担心常规查询一样担心您的视图 - 不多也不少。
    • @Larry Lusting 我快到了,即使我并没有真正想到优化,只有当我看到性能不佳时,你能详细说明一下这个主题吗?
    • 构建您的表格。索引您要搜索的列。不用担心视图,DBMS 将根据您的表结构和索引优化这些查询。除非您注意到它们在测试中的性能问题,否则不要担心视图的速度。除了最大的数据库和最复杂的查询之外,所有的性能都很好。
    【解决方案2】:

    如果您有

    【讨论】:

    • 感谢您的回答,但我正在寻找更通用的方法。
    • 对于更通用的方法,使用对象关系映射器并获得好处:声明式性能调整、各种保护(sql 注入是明显的例子)、读写支持(而不是只读模式在这里讨论),数据库独立性(非常好的事情!)等。
    • 确实很有趣!我会尝试搜索有关该主题的内容!
    【解决方案3】:

    如果将管理员、用户、经理和其他人规范化到一个统一的表中,其中包含一个鉴别器列“角色”,这可能会好得多,这将节省大量重复,这本质上是进行规范化的原因首先。然后,您可以将特定于角色的详细信息添加到与连接中的用户表一起使用的不同表中。

    您的查询可能看起来很简单:

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

    这也比一组unions 更容易让数据库处理

    如果您更进一步,您可以添加一个 UserRoleCoupling 表(而不是 User 中的 Role 列),其中包含用户每个用户拥有的所有角色:

    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 名称的逗号分隔列表。

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

    我会看看我是否能找到我最喜欢的关于数据库规范化的书,并在以后有时间的时候发布 ISBN。

    【讨论】:

    • 规范化确实删除了重复项,但也倾向于创建额外的表,正如你所说,无论如何我的目的是为了安全目的将不同类型的用户保留在不同的表中(SQL 注入)。
    • SQL 注入的风险是在基于用户输入访问数据时使用诸如存储过程、准备好的语句和常识之类的一个很好的理由。不过,我看不出它与将相同数据的表拆分为多个表有何关系。如果您在所有这些表中拥有数百万用户,它可能会更快,但也更难维护。
    • 我忘了告诉你,这些表只共享一部分值(姓名、姓氏、电子邮件、电话),其他列完全不同(不是相同数据的分区) .关于安全性,例如,如果恶意攻击者从数据库中的特定表中获取数据,至少他没有得到全部内容,即使我确信有更好的方法来完成这项任务。
    • @Gianluca:这在数据分区方面会有所改变,您对数据漏洞的看法或多或少是正确的,尽管您正在减轻症状而不是处理潜在的麻烦原因.我希望您的数据访问是通过 PDO 之类的方式完成的,并且您正在使用准备好的语句等。
    • 我同意你的观点,系统中的所有组件必须同样坚固!目前我正在使用 mysqli,但我肯定会传递给 PDO(我听说准备好的语句更容易处理)。即使这不能回答我最初的问题,也感谢您以正确的思维方式引导我!
    猜你喜欢
    • 2013-08-21
    • 2018-06-06
    • 1970-01-01
    • 2012-10-08
    • 2011-03-03
    • 2021-09-22
    • 1970-01-01
    • 2013-01-08
    • 1970-01-01
    相关资源
    最近更新 更多