2010-03-15 41 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